diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6570e50cea8..5594146998d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,6 +45,9 @@ set(LIBRARY_SRCS
   libraries/ArduinoOTA/src/ArduinoOTA.cpp
   libraries/AsyncUDP/src/AsyncUDP.cpp
   libraries/BluetoothSerial/src/BluetoothSerial.cpp
+  libraries/BluetoothSerial/src/BTAddress.cpp
+  libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
+  libraries/BluetoothSerial/src/BTScanResultsSet.cpp
   libraries/DNSServer/src/DNSServer.cpp
   libraries/EEPROM/src/EEPROM.cpp
   libraries/ESPmDNS/src/ESPmDNS.cpp
diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3 b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2 b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino
new file mode 100644
index 00000000000..b3ec78ccf2a
--- /dev/null
+++ b/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino
@@ -0,0 +1,52 @@
+#include <BluetoothSerial.h>
+
+#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
+#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
+#endif
+
+BluetoothSerial SerialBT;
+
+
+#define BT_DISCOVER_TIME	10000
+
+
+static bool btScanAsync = true;
+static bool btScanSync = true;
+
+
+void btAdvertisedDeviceFound(BTAdvertisedDevice* pDevice) {
+	Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str());
+}
+
+void setup() {
+  Serial.begin(115200);
+  SerialBT.begin("ESP32test"); //Bluetooth device name
+  Serial.println("The device started, now you can pair it with bluetooth!");
+
+
+  if (btScanAsync) {
+    Serial.print("Starting discoverAsync...");
+    if (SerialBT.discoverAsync(btAdvertisedDeviceFound)) {
+      Serial.println("Findings will be reported in \"btAdvertisedDeviceFound\"");
+      delay(10000);
+      Serial.print("Stopping discoverAsync... ");
+      SerialBT.discoverAsyncStop();
+      Serial.println("stopped");
+    } else {
+      Serial.println("Error on discoverAsync f.e. not workin after a \"connect\"");
+    }
+  }
+  
+  if (btScanSync) {
+    Serial.println("Starting discover...");
+    BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME);
+    if (pResults)
+      pResults->dump(&Serial);
+    else
+      Serial.println("Error on BT Scan, no result!");
+  }
+}
+
+void loop() {
+  delay(100);
+}
diff --git a/libraries/BluetoothSerial/src/BTAddress.cpp b/libraries/BluetoothSerial/src/BTAddress.cpp
new file mode 100644
index 00000000000..1ed416f2b24
--- /dev/null
+++ b/libraries/BluetoothSerial/src/BTAddress.cpp
@@ -0,0 +1,96 @@
+/*
+ * BTAddress.cpp
+ *
+ *  Created on: Jul 2, 2017
+ *      Author: kolban
+ *  Ported  on: Feb 5, 2021
+ *      Author: Thomas M. (ArcticSnowSky)
+ */
+#include "sdkconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+#include "BTAddress.h"
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#ifdef ARDUINO_ARCH_ESP32
+#include "esp32-hal-log.h"
+#endif
+
+
+/**
+ * @brief Create an address from the native ESP32 representation.
+ * @param [in] address The native representation.
+ */
+BTAddress::BTAddress(esp_bd_addr_t address) {
+	memcpy(m_address, address, ESP_BD_ADDR_LEN);
+} // BTAddress
+
+
+/**
+ * @brief Create an address from a hex string
+ *
+ * A hex string is of the format:
+ * ```
+ * 00:00:00:00:00:00
+ * ```
+ * which is 17 characters in length.
+ *
+ * @param [in] stringAddress The hex representation of the address.
+ */
+BTAddress::BTAddress(std::string stringAddress) {
+	if (stringAddress.length() != 17) return;
+
+	int data[6];
+	sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]);
+	m_address[0] = (uint8_t) data[0];
+	m_address[1] = (uint8_t) data[1];
+	m_address[2] = (uint8_t) data[2];
+	m_address[3] = (uint8_t) data[3];
+	m_address[4] = (uint8_t) data[4];
+	m_address[5] = (uint8_t) data[5];
+} // BTAddress
+
+
+/**
+ * @brief Determine if this address equals another.
+ * @param [in] otherAddress The other address to compare against.
+ * @return True if the addresses are equal.
+ */
+bool BTAddress::equals(BTAddress otherAddress) {
+	return memcmp(otherAddress.getNative(), m_address, 6) == 0;
+} // equals
+
+
+/**
+ * @brief Return the native representation of the address.
+ * @return The native representation of the address.
+ */
+esp_bd_addr_t *BTAddress::getNative() {
+	return &m_address;
+} // getNative
+
+
+/**
+ * @brief Convert a BT address to a string.
+ *
+ * A string representation of an address is in the format:
+ *
+ * ```
+ * xx:xx:xx:xx:xx:xx
+ * ```
+ *
+ * @return The string representation of the address.
+ */
+std::string BTAddress::toString() {
+	auto size = 18;
+	char *res = (char*)malloc(size);
+	snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]);
+	std::string ret(res);
+	free(res);
+	return ret;
+} // toString
+#endif
diff --git a/libraries/BluetoothSerial/src/BTAddress.h b/libraries/BluetoothSerial/src/BTAddress.h
new file mode 100644
index 00000000000..e23d34593f1
--- /dev/null
+++ b/libraries/BluetoothSerial/src/BTAddress.h
@@ -0,0 +1,36 @@
+/*
+ * BTAddress.h
+ *
+ *  Created on: Jul 2, 2017
+ *      Author: kolban
+ *  Ported  on: Feb 5, 2021
+ *      Author: Thomas M. (ArcticSnowSky)
+ */
+
+#ifndef COMPONENTS_CPP_UTILS_BTADDRESS_H_
+#define COMPONENTS_CPP_UTILS_BTADDRESS_H_
+#include "sdkconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+#include <esp_gap_bt_api.h> // ESP32 BT
+#include <string>
+
+
+/**
+ * @brief A %BT device address.
+ *
+ * Every %BT device has a unique address which can be used to identify it and form connections.
+ */
+class BTAddress {
+public:
+	BTAddress(esp_bd_addr_t address);
+	BTAddress(std::string stringAddress);
+	bool           equals(BTAddress otherAddress);
+	esp_bd_addr_t* getNative();
+	std::string    toString();
+
+private:
+	esp_bd_addr_t m_address;
+};
+
+#endif /* CONFIG_BT_ENABLED */
+#endif /* COMPONENTS_CPP_UTILS_BTADDRESS_H_ */
diff --git a/libraries/BluetoothSerial/src/BTAdvertisedDevice.h b/libraries/BluetoothSerial/src/BTAdvertisedDevice.h
new file mode 100644
index 00000000000..07e93622e92
--- /dev/null
+++ b/libraries/BluetoothSerial/src/BTAdvertisedDevice.h
@@ -0,0 +1,65 @@
+/*
+ * BTAdvertisedDevice.h
+ *
+ *  Created on: Feb 5, 2021
+ *      Author: Thomas M. (ArcticSnowSky)
+ */
+
+#ifndef __BTADVERTISEDDEVICE_H__
+#define __BTADVERTISEDDEVICE_H__
+
+#include "BTAddress.h"
+
+
+class BTAdvertisedDevice {
+public:
+    virtual ~BTAdvertisedDevice() = default;
+
+    virtual BTAddress   getAddress();
+    virtual uint32_t    getCOD();
+    virtual std::string getName();
+    virtual int8_t      getRSSI();
+
+
+    virtual bool        haveCOD();
+    virtual bool        haveName();
+    virtual bool        haveRSSI();
+
+    virtual std::string toString();
+};
+
+class BTAdvertisedDeviceSet : public virtual BTAdvertisedDevice {
+public:
+    BTAdvertisedDeviceSet();
+    //~BTAdvertisedDeviceSet() = default;
+    
+
+    BTAddress   getAddress();
+    uint32_t    getCOD();
+    std::string getName();
+    int8_t      getRSSI();
+
+
+    bool        haveCOD();
+    bool        haveName();
+    bool        haveRSSI();
+
+    std::string toString();
+
+    void setAddress(BTAddress address);
+    void setCOD(uint32_t cod);
+    void setName(std::string name);
+    void setRSSI(int8_t rssi);
+
+    bool m_haveCOD;
+    bool m_haveName;
+    bool m_haveRSSI;
+
+
+    BTAddress   m_address = BTAddress((uint8_t*)"\0\0\0\0\0\0");
+    uint32_t    m_cod;
+    std::string m_name;
+    int8_t      m_rssi;
+};
+
+#endif
\ No newline at end of file
diff --git a/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp b/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
new file mode 100644
index 00000000000..ec8a23e80b6
--- /dev/null
+++ b/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
@@ -0,0 +1,78 @@
+/*
+ * BTAdvertisedDeviceSet.cpp
+ *
+ *  Created on: Feb 5, 2021
+ *      Author: Thomas M. (ArcticSnowSky)
+ */
+
+#include "sdkconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+//#include <map>
+
+#include "BTAdvertisedDevice.h"
+//#include "BTScan.h"
+
+
+BTAdvertisedDeviceSet::BTAdvertisedDeviceSet() {
+	m_cod		       = 0;
+	m_name             = "";
+	m_rssi             = 0;
+
+	m_haveCOD	       = false;
+	m_haveName         = false;
+	m_haveRSSI         = false;
+} // BTAdvertisedDeviceSet
+
+BTAddress   BTAdvertisedDeviceSet::getAddress()    { return m_address; }
+uint32_t    BTAdvertisedDeviceSet::getCOD()        { return m_cod; }
+std::string BTAdvertisedDeviceSet::getName()       { return m_name; }
+int8_t      BTAdvertisedDeviceSet::getRSSI()	    { return m_rssi; }
+
+
+bool        BTAdvertisedDeviceSet::haveCOD()   { return m_haveCOD; }
+bool        BTAdvertisedDeviceSet::haveName()  { return m_haveName; }
+bool        BTAdvertisedDeviceSet::haveRSSI()  { return m_haveRSSI; }
+
+/**
+ * @brief Create a string representation of this device.
+ * @return A string representation of this device.
+ */
+std::string BTAdvertisedDeviceSet::toString() {
+	std::string res = "Name: " + getName() + ", Address: " + getAddress().toString();
+	if (haveCOD()) {
+		char val[6];
+		snprintf(val, sizeof(val), "%d", getCOD());
+		res += ", cod: ";
+		res += val;
+	}
+	if (haveRSSI()) {
+		char val[4];
+		snprintf(val, sizeof(val), "%d", getRSSI());
+		res += ", rssi: ";
+		res += val;
+	}
+	return res;
+} // toString
+
+
+void BTAdvertisedDeviceSet::setAddress(BTAddress address) {
+    m_address = address;
+}
+
+void BTAdvertisedDeviceSet::setCOD(uint32_t cod) {
+    m_cod     = cod;
+	m_haveCOD = true;
+}
+
+void BTAdvertisedDeviceSet::setName(std::string name) {
+    m_name     = name;
+	m_haveName = true;
+}
+
+void BTAdvertisedDeviceSet::setRSSI(int8_t rssi) {
+    m_rssi     = rssi;
+	m_haveRSSI = true;
+}
+
+#endif /* CONFIG_BT_ENABLED */
diff --git a/libraries/BluetoothSerial/src/BTScan.h b/libraries/BluetoothSerial/src/BTScan.h
new file mode 100644
index 00000000000..3650d41625b
--- /dev/null
+++ b/libraries/BluetoothSerial/src/BTScan.h
@@ -0,0 +1,42 @@
+/*
+ * BTScan.h
+ *
+ *  Created on: Feb 5, 2021
+ *      Author: Thomas M. (ArcticSnowSky)
+ */
+
+#ifndef __BTSCAN_H__
+#define __BTSCAN_H__
+
+#include <map>
+#include <string>
+#include <Print.h>
+#include "BTAddress.h"
+#include "BTAdvertisedDevice.h"
+
+class BTAdvertisedDevice;
+class BTAdvertisedDeviceSet;
+
+
+class BTScanResults {
+public:
+	virtual ~BTScanResults() = default;
+
+    virtual void        		dump(Print *print = nullptr);
+    virtual int         		getCount();
+    virtual BTAdvertisedDevice* getDevice(uint32_t i);
+};
+
+class BTScanResultsSet : public BTScanResults {
+public:
+    void                	dump(Print *print = nullptr);
+    int                 	getCount();
+    BTAdvertisedDevice*		getDevice(uint32_t i);
+
+	bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
+	void clear();
+
+    std::map<std::string, BTAdvertisedDeviceSet> m_vectorAdvertisedDevices;
+};
+
+#endif
\ No newline at end of file
diff --git a/libraries/BluetoothSerial/src/BTScanResultsSet.cpp b/libraries/BluetoothSerial/src/BTScanResultsSet.cpp
new file mode 100644
index 00000000000..c4d00fa4204
--- /dev/null
+++ b/libraries/BluetoothSerial/src/BTScanResultsSet.cpp
@@ -0,0 +1,95 @@
+/*
+ * BTScanResultsSet.cpp
+ *
+ *  Created on: Feb 5, 2021
+ *      Author: Thomas M. (ArcticSnowSky)
+ */
+
+#include "sdkconfig.h"
+#if defined(CONFIG_BT_ENABLED)
+
+
+#include <esp_err.h>
+
+#include "BTAdvertisedDevice.h"
+#include "BTScan.h"
+//#include "GeneralUtils.h"
+#include "esp32-hal-log.h"
+
+
+class BTAdvertisedDevice;
+
+/**
+ * @brief Dump the scan results to the log.
+ */
+void BTScanResultsSet::dump(Print *print) {
+	int cnt = getCount();
+	if (print == nullptr) {
+		log_v(">> Dump scan results : %d", cnt);
+		for (int i=0; i < cnt; i++) {
+			BTAdvertisedDevice* dev = getDevice(i);
+			if (dev)
+				log_d("- %d: %s\n", i+1, dev->toString().c_str());
+			else
+				log_d("- %d is null\n", i+1);
+		}
+		log_v("-- dump finished --");
+	} else {
+		print->printf(">> Dump scan results: %d\n", cnt);
+		for (int i=0; i < cnt; i++) {
+			BTAdvertisedDevice* dev = getDevice(i);
+			if (dev)
+				print->printf("- %d: %s\n", i+1, dev->toString().c_str());
+			else
+				print->printf("- %d is null\n", i+1);
+		}
+		print->println("-- Dump finished --");
+	}
+} // dump
+
+
+/**
+ * @brief Return the count of devices found in the last scan.
+ * @return The number of devices found in the last scan.
+ */
+int BTScanResultsSet::getCount() {
+	return m_vectorAdvertisedDevices.size();
+} // getCount
+
+
+/**
+ * @brief Return the specified device at the given index.
+ * The index should be between 0 and getCount()-1.
+ * @param [in] i The index of the device.
+ * @return The device at the specified index.
+ */
+BTAdvertisedDevice* BTScanResultsSet::getDevice(uint32_t i) {
+	if (i < 0)
+		return nullptr;
+
+	uint32_t x = 0;
+	BTAdvertisedDeviceSet* pDev = &m_vectorAdvertisedDevices.begin()->second;
+	for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) {
+		pDev = &it->second;
+		if (x==i)	break;
+		x++;
+	}
+	return x==i ? pDev : nullptr;
+}
+
+void BTScanResultsSet::clear() {
+    //for(auto _dev : m_vectorAdvertisedDevices)
+	//	delete _dev.second;
+	m_vectorAdvertisedDevices.clear();
+}
+
+bool BTScanResultsSet::add(BTAdvertisedDeviceSet advertisedDevice, bool unique) {
+	std::string key = advertisedDevice.getAddress().toString();
+	if (!unique || m_vectorAdvertisedDevices.count(key) == 0) {
+		m_vectorAdvertisedDevices.insert(std::pair<std::string, BTAdvertisedDeviceSet>(key, advertisedDevice));
+		return true;
+	} else
+		return false;
+}
+
+#endif
\ No newline at end of file
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
old mode 100755
new mode 100644
index ab8ab1fbfcd..b20452c186a
--- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
@@ -52,6 +52,7 @@ static xQueueHandle _spp_tx_queue = NULL;
 static SemaphoreHandle_t _spp_tx_done = NULL;
 static TaskHandle_t _spp_task_handle = NULL;
 static EventGroupHandle_t _spp_event_group = NULL;
+static EventGroupHandle_t _bt_event_group = NULL;
 static boolean secondConnectionAttempt;
 static esp_spp_cb_t * custom_spp_callback = NULL;
 static BluetoothSerialDataCb custom_data_callback = NULL;
@@ -72,11 +73,18 @@ static int _pin_len;
 static bool _isPinSet;
 static bool _enableSSP;
 
+static BTScanResultsSet scanResults;
+static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr;
+
 #define SPP_RUNNING     0x01
 #define SPP_CONNECTED   0x02
 #define SPP_CONGESTED   0x04
 #define SPP_DISCONNECTED 0x08
 
+#define BT_DISCOVERY_RUNNING    0x01
+#define BT_DISCOVERY_COMPLETED  0x02
+
+
 typedef struct {
         size_t len;
         uint8_t data[];
@@ -368,15 +376,16 @@ void BluetoothSerial::onData(BluetoothSerialDataCb cb){
 static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
 {
     switch(event){
-        case ESP_BT_GAP_DISC_RES_EVT:
+        case ESP_BT_GAP_DISC_RES_EVT: {
             log_i("ESP_BT_GAP_DISC_RES_EVT");
 #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
             char bda_str[18];
             log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
 #endif
+            BTAdvertisedDeviceSet advertisedDevice;
+            uint8_t peer_bdname_len = 0;
+            char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
             for (int i = 0; i < param->disc_res.num_prop; i++) {
-                uint8_t peer_bdname_len;
-                char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
                 switch(param->disc_res.prop[i].type) {
                     case ESP_BT_GAP_DEV_PROP_EIR:  
                         if (get_name_from_eir((uint8_t*)param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)) {
@@ -409,10 +418,24 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
 
                     case ESP_BT_GAP_DEV_PROP_COD:
                         log_d("ESP_BT_GAP_DEV_PROP_COD");
+                        if (param->disc_res.prop[i].len <= sizeof(int)) {
+                            uint32_t cod = 0;
+                            memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
+                            advertisedDevice.setCOD(cod);
+                        } else {
+                            log_d("Value size larger than integer");
+                        }
                         break;
 
                     case ESP_BT_GAP_DEV_PROP_RSSI:
                         log_d("ESP_BT_GAP_DEV_PROP_RSSI");
+                        if (param->disc_res.prop[i].len <= sizeof(int)) {
+                            uint8_t rssi = 0;
+                            memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
+                            advertisedDevice.setRSSI(rssi);
+                        } else {
+                            log_d("Value size larger than integer");
+                        }
                         break;
                         
                     default:
@@ -421,17 +444,33 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
                 if (_isRemoteAddressSet)
                     break;
             }
-            break;
+            if (peer_bdname_len)
+                advertisedDevice.setName(peer_bdname);
+            esp_bd_addr_t addr;
+            memcpy(addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
+            advertisedDevice.setAddress(BTAddress(addr));
+            if (scanResults.add(advertisedDevice) && advertisedDeviceCb)
+                advertisedDeviceCb(&advertisedDevice);
+        }
+        break;
+
         case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
             log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
+            if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
+                xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING);
+                xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
+            } else { // ESP_BT_GAP_DISCOVERY_STARTED
+                xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
+                xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_RUNNING);
+            }
             break;
 
         case ESP_BT_GAP_RMT_SRVCS_EVT:
-            log_i( "ESP_BT_GAP_RMT_SRVCS_EVT");
+            log_i( "ESP_BT_GAP_RMT_SRVCS_EVT: status = %d, num_uuids = %d", param->rmt_srvcs.stat, param->rmt_srvcs.num_uuids);
             break;
 
         case ESP_BT_GAP_RMT_SRVC_REC_EVT:
-            log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT");
+            log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT: status = %d", param->rmt_srvc_rec.stat);
             break;
 
         case ESP_BT_GAP_AUTH_CMPL_EVT:
@@ -490,6 +529,14 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
 
 static bool _init_bt(const char *deviceName)
 {
+    if(!_bt_event_group){
+        _bt_event_group = xEventGroupCreate();
+        if(!_bt_event_group){
+            log_e("BT Event Group Create Failed!");
+            return false;
+        }
+        xEventGroupClearBits(_bt_event_group, 0xFFFFFF);
+    }
     if(!_spp_event_group){
         _spp_event_group = xEventGroupCreate();
         if(!_spp_event_group){
@@ -634,6 +681,10 @@ static bool _stop_bt()
         vSemaphoreDelete(_spp_tx_done);
         _spp_tx_done = NULL;
     }
+    if (_bt_event_group) {
+        vEventGroupDelete(_bt_event_group);
+        _bt_event_group = NULL;
+    }
     return true;
 }
 
@@ -642,6 +693,11 @@ static bool waitForConnect(int timeout) {
     return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_CONNECTED) != 0;
 }
 
+static bool waitForDiscovered(int timeout) {
+    TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
+    return (xEventGroupWaitBits(_spp_event_group, BT_DISCOVERY_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_DISCOVERY_COMPLETED) != 0;
+}
+
 /*
  * Serial Bluetooth Arduino
  *
@@ -881,6 +937,73 @@ bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
     return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) & SPP_RUNNING) != 0;
 }
 
+
+/**
+ * @brief           RemoteName or address are not allowed to be set during discovery
+ *                  (otherwhise it might connect automatically and stop discovery)
+ * @param[in]       timeoutMs can range from MIN_INQ_TIME to MAX_INQ_TIME
+ * @return          in case of Error immediately Empty ScanResults.
+ */
+BTScanResults* BluetoothSerial::discover(int timeoutMs) {
+    scanResults.clear();
+    if (timeoutMs < MIN_INQ_TIME || timeoutMs > MAX_INQ_TIME || strlen(_remote_name) || _isRemoteAddressSet)
+        return nullptr;
+    int timeout = timeoutMs / INQ_TIME;
+    log_i("discover::disconnect");
+    disconnect();
+    log_i("discovering");
+    // will resolve name to address first - it may take a while
+    esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+    if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK) {
+        waitForDiscovered(timeoutMs);
+        esp_bt_gap_cancel_discovery();
+    }
+    return &scanResults;
+}
+
+/**
+ * @brief           RemoteName or address are not allowed to be set during discovery
+ *                  (otherwhise it might connect automatically and stop discovery)
+ * @param[in]       cb called when a [b]new[/b] device has been discovered
+ * @param[in]       timeoutMs can be 0 or range from MIN_INQ_TIME to MAX_INQ_TIME
+ *
+ * @return          Wheter start was successfull or problems with params
+ */
+bool BluetoothSerial::discoverAsync(BTAdvertisedDeviceCb cb, int timeoutMs) {
+    scanResults.clear();
+    if (strlen(_remote_name) || _isRemoteAddressSet)
+        return false;
+    int timeout = timeoutMs / INQ_TIME;
+    disconnect();
+    advertisedDeviceCb = cb;
+    log_i("discovering");
+    // will resolve name to address first - it may take a while
+    esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+    if (timeout > 0)
+        return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK;
+    else return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, ESP_BT_GAP_MAX_INQ_LEN, 0) == ESP_OK;
+}
+
+/** @brief      Stops the asynchronous discovery and clears the callback */
+void BluetoothSerial::discoverAsyncStop() {
+    esp_bt_gap_cancel_discovery();
+    advertisedDeviceCb = nullptr;
+}
+
+/** @brief      Clears scanresult entries */
+void BluetoothSerial::discoverClear() {
+    scanResults.clear();
+}
+
+/** @brief      Can be used while discovering asynchronously
+ *              Will be returned also on synchronous discovery.
+ *
+ * @return      BTScanResults contains several information of found devices
+ */
+BTScanResults* BluetoothSerial::getScanResults() {
+    return &scanResults;
+}
+
 BluetoothSerial::operator bool() const
 {
     return true;
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.h b/libraries/BluetoothSerial/src/BluetoothSerial.h
old mode 100755
new mode 100644
index c6b24fa9d22..cfb8b823045
--- a/libraries/BluetoothSerial/src/BluetoothSerial.h
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.h
@@ -21,12 +21,15 @@
 
 #include "Arduino.h"
 #include "Stream.h"
+#include <esp_gap_bt_api.h>
 #include <esp_spp_api.h>
 #include <functional>
+#include "BTScan.h"
 
 typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
 typedef std::function<void(uint32_t num_val)> ConfirmRequestCb;
 typedef std::function<void(boolean success)> AuthCompleteCb;
+typedef std::function<void(BTAdvertisedDevice* pAdvertisedDevice)> BTAdvertisedDeviceCb;
 
 class BluetoothSerial: public Stream
 {
@@ -63,6 +66,16 @@ class BluetoothSerial: public Stream
         bool isReady(bool checkMaster=false, int timeout=0);
         bool disconnect();
         bool unpairDevice(uint8_t remoteAddress[]);
+
+        BTScanResults* discover(int timeout=0x30*1280);
+        bool discoverAsync(BTAdvertisedDeviceCb cb, int timeout=0x30*1280);
+        void discoverAsyncStop();
+        void discoverClear();
+        BTScanResults* getScanResults();
+        
+        const int INQ_TIME = 1280;   // Inquire Time unit 1280 ms
+        const int MIN_INQ_TIME = (ESP_BT_GAP_MIN_INQ_LEN * INQ_TIME);
+        const int MAX_INQ_TIME = (ESP_BT_GAP_MAX_INQ_LEN * INQ_TIME);
         
         operator bool() const;
     private: