Skip to content

BT serial: SSP improvements, added missing events #8453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 67 additions & 8 deletions libraries/BluetoothSerial/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,78 @@
### Bluetooth Serial Library
## Bluetooth Serial Library

A simple Serial compatible library using ESP32 classical bluetooth (SPP)
A simple Serial compatible library using ESP32 classical Bluetooth Serial Port Profile (SPP)

Note: Since version 3.0.0 this library does not support legacy pairing (using fixed PIN consisting of 4 digits).

### How to use it?

#### How to use it?
There are 3 basic use cases: phone, other ESP32 or any MCU with a Bluetooth serial module

- Download one bluetooth terminal app in your smartphone<br>
For Android: https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal <br>
For iOS: https://itunes.apple.com/us/app/hm10-bluetooth-serial-lite/id1030454675
#### Phone

- Download one of the Bluetooth terminal apps to your smartphone

- For [Android](https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal)
- For [iOS](https://itunes.apple.com/us/app/hm10-bluetooth-serial-lite/id1030454675)

- Flash an example sketch to your ESP32

- Scan and pair the device in your smartphone
- Scan and pair the device to your smartphone

- Open the bluetooth terminal app
- Open the Bluetooth terminal app and connect

- Enjoy

#### ESP32

You can flash one of the ESP32 with the example [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) (the Master) and another ESP32 with [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino) (the Slave).
Those examples are preset to work out-of-the-box but they should be scalable to connect multiple Slaves to the Master.
Comment on lines +26 to +29
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried following these instructions but couldn't get it to work. I am using two ESP32-DevKitC V4. Did I do something wrong or is it broken somehow ?

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is really strange... for me, it is also not working. However, I can connect to the slave from my smartphone.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, using my smartphone I also managed to connect. There might be something weird happening in the master sketch.


#### 3rd party Serial Bluetooth module

Using a 3rd party Serial Bluetooth module will require to study the documentation of the particular module in order to make it work, however, one side can utilize the mentioned [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) (the Master) or [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino) (the Slave).

### Pairing options

There are two easy options and one difficult.

The easy options can be used as usual. These offer pairing with and without Secure Simple Pairing (SSP).

The difficult option offers legacy pairing (using fixed PIN) however this must be compiled with Arduino as an IDF component with disabled sdkconfig option `CONFIG_BT_SSP_ENABLED`.

#### Without SSP

This method will authenticate automatically any attempt to pair and should not be used if security is a concern! This option is used for the examples [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) and [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino).

### With SSP

The usage of SSP provides a secure connection. This option is demonstrated in the example `SerialToSerialBT_SSP``](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino)

The Secure Simple Pairing is enabled by calling method `enableSSP` which has two variants - one is backward compatible without parameter `enableSSP()` and second with parameters `enableSSP(bool inputCapability, bool outputCapability)`. Similarly, the SSP can be disabled by calling `disableSSP()`.

Both options must be called before `begin()` or if it is called after `begin()` the driver needs to be restarted (call `end()` followed by `begin()`) in order to take in effect enabling or disabling the SSP.

#### The parameters define the method of authentication:

**inputCapability** - Defines if ESP32 device has input method (Serial terminal, keyboard or similar)

**outputCapability** - Defines if ESP32 device has output method (Serial terminal, display or similar)

* **inputCapability=true and outputCapability=true**
* Both devices display randomly generated code and if they match the user will authenticate pairing on both devices.
* This must be implemented by registering a callback via `onConfirmRequest()` and in this callback the user will input the response and call `confirmReply(true)` if the authenticated, otherwise call `confirmReply(false)` to reject the pairing.
* **inputCapability=false and outputCapability=false**
* Only the other device authenticates pairing without any pin.
* **inputCapability=false and outputCapability=true**
* Only the other device authenticates pairing without any pin.
* **inputCapability=true and outputCapability=false**
* The user will be required to input the passkey to the ESP32 device to authenticate.
* This must be implemented by registering a callback via `onKeyRequest`()` and in this callback the entered passkey will be responded via `respondPasskey(passkey)`

### Legacy Pairing (IDF component)

To use Legacy pairing you will have to use [Arduino as an IDF component](https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/esp-idf_component.html) and disable option `CONFIG_BT_SSP_ENABLED`.
Please refer to the documentation on how to setup Arduino as an IDF component and when you are done, run `idf.py menuconfig` navigate to `Component Config -> Bluetooth -> Bluedroid -> [ ] Secure Simple Pairing` and disable it.
While in the menuconfig you will also need to change the partition scheme `Partition Table -> Partition Table -> (X) Single Factory app (large), no OTA`.
After these changes save & quit menuconfig and you are ready to go: `idf.py monitor flash`.
Please note that to use the PIN in smartphones and computers you need to use characters `SerialBT.setPin("1234", 4);` not a number `SerialBT.setPin(1234, 4);` . Numbers CAN be used if the other side uses them too, but phones and computers use characters.
Original file line number Diff line number Diff line change
@@ -19,19 +19,18 @@
#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
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;


#define BT_DISCOVER_TIME 10000
esp_spp_sec_t sec_mask=ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation
esp_spp_role_t role=ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER
esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation
esp_spp_role_t role = ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER

// std::map<BTAddress, BTAdvertisedDeviceSet> btDeviceList;

Original file line number Diff line number Diff line change
@@ -6,11 +6,11 @@
String device_name = "ESP32-example";

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
//This example code is in the Public Domain (or CC0 licensed, at your option.)
//By Evandro Copercini - 2018
// This example code is in the Public Domain (or CC0 licensed, at your option.)
// By Evandro Copercini - 2018
//
//This example creates a bridge between Serial and Classical Bluetooth (SPP)
//and also demonstrate that SerialBT have the same functionalities of a normal Serial
// This example creates a bridge between Serial and Classical Bluetooth (SPP)
// and also demonstrate that SerialBT have the same functionalities of a normal Serial
// Note: Pairing is authenticated automatically by this device

#include "BluetoothSerial.h"

//#define USE_PIN // Uncomment this to use PIN during pairing. The pin is specified on the line below
const char *pin = "1234"; // Change this to more secure PIN.

String device_name = "ESP32-BT-Slave";

// Check if Bluetooth is available
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Check Serial Port Profile
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;

void setup() {
Serial.begin(115200);
SerialBT.begin(device_name); //Bluetooth device name
//SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin
Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str());
//Serial.printf("The device with name \"%s\" and MAC address %s is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str(), SerialBT.getMacString()); // Use this after the MAC method is implemented
#ifdef USE_PIN
SerialBT.setPin(pin);
Serial.println("Using PIN");
#endif
}

void loop() {
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
// This example code is in the Public Domain (or CC0 licensed, at your option.)
// By Victor Tchistiak - 2019
//
// This example demonstrates master mode Bluetooth connection to a slave BT device using PIN (password)
// defined either by String "slaveName" by default "OBDII" or by MAC address
// This example demonstrates master mode Bluetooth connection to a slave BT device
// defined either by String "slaveName" by default "ESP32-BT-Slave" or by MAC address
//
// This example creates a bridge between Serial and Classical Bluetooth (SPP)
// This is an extension of the SerialToSerialBT example by Evandro Copercini - 2018
//
// DO NOT try to connect to phone or laptop - they are master
// devices, same as the ESP using this code - it will NOT work!
// devices, same as the ESP using this code - you will be able
// to pair, but the serial communication will NOT work!
//
// You can try to flash a second ESP32 with the example SerialToSerialBT - it should
// automatically pair with ESP32 running this code
// Note: Pairing is authenticated automatically by this device

#include "BluetoothSerial.h"

#define USE_NAME // Comment this to use MAC address instead of a slaveName
const char *pin = "1234"; // Change this to reflect the pin expected by the real slave BT device

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
// Check if Bluetooth is available
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Check Serial Port Profile
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
#endif
BluetoothSerial SerialBT;

#ifdef USE_NAME
@@ -38,6 +44,7 @@ void setup() {
Serial.begin(115200);

SerialBT.begin(myName, true);
//SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin
Serial.printf("The device \"%s\" started in master mode, make sure slave BT device is on!\n", myName.c_str());

#ifndef USE_NAME
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// This example code is in the Public Domain (or CC0 licensed, at your option.)
//
// This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication)
// and also demonstrate that SerialBT have the same functionalities of a normal Serial
// Legacy pairing TODO
// Must be run as idf component ... todo

#include "BluetoothSerial.h"

// Check if Bluetooth is available
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Check Serial Port Profile
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
#endif

// Check Simple Secure Pairing
#if defined(CONFIG_BT_SSP_ENABLED)
#warning Legacy Pairing is disabled (CONFIG_BT_SSP_ENABLED is enabled. Disable it in menuconfig).
void setup(){}
void loop(){}
#else
const char * deviceName = "ESP32_Legacy_example";

BluetoothSerial SerialBT;
bool confirmRequestDone = false;

void BTAuthCompleteCallback(boolean success){
if (success){
confirmRequestDone = true;
Serial.println("Pairing success!!");
} else {
Serial.println("Pairing failed, rejected by user!!");
}
}

void serial_response(){
if (Serial.available()){
SerialBT.write(Serial.read());
}
if (SerialBT.available()){
Serial.write(SerialBT.read());
}
delay(20);
}

void setup(){
Serial.begin(115200);
SerialBT.onAuthComplete(BTAuthCompleteCallback);
SerialBT.begin(deviceName); // Initiate Bluetooth device with name in parameter
SerialBT.setPin("1234", 4);
Serial.printf("The device started with name \"%s\", now you can pair it with Bluetooth!\n", deviceName);
}

void loop(){
if (confirmRequestDone){
serial_response();
} else {
delay(1); // Feed the watchdog
}
}
#endif
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// This example code is in the Public Domain (or CC0 licensed, at your option.)
// By Richard Li - 2020
//
// This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication)
// and also demonstrate that SerialBT have the same functionalities of a normal Serial
// SSP - Simple Secure Pairing - The device (ESP32) will display random number and the user is responsible of comparing it to the number
// displayed on the other device (for example phone).
// If the numbers match the user authenticates the pairing on both devices - on phone simply press "Pair" and in terminal for the sketch send 'Y' or 'y' to confirm.
// Alternatively uncomment AUTO_PAIR to skip the terminal confirmation.

#include "BluetoothSerial.h"

//#define AUTO_PAIR // Uncomment to automatically authenticate ESP32 side

// Check if Bluetooth is available
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Check Serial Port Profile
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
#endif

// Check Simple Secure Pairing
#if !defined(CONFIG_BT_SSP_ENABLED)
#error Simple Secure Pairing for Bluetooth is not available or not enabled.
#endif

const char * deviceName = "ESP32_SSP_example";

// The following lines defines the method of pairing
// When both Input and Output are false only the other device authenticates pairing without any pin.
// When Output is true and Input is false only the other device authenticates pairing without any pin.
// When both Input and Output are true both devices display randomly generated code and if they match authenticate pairing on both devices
// - This must be implemented by registering callback via onConfirmRequest() and in this callback request user input and call confirmReply(true); if the authenticated
// otherwise call `confirmReply(false)` to reject the pairing.
// When Input is true and Output is false User will be required to input the passkey to the ESP32 device to authenticate.
// - This must be implemented by registering callback via onKeyRequest() and in this callback the entered passkey will be responded via respondPasskey(passkey);
const bool INPUT_CAPABILITY = false; // Defines if ESP32 device has input method (Serial terminal, keyboard or similar)
const bool OUTPUT_CAPABILITY = true; // Defines if ESP32 device has output method (Serial terminal, display or similar)

BluetoothSerial SerialBT;
bool confirmRequestDone = false;

void BTConfirmRequestCallback(uint32_t numVal){
confirmRequestDone = false;
#ifndef AUTO_PAIR
Serial.printf("The PIN is: %06lu. If it matches number displayed on the other device write \'Y\' or \'y\':\n", numVal); // Note the formatting "%06lu" - PIN can start with zero(s) which would be ignored with simple "%lu"
while (!Serial.available()) {
delay(1); // Feed the watchdog
// Wait until data is available on the Serial port.
}
Serial.printf("Oh you sent %d Bytes, lets see...", Serial.available());
int dat = Serial.read();
if (dat == 'Y' || dat == 'y'){
SerialBT.confirmReply(true);
}
else{
SerialBT.confirmReply(false);
}
#else
SerialBT.confirmReply(true);
#endif
}

void BTKeyRequestCallback(){
Serial.println("BTKeyRequestCallback"); // debug
char buffer[7] = {0}; // 6 bytes for number, one for termination '0'
while (1) {
Serial.print("Enter the passkey displayed on the other device: ");
while (!Serial.available()) {
delay(1); // Feed the watchdog
// Wait until data is available on the Serial port.
}
size_t len = Serial.readBytesUntil('\n', buffer, sizeof(buffer) - 1);
buffer[len] = '\0'; // Null-terminate the string.
try {
uint32_t passkey = std::stoi(buffer);
Serial.printf("Entered PIN: %lu\n", passkey);
SerialBT.respondPasskey(passkey);
return;
} catch (...) {
Serial.print("Wrong PIN! Try again.");
} // try
} // while(1)
}

void BTAuthCompleteCallback(boolean success){
if (success){
confirmRequestDone = true;
Serial.println("Pairing success!!");
} else {
Serial.println("Pairing failed, rejected by user!!");
}
}

void serial_response(){
if (Serial.available()){
SerialBT.write(Serial.read());
}
if (SerialBT.available()){
Serial.write(SerialBT.read());
}
delay(20);
}

void setup(){
Serial.begin(115200);
SerialBT.enableSSP(INPUT_CAPABILITY, OUTPUT_CAPABILITY); // Must be called before begin
SerialBT.onConfirmRequest(BTConfirmRequestCallback);
SerialBT.onKeyRequest(BTKeyRequestCallback);
SerialBT.onAuthComplete(BTAuthCompleteCallback);
SerialBT.begin(deviceName); // Initiate Bluetooth device with name in parameter
//SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin
Serial.printf("The device started with name \"%s\", now you can pair it with Bluetooth!\n", deviceName);
if(INPUT_CAPABILITY and OUTPUT_CAPABILITY){
Serial.println("Both devices will display randomly generated code and if they match authenticate pairing on both devices");
}else if(not INPUT_CAPABILITY and not OUTPUT_CAPABILITY){
Serial.println("Authenticate pairing on the other device. No PIN is used");
}else if(not INPUT_CAPABILITY and OUTPUT_CAPABILITY){
Serial.println("Authenticate pairing on the other device. No PIN is used");
}else if(INPUT_CAPABILITY and not OUTPUT_CAPABILITY){
Serial.println("After pairing is initiated you will be required to enter the passkey to the ESP32 device to authenticate\n > The Passkey will displayed on the other device");
}
}

void loop(){
if (confirmRequestDone){
serial_response();
} else {
delay(1); // Feed the watchdog
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
#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
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;


#define BT_DISCOVER_TIME 10000
#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());
Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str());
}

void setup() {
@@ -29,20 +29,20 @@ void setup() {


if (btScanAsync) {
Serial.print("Starting discoverAsync...");
Serial.print("Starting asynchronous discovery... ");
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\"");
Serial.println("Error on discoverAsync f.e. not working after a \"connect\"");
}
}

if (btScanSync) {
Serial.println("Starting discover...");
Serial.println("Starting synchronous discovery... ");
BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME);
if (pResults)
pResults->dump(&Serial);
Original file line number Diff line number Diff line change
@@ -1,91 +1,74 @@
//This example code is in the Public Domain (or CC0 licensed, at your option.)
//By Victor Tchistiak - 2019
// This example code is in the Public Domain (or CC0 licensed, at your option.)
// Originally by Victor Tchistiak - 2019
// Rewritten with new API by Tomas Pilny - 2023
//
//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"
// 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 "BluetoothSerial.h"
//#include "esp_bt_device.h"

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

#define REMOVE_BONDED_DEVICES 0 // <- Set to 0 to view all bonded devices addresses, set to 1 to remove

#define REMOVE_BONDED_DEVICES true // <- Set to `false` to view all bonded devices addresses, set to `true` 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;
}
BluetoothSerial SerialBT;

char *bda2str(const uint8_t* bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
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() {

void setup(){
char bda_str[18];
uint8_t pairedDeviceBtAddr[PAIR_MAX_DEVICES][6];
Serial.begin(115200);

initBluetooth();
Serial.print("ESP32 bluetooth address: "); Serial.println(bda2str(esp_bt_dev_get_address(), bda_str, 18));

SerialBT.begin();
Serial.printf("ESP32 bluetooth address: %s\n", SerialBT.getBtAddressString().c_str());
// SerialBT.deleteAllBondedDevices(); // If you want just delete all, this is the way
// 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.");
int count = SerialBT.getNumberOfBondedDevices();
if(!count){
Serial.println("No bonded devices 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);
Serial.printf("Bonded device count: %d\n", count);
if(PAIR_MAX_DEVICES < count){
count = PAIR_MAX_DEVICES;
Serial.printf("Reset %d bonded devices\n", 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);
count = SerialBT.getBondedDevices(count, pairedDeviceBtAddr);
char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
if(count > 0){
for(int i = 0; i < count; i++){
SerialBT.requestRemoteName(pairedDeviceBtAddr[i]);
while(!SerialBT.readRemoteName(rmt_name)){
delay(1); // Wait for response with the device name
}
}
}
}
Serial.printf("Found bonded device #%d BDA:%s; Name:\"%s\"\n", i, bda2str(pairedDeviceBtAddr[i], bda_str, 18), rmt_name);
SerialBT.invalidateRemoteName(); // Allows waiting for next reading
if(REMOVE_BONDED_DEVICES){
if(SerialBT.deleteBondedDevice(pairedDeviceBtAddr[i])){
Serial.printf("Removed bonded device # %d\n", i);
} else {
Serial.printf("Failed to remove bonded device # %d", i);
} // if(ESP_OK == tError)
} // if(REMOVE_BONDED_DEVICES)
} // for(int i = 0; i < count; i++)
} // if(ESP_OK == tError)
} // if(!count)
}

void loop() {}
16 changes: 8 additions & 8 deletions libraries/BluetoothSerial/src/BTScan.h
Original file line number Diff line number Diff line change
@@ -20,21 +20,21 @@ class BTAdvertisedDeviceSet;

class BTScanResults {
public:
virtual ~BTScanResults() = default;
virtual ~BTScanResults() = default;

virtual void dump(Print *print = nullptr);
virtual int getCount();
virtual void dump(Print *print = nullptr);
virtual int getCount();
virtual BTAdvertisedDevice* getDevice(int i);
};

class BTScanResultsSet : public BTScanResults {
public:
void dump(Print *print = nullptr);
int getCount();
BTAdvertisedDevice* getDevice(int i);
void dump(Print *print = nullptr);
int getCount();
BTAdvertisedDevice* getDevice(int i);

bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
void clear();
bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
void clear();

std::map<std::string, BTAdvertisedDeviceSet> m_vectorAdvertisedDevices;
};
554 changes: 367 additions & 187 deletions libraries/BluetoothSerial/src/BluetoothSerial.cpp

Large diffs are not rendered by default.

24 changes: 22 additions & 2 deletions libraries/BluetoothSerial/src/BluetoothSerial.h
Original file line number Diff line number Diff line change
@@ -26,9 +26,12 @@
#include <functional>
#include <map>
#include "BTScan.h"
#include "BTAdvertisedDevice.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()> KeyRequestCb;
typedef std::function<void(boolean success)> AuthCompleteCb;
typedef std::function<void(BTAdvertisedDevice* pAdvertisedDevice)> BTAdvertisedDeviceCb;

@@ -55,16 +58,25 @@ class BluetoothSerial: public Stream
void onData(BluetoothSerialDataCb cb);
esp_err_t register_callback(esp_spp_cb_t * callback);

#ifdef CONFIG_BT_SSP_ENABLED
void onConfirmRequest(ConfirmRequestCb cb);
void onKeyRequest(KeyRequestCb cb);
void respondPasskey(uint32_t passkey);
#endif
void onAuthComplete(AuthCompleteCb cb);
void confirmReply(boolean confirm);

#ifdef CONFIG_BT_SSP_ENABLED
void enableSSP();
bool setPin(const char *pin);
void enableSSP(bool inputCapability, bool outputCapability);
void disableSSP();
#else
bool setPin(const char *pin, uint8_t pin_code_len);
#endif
bool connect(String remoteName);
bool connect(uint8_t remoteAddress[], int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER);
bool connect(const BTAddress &remoteAddress, int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER) {
return connect(*remoteAddress.getNative(), channel, sec_mask); };
return connect(*remoteAddress.getNative(), channel, sec_mask); };
bool connect();
bool connected(int timeout=0);
bool isClosed();
@@ -88,6 +100,14 @@ class BluetoothSerial: public Stream
void getBtAddress(uint8_t *mac);
BTAddress getBtAddressObject();
String getBtAddressString();
//void dropCache(); // To be replaced
void requestRemoteName(uint8_t *remoteAddress);
bool readRemoteName(char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]);
void invalidateRemoteName();
int getNumberOfBondedDevices();
int getBondedDevices(uint dev_num, esp_bd_addr_t *dev_list);
bool deleteBondedDevice(uint8_t *remoteAddress);
void deleteAllBondedDevices();
private:
String local_name;
int timeoutTicks=0;