diff --git a/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino b/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino
new file mode 100644
index 00000000000..73f3dc058b4
--- /dev/null
+++ b/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino
@@ -0,0 +1,56 @@
+//This example code is in the Public Domain (or CC0 licensed, at your option.)
+//By Victor Tchistiak - 2019
+//
+//This example demostrates master mode bluetooth connection and pin 
+//it creates a bridge between Serial and Classical Bluetooth (SPP)
+//this is an extention of the SerialToSerialBT example by Evandro Copercini - 2018
+//
+
+#include "BluetoothSerial.h"
+
+BluetoothSerial SerialBT;
+
+String MACadd = "AA:BB:CC:11:22:33";
+uint8_t address[6]  = {0xAA, 0xBB, 0xCC, 0x11, 0x22, 0x33};
+//uint8_t address[6]  = {0x00, 0x1D, 0xA5, 0x02, 0xC3, 0x22};
+String name = "OBDII";
+char *pin = "1234"; //<- standard pin would be provided by default
+bool connected;
+
+void setup() {
+  Serial.begin(115200);
+  //SerialBT.setPin(pin);
+  SerialBT.begin("ESP32test", true); 
+  //SerialBT.setPin(pin);
+  Serial.println("The device started in master mode, make sure remote BT device is on!");
+  
+  // connect(address) is fast (upto 10 secs max), connect(name) is slow (upto 30 secs max) as it needs
+  // to resolve name to address first, but it allows to connect to different devices with the same name.
+  // Set CoreDebugLevel to Info to view devices bluetooth address and device names
+  connected = SerialBT.connect(name);
+  //connected = SerialBT.connect(address);
+  
+  if(connected) {
+    Serial.println("Connected Succesfully!");
+  } else {
+    while(!SerialBT.connected(10000)) {
+      Serial.println("Failed to connect. Make sure remote device is available and in range, then restart app."); 
+    }
+  }
+  // disconnect() may take upto 10 secs max
+  if (SerialBT.disconnect()) {
+    Serial.println("Disconnected Succesfully!");
+  }
+  // this would reconnect to the name(will use address, if resolved) or address used with connect(name/address).
+  SerialBT.connect();
+}
+
+void loop() {
+  if (Serial.available()) {
+    SerialBT.write(Serial.read());
+  }
+  if (SerialBT.available()) {
+    Serial.write(SerialBT.read());
+  }
+  delay(20);
+}
diff --git a/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino
new file mode 100755
index 00000000000..c316a73b2bc
--- /dev/null
+++ b/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino
@@ -0,0 +1,87 @@
+//This example code is in the Public Domain (or CC0 licensed, at your option.)
+//By Victor Tchistiak - 2019
+//
+//This example demonstrates reading and removing paired devices stored on the ESP32 flash memory
+//Sometimes you may find your ESP32 device could not connect to the remote device despite
+//many successful connections earlier. This is most likely a result of client replacing your paired
+//device info with new one from other device. The BT clients store connection info for paired devices,
+//but it is limited to a few devices only. When new device pairs and number of stored devices is exceeded,
+//one of the previously paired devices would be replaced with new one.
+//The only remedy is to delete this saved bound device from your device flash memory
+//and pair with the other device again.
+//
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include"esp_gap_bt_api.h"
+#include "esp_err.h"
+
+#define REMOVE_BONDED_DEVICES 0   // <- Set to 0 to view all bonded devices addresses, set to 1 to remove
+
+#define PAIR_MAX_DEVICES 20
+uint8_t pairedDeviceBtAddr[PAIR_MAX_DEVICES][6];
+char bda_str[18];
+
+bool initBluetooth()
+{
+  if(!btStart()) {
+    Serial.println("Failed to initialize controller");
+    return false;
+  }
+ 
+  if(esp_bluedroid_init() != ESP_OK) {
+    Serial.println("Failed to initialize bluedroid");
+    return false;
+  }
+ 
+  if(esp_bluedroid_enable() != ESP_OK) {
+    Serial.println("Failed to enable bluedroid");
+    return false;
+  }
+  return true;
+}
+
+char *bda2str(const uint8_t* bda, char *str, size_t size)
+{
+  if (bda == NULL || str == NULL || size < 18) {
+    return NULL;
+  }
+  sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+          bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+  return str;
+}
+ 
+void setup() {
+  Serial.begin(115200);
+ 
+  initBluetooth();
+  Serial.print("ESP32 bluetooth address: "); Serial.println(bda2str(esp_bt_dev_get_address(), bda_str, 18));
+  // Get the numbers of bonded/paired devices in the BT module
+  int count = esp_bt_gap_get_bond_device_num();
+  if(!count) {
+    Serial.println("No bonded device found.");
+  } else {
+    Serial.print("Bonded device count: "); Serial.println(count);
+    if(PAIR_MAX_DEVICES < count) {
+      count = PAIR_MAX_DEVICES; 
+      Serial.print("Reset bonded device count: "); Serial.println(count);
+    }
+    esp_err_t tError =  esp_bt_gap_get_bond_device_list(&count, pairedDeviceBtAddr);
+    if(ESP_OK == tError) {
+      for(int i = 0; i < count; i++) {
+        Serial.print("Found bonded device # "); Serial.print(i); Serial.print(" -> ");
+        Serial.println(bda2str(pairedDeviceBtAddr[i], bda_str, 18));     
+        if(REMOVE_BONDED_DEVICES) {
+          esp_err_t tError = esp_bt_gap_remove_bond_device(pairedDeviceBtAddr[i]);
+          if(ESP_OK == tError) {
+            Serial.print("Removed bonded device # "); 
+          } else {
+            Serial.print("Failed to remove bonded device # ");
+          }
+          Serial.println(i);
+        }
+      }        
+    }
+  }
+}
+ 
+void loop() {}
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
old mode 100644
new mode 100755
index d3d09216303..758ee08c296
--- a/libraries/BluetoothSerial/src/BluetoothSerial.cpp
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.cpp
@@ -53,15 +53,80 @@ static EventGroupHandle_t _spp_event_group = NULL;
 static boolean secondConnectionAttempt;
 static esp_spp_cb_t * custom_spp_callback = NULL;
 
+#define INQ_LEN 0x10
+#define INQ_NUM_RSPS 20
+#define READY_TIMEOUT (10 * 1000)
+#define SCAN_TIMEOUT (INQ_LEN * 2 * 1000)
+static esp_bd_addr_t _peer_bd_addr;
+static char _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
+static bool _isRemoteAddressSet;
+static bool _isMaster;
+static esp_bt_pin_code_t _pin_code;
+static int _pin_len;
+static bool _isPinSet;
+static bool _enableSSP;
+
 #define SPP_RUNNING     0x01
 #define SPP_CONNECTED   0x02
 #define SPP_CONGESTED   0x04
+#define SPP_DISCONNECTED 0x08
 
 typedef struct {
         size_t len;
         uint8_t data[];
 } spp_packet_t;
 
+static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
+{
+  if (bda == NULL || str == NULL || size < 18) {
+    return NULL;
+  }
+
+  uint8_t *p = bda;
+  sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+          p[0], p[1], p[2], p[3], p[4], p[5]);
+  return str;
+}
+
+static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
+{
+    if (!eir || !bdname || !bdname_len) {
+        return false;
+    }
+
+    uint8_t *rmt_bdname, rmt_bdname_len;
+    *bdname = *bdname_len = rmt_bdname_len = 0;
+
+    rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
+    if (!rmt_bdname) {
+        rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
+    }
+    if (rmt_bdname) {
+        rmt_bdname_len = rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN ? ESP_BT_GAP_MAX_BDNAME_LEN : rmt_bdname_len;
+        memcpy(bdname, rmt_bdname, rmt_bdname_len);
+        bdname[rmt_bdname_len] = 0;
+        *bdname_len = rmt_bdname_len;
+        return true;
+    }
+    return false;
+}
+
+static bool btSetPin() {
+    esp_bt_pin_type_t pin_type;
+    if (_isPinSet) {
+        if (_pin_len) {
+            log_i("pin set");
+            pin_type = ESP_BT_PIN_TYPE_FIXED;
+        } else {
+            _isPinSet = false;
+            log_i("pin reset");
+            pin_type = ESP_BT_PIN_TYPE_VARIABLE; // pin_code would be ignored (default)
+        }
+        return (esp_bt_gap_set_pin(pin_type, _pin_len, _pin_code) == ESP_OK);        
+    }
+    return false;
+}
+
 static esp_err_t _spp_queue_packet(uint8_t *data, size_t len){
     if(!data || !len){
         log_w("No data provided");
@@ -159,29 +224,34 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
     case ESP_SPP_INIT_EVT:
         log_i("ESP_SPP_INIT_EVT");
         esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
-        esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 0, _spp_server_name);
+        if (!_isMaster) {
+            log_i("ESP_SPP_INIT_EVT: slave: start");
+            esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 0, _spp_server_name);
+        }
         xEventGroupSetBits(_spp_event_group, SPP_RUNNING);
         break;
 
     case ESP_SPP_SRV_OPEN_EVT://Server connection open
+        log_i("ESP_SPP_SRV_OPEN_EVT");
         if (!_spp_client){
             _spp_client = param->open.handle;
         } else {
             secondConnectionAttempt = true;
             esp_spp_disconnect(param->open.handle);
         }
+        xEventGroupClearBits(_spp_event_group, SPP_DISCONNECTED);
         xEventGroupSetBits(_spp_event_group, SPP_CONNECTED);
-        log_i("ESP_SPP_SRV_OPEN_EVT");
         break;
 
     case ESP_SPP_CLOSE_EVT://Client connection closed
+        log_i("ESP_SPP_CLOSE_EVT");
         if(secondConnectionAttempt) {
             secondConnectionAttempt = false;
         } else {
             _spp_client = 0;
-        }
+            xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
+        }        
         xEventGroupClearBits(_spp_event_group, SPP_CONNECTED);
-        log_i("ESP_SPP_CLOSE_EVT");
         break;
 
     case ESP_SPP_CONG_EVT://connection congestion status changed
@@ -216,25 +286,149 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
         }
         break;
 
-        //should maybe delete those.
     case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
         log_i("ESP_SPP_DISCOVERY_COMP_EVT");
+        if (param->disc_comp.status == ESP_SPP_SUCCESS) {
+            log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote");
+            esp_spp_connect(ESP_SPP_SEC_AUTHENTICATE, ESP_SPP_ROLE_MASTER, param->disc_comp.scn[0], _peer_bd_addr);
+        }
         break;
+
     case ESP_SPP_OPEN_EVT://Client connection open
         log_i("ESP_SPP_OPEN_EVT");
+        if (!_spp_client){
+                _spp_client = param->open.handle;
+        } else {
+            secondConnectionAttempt = true;
+            esp_spp_disconnect(param->open.handle);
+        }
+        xEventGroupClearBits(_spp_event_group, SPP_DISCONNECTED);
+        xEventGroupSetBits(_spp_event_group, SPP_CONNECTED);
         break;
+
     case ESP_SPP_START_EVT://server started
         log_i("ESP_SPP_START_EVT");
         break;
+
     case ESP_SPP_CL_INIT_EVT://client initiated a connection
         log_i("ESP_SPP_CL_INIT_EVT");
         break;
+
     default:
         break;
     }
     if(custom_spp_callback)(*custom_spp_callback)(event, param);
 }
 
+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:
+            log_i("ESP_BT_GAP_DISC_RES_EVT");
+            char bda_str[18];
+            log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
+            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)) {
+                            log_i("ESP_BT_GAP_DISC_RES_EVT : EIR : %s : %d", peer_bdname, peer_bdname_len);
+                            if (strlen(_remote_name) == peer_bdname_len
+                                && strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
+                                log_v("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_EIR : %s", peer_bdname, peer_bdname_len);
+                                _isRemoteAddressSet = true;
+                                memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
+                                esp_bt_gap_cancel_discovery();
+                                esp_spp_start_discovery(_peer_bd_addr);
+                            }
+                        }
+                        break;
+
+                    case ESP_BT_GAP_DEV_PROP_BDNAME:
+                        peer_bdname_len = param->disc_res.prop[i].len;
+                        memcpy(peer_bdname, param->disc_res.prop[i].val, peer_bdname_len);
+                        peer_bdname_len--; // len includes 0 terminator
+                        log_v("ESP_BT_GAP_DISC_RES_EVT : BDNAME :  %s : %d", peer_bdname, peer_bdname_len);
+                        if (strlen(_remote_name) == peer_bdname_len
+                            && strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
+                            log_i("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_BDNAME : %s", peer_bdname);
+                            _isRemoteAddressSet = true;
+                            memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
+                            esp_bt_gap_cancel_discovery();
+                            esp_spp_start_discovery(_peer_bd_addr);
+                        } 
+                        break;
+
+                    case ESP_BT_GAP_DEV_PROP_COD:
+                        //log_i("ESP_BT_GAP_DEV_PROP_COD");
+                        break;
+
+                    case ESP_BT_GAP_DEV_PROP_RSSI:
+                        //log_i("ESP_BT_GAP_DEV_PROP_RSSI");
+                        break;
+                        
+                    default:
+                        break;
+                }
+                if (_isRemoteAddressSet)
+                    break;
+            }
+            break;
+        case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
+            log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
+            break;
+
+        case ESP_BT_GAP_RMT_SRVCS_EVT:
+            log_i( "ESP_BT_GAP_RMT_SRVCS_EVT");
+            break;
+
+        case ESP_BT_GAP_RMT_SRVC_REC_EVT:
+            log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT");
+            break;
+
+        case ESP_BT_GAP_AUTH_CMPL_EVT:
+            if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
+                log_v("authentication success: %s", param->auth_cmpl.device_name);
+            } else {
+                log_e("authentication failed, status:%d", param->auth_cmpl.stat);
+            }
+            break;
+
+        case ESP_BT_GAP_PIN_REQ_EVT:
+            // default pairing pins
+            log_i("ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
+            if (param->pin_req.min_16_digit) {
+                log_i("Input pin code: 0000 0000 0000 0000");
+                esp_bt_pin_code_t pin_code;
+                memset(pin_code, '0', ESP_BT_PIN_CODE_LEN);
+                esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
+            } else {
+                log_i("Input pin code: 1234");
+                esp_bt_pin_code_t pin_code;
+                memcpy(pin_code, "1234", 4);
+                esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
+            }
+            break;
+       
+        case ESP_BT_GAP_CFM_REQ_EVT:
+            log_i("ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
+            esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
+            break;
+
+        case ESP_BT_GAP_KEY_NOTIF_EVT:
+            log_i("ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
+            break;
+
+        case ESP_BT_GAP_KEY_REQ_EVT:
+            log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
+            break;
+
+        default:
+            break;
+    }
+}
+
 static bool _init_bt(const char *deviceName)
 {
     if(!_spp_event_group){
@@ -245,6 +439,7 @@ static bool _init_bt(const char *deviceName)
         }
         xEventGroupClearBits(_spp_event_group, 0xFFFFFF);
         xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
+        xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
     }
     if (_spp_rx_queue == NULL){
         _spp_rx_queue = xQueueCreate(RX_QUEUE_SIZE, sizeof(uint8_t)); //initialize the queue
@@ -297,6 +492,11 @@ static bool _init_bt(const char *deviceName)
         }
     }
 
+    if (_isMaster && esp_bt_gap_register_callback(esp_bt_gap_cb) != ESP_OK) {
+        log_e("gap register failed");
+        return false;
+    }
+
     if (esp_spp_register_callback(esp_spp_cb) != ESP_OK){
         log_e("spp register failed");
         return false;
@@ -307,8 +507,20 @@ static bool _init_bt(const char *deviceName)
         return false;
     }
 
+    log_i("device name set");
     esp_bt_dev_set_device_name(deviceName);
 
+    if (_isPinSet) {
+        btSetPin();
+    }
+
+    if (_enableSSP) {
+        log_i("Simple Secure Pairing");
+        esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
+        esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
+        esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
+    }
+
     // the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack
     esp_bt_cod_t cod;
     cod.major = 0b00001;
@@ -318,7 +530,6 @@ static bool _init_bt(const char *deviceName)
         log_e("set cod failed");
         return false;
     }
-
     return true;
 }
 
@@ -361,6 +572,11 @@ static bool _stop_bt()
     return true;
 }
 
+static bool waitForConnect(int timeout) {
+    TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
+    return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) != 0);
+}
+
 /*
  * Serial Bluetooth Arduino
  *
@@ -376,8 +592,9 @@ BluetoothSerial::~BluetoothSerial(void)
     _stop_bt();
 }
 
-bool BluetoothSerial::begin(String localName)
+bool BluetoothSerial::begin(String localName, bool isMaster)
 {
+    _isMaster = isMaster;
     if (localName.length()){
         local_name = localName;
     }
@@ -445,4 +662,129 @@ esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t * callback)
     return ESP_OK;
 }
 
+//Simple Secure Pairing
+void BluetoothSerial::enableSSP() {
+    _enableSSP = true;
+}
+/*
+     * Set default parameters for Legacy Pairing
+     * Use fixed pin code
+*/
+bool BluetoothSerial::setPin(const char *pin) {
+    bool isEmpty =  !(pin  && *pin);
+    if (isEmpty && !_isPinSet) {
+        return true; // nothing to do
+    } else if (!isEmpty){
+        _pin_len = strlen(pin);
+        memcpy(_pin_code, pin, _pin_len);
+    } else {
+        _pin_len = 0; // resetting pin to none (default)
+    }
+    _pin_code[_pin_len] = 0;
+    _isPinSet = true;
+    if (isReady(false, READY_TIMEOUT)) {
+        btSetPin();
+    }
+    return true;
+}
+
+bool BluetoothSerial::connect(String remoteName)
+{
+    if (!isReady(true, READY_TIMEOUT)) return false;
+    if (remoteName && remoteName.length() < 1) {
+        log_e("No remote name is provided");
+        return false; 
+    }
+    disconnect();
+    _isRemoteAddressSet = false;
+    strncpy(_remote_name, remoteName.c_str(), ESP_BT_GAP_MAX_BDNAME_LEN);
+    _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN] = 0;
+    log_i("master : remoteName");
+    // will first resolve name to address
+    esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+    if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, INQ_LEN, INQ_NUM_RSPS) == ESP_OK) {
+        return waitForConnect(SCAN_TIMEOUT);
+    }
+    return false;
+}
+
+bool BluetoothSerial::connect(uint8_t remoteAddress[])
+{
+    if (!isReady(true, READY_TIMEOUT)) return false;
+    if (!remoteAddress) {
+        log_e("No remote address is provided");
+        return false; 
+    }
+    disconnect();
+    _remote_name[0] = 0;
+    _isRemoteAddressSet = true;
+    memcpy(_peer_bd_addr, remoteAddress, ESP_BD_ADDR_LEN);
+    log_i("master : remoteAddress");
+    if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) {
+        return waitForConnect(READY_TIMEOUT);
+    }
+    return false;
+}
+
+bool BluetoothSerial::connect()
+{
+    if (!isReady(true, READY_TIMEOUT)) return false;
+    if (_isRemoteAddressSet){
+        disconnect();
+        // use resolved or set address first
+        log_i("master : remoteAddress");
+        if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) {
+            return waitForConnect(READY_TIMEOUT);
+        }
+        return false;
+    } else if (_remote_name[0]) {
+        disconnect();
+        log_i("master : remoteName");
+        // will resolve name to address first - it may take a while
+        esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+        if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, INQ_LEN, INQ_NUM_RSPS) == ESP_OK) {
+            return waitForConnect(SCAN_TIMEOUT);
+        }
+        return false;
+    }
+    log_e("Neither Remote name nor address was provided");
+    return false;
+}
+
+bool BluetoothSerial::disconnect() {
+    if (_spp_client) {
+        flush();
+        log_i("disconnecting");
+        if (esp_spp_disconnect(_spp_client) == ESP_OK) {
+            TickType_t xTicksToWait = READY_TIMEOUT / portTICK_PERIOD_MS;
+            return (xEventGroupWaitBits(_spp_event_group, SPP_DISCONNECTED, pdFALSE, pdTRUE, xTicksToWait) != 0);
+        }
+    }
+    return false;
+}
+
+bool BluetoothSerial::unpairDevice(uint8_t remoteAddress[]) {
+    if (isReady(false, READY_TIMEOUT)) {
+        log_i("removing bonded device");
+        return (esp_bt_gap_remove_bond_device(remoteAddress) == ESP_OK);
+    }
+    return false;
+}
+
+bool BluetoothSerial::connected(int timeout) {
+    return waitForConnect(timeout);
+}
+
+bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
+    if (checkMaster && !_isMaster) {
+        log_e("Master mode is not active. Call begin(localName, true) to enable Master mode");
+        return false;
+    }
+    if (!btStarted()) {
+        log_e("BT is not initialized. Call begin() first");
+        return false;
+    }
+    TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
+    return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) != 0);
+}
 #endif
diff --git a/libraries/BluetoothSerial/src/BluetoothSerial.h b/libraries/BluetoothSerial/src/BluetoothSerial.h
old mode 100644
new mode 100755
index 3f4372e55d2..68269fa9ae6
--- a/libraries/BluetoothSerial/src/BluetoothSerial.h
+++ b/libraries/BluetoothSerial/src/BluetoothSerial.h
@@ -30,7 +30,7 @@ class BluetoothSerial: public Stream
         BluetoothSerial(void);
         ~BluetoothSerial(void);
 
-        bool begin(String localName=String());
+        bool begin(String localName=String(), bool isMaster=false);
         int available(void);
         int peek(void);
         bool hasClient(void);
@@ -41,6 +41,16 @@ class BluetoothSerial: public Stream
         void end(void);
         esp_err_t register_callback(esp_spp_cb_t * callback);
 
+        void enableSSP();
+        bool setPin(const char *pin);
+        bool connect(String remoteName);
+        bool connect(uint8_t remoteAddress[]);
+        bool connect();
+        bool connected(int timeout=0);
+        bool isReady(bool checkMaster=false, int timeout=0);
+        bool disconnect();
+        bool unpairDevice(uint8_t remoteAddress[]);
+
     private:
         String local_name;