This commit is contained in:
2026-05-22 21:52:50 +03:00
commit be7c60e4dd
1854 changed files with 583428 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
## Bluetooth Serial Library
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?
There are 3 basic use cases: phone, other ESP32 or any MCU with a Bluetooth serial module
#### 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 to your smartphone
- 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.
#### 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.
@@ -0,0 +1,110 @@
/**
* Bluetooth Classic Example
* Scan for devices - asynchronously, print device as soon as found
* query devices for SPP - SDP profile
* connect to first device offering a SPP connection
*
* Example python server:
* source: https://gist.github.com/ukBaz/217875c83c2535d22a16ba38fc8f2a91
*
* Tested with Raspberry Pi onboard Wifi/BT, USB BT 4.0 dongles, USB BT 1.1 dongles,
* 202202: does NOT work with USB BT 2.0 dongles when esp32 arduino lib is compiled with SSP support!
* see https://github.com/espressif/esp-idf/issues/8394
*
* use ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side requests 'RequireAuthentication': dbus.Boolean(True),
* use ESP_SPP_SEC_NONE or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side has Authentication: False
*/
#include <map>
#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
#if !defined(CONFIG_BT_SPP_ENABLED)
#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
// std::map<BTAddress, BTAdvertisedDeviceSet> btDeviceList;
void setup() {
Serial.begin(115200);
if (!SerialBT.begin("ESP32test", true)) {
Serial.println("========== serialBT failed!");
abort();
}
// SerialBT.setPin("1234"); // doesn't seem to change anything
// SerialBT.enableSSP(); // doesn't seem to change anything
Serial.println("Starting discoverAsync...");
BTScanResults *btDeviceList = SerialBT.getScanResults(); // maybe accessing from different threads!
if (SerialBT.discoverAsync([](BTAdvertisedDevice *pDevice) {
// BTAdvertisedDeviceSet*set = reinterpret_cast<BTAdvertisedDeviceSet*>(pDevice);
// btDeviceList[pDevice->getAddress()] = * set;
Serial.printf(">>>>>>>>>>>Found a new device asynchronously: %s\n", pDevice->toString().c_str());
})) {
delay(BT_DISCOVER_TIME);
Serial.print("Stopping discoverAsync... ");
SerialBT.discoverAsyncStop();
Serial.println("discoverAsync stopped");
delay(5000);
if (btDeviceList->getCount() > 0) {
BTAddress addr;
int channel = 0;
Serial.println("Found devices:");
for (int i = 0; i < btDeviceList->getCount(); i++) {
BTAdvertisedDevice *device = btDeviceList->getDevice(i);
Serial.printf(" ----- %s %s %d\n", device->getAddress().toString().c_str(), device->getName().c_str(), device->getRSSI());
std::map<int, std::string> channels = SerialBT.getChannels(device->getAddress());
Serial.printf("scanned for services, found %zu\n", channels.size());
for (auto const &entry : channels) {
Serial.printf(" channel %d (%s)\n", entry.first, entry.second.c_str());
}
if (channels.size() > 0) {
addr = device->getAddress();
channel = channels.begin()->first;
}
}
if (addr) {
Serial.printf("connecting to %s - %d\n", addr.toString().c_str(), channel);
SerialBT.connect(addr, channel, sec_mask, role);
}
} else {
Serial.println("Didn't find any devices");
}
} else {
Serial.println("Error on discoverAsync f.e. not working after a \"connect\"");
}
}
String sendData = "Hi from esp32!\n";
void loop() {
if (!SerialBT.isClosed() && SerialBT.connected()) {
if (SerialBT.write((const uint8_t *)sendData.c_str(), sendData.length()) != sendData.length()) {
Serial.println("tx: error");
} else {
Serial.printf("tx: %s", sendData.c_str());
}
if (SerialBT.available()) {
Serial.print("rx: ");
while (SerialBT.available()) {
int c = SerialBT.read();
if (c >= 0) {
Serial.print((char)c);
}
}
Serial.println();
}
} else {
Serial.println("not connected");
}
delay(1000);
}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,49 @@
// This example demonstrates usage of BluetoothSerial method to retrieve MAC address of local BT device in various formats.
// By Tomas Pilny - 2023
#include "BluetoothSerial.h"
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
#endif
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth 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
uint8_t mac_arr[6]; // Byte array to hold the MAC address from getBtAddress()
BTAddress mac_obj; // Object holding instance of BTAddress with the MAC (for more details see libraries/BluetoothSerial/src/BTAddress.h)
String mac_str; // String holding the text version of MAC in format AA:BB:CC:DD:EE:FF
SerialBT.getBtAddress(mac_arr); // Fill in the array
mac_obj = SerialBT.getBtAddressObject(); // Instantiate the object
mac_str = SerialBT.getBtAddressString(); // Copy the string
Serial.print("This device is instantiated with name ");
Serial.println(device_name);
Serial.print("The mac address using byte array: ");
for (int i = 0; i < ESP_BD_ADDR_LEN - 1; i++) {
Serial.print(mac_arr[i], HEX);
Serial.print(":");
}
Serial.println(mac_arr[ESP_BD_ADDR_LEN - 1], HEX);
Serial.print("The mac address using BTAddress object using default method `toString()`: ");
Serial.println(mac_obj.toString().c_str());
Serial.print("The mac address using BTAddress object using method `toString(true)`\n\twhich prints the MAC with capital letters: ");
Serial.println(mac_obj.toString(true).c_str()); // This actually what is used inside the getBtAddressString()
Serial.print("The mac address using string: ");
Serial.println(mac_str.c_str());
}
void loop() {}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,39 @@
// 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
// Note: Pairing is authenticated automatically by this device
#include "BluetoothSerial.h"
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
#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;
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());
}
void loop() {
if (Serial.available()) {
SerialBT.write(Serial.read());
}
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20);
}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,97 @@
// 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
// 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 - 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
// 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
String slaveName = "ESP32-BT-Slave"; // Change this to reflect the real name of your slave BT device
#else
String MACadd = "AA:BB:CC:11:22:33"; // This only for printing
uint8_t address[6] = {0xAA, 0xBB, 0xCC, 0x11, 0x22, 0x33}; // Change this to reflect real MAC address of your slave BT device
#endif
String myName = "ESP32-BT-Master";
void setup() {
bool connected;
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
SerialBT.setPin(pin);
Serial.println("Using PIN");
#endif
// connect(address) is fast (up to 10 secs max), connect(slaveName) is slow (up to 30 secs max) as it needs
// to resolve slaveName 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
#ifdef USE_NAME
connected = SerialBT.connect(slaveName);
Serial.printf("Connecting to slave BT device named \"%s\"\n", slaveName.c_str());
#else
connected = SerialBT.connect(address);
Serial.print("Connecting to slave BT device with MAC ");
Serial.println(MACadd);
#endif
if (connected) {
Serial.println("Connected Successfully!");
} 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 up to 10 secs max
if (SerialBT.disconnect()) {
Serial.println("Disconnected Successfully!");
}
// This would reconnect to the slaveName(will use address, if resolved) or address used with connect(slaveName/address).
SerialBT.connect();
if (connected) {
Serial.println("Reconnected Successfully!");
} else {
while (!SerialBT.connected(10000)) {
Serial.println("Failed to reconnect. Make sure remote device is available and in range, then restart app.");
}
}
}
void loop() {
if (Serial.available()) {
SerialBT.write(Serial.read());
}
if (SerialBT.available()) {
Serial.write(SerialBT.read());
}
delay(20);
}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,58 @@
// 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
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
}
}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,131 @@
// 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
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
}
}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,53 @@
#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
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#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 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 working after a \"connect\"");
}
}
if (btScanSync) {
Serial.println("Starting synchronous discovery... ");
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);
}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
@@ -0,0 +1,73 @@
// 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 "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.
#endif
#define REMOVE_BONDED_DEVICES true // <- Set to `false` to view all bonded devices addresses, set to `true` to remove
#define PAIR_MAX_DEVICES 20
BluetoothSerial SerialBT;
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() {
char bda_str[18];
uint8_t pairedDeviceBtAddr[PAIR_MAX_DEVICES][6];
Serial.begin(115200);
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 = SerialBT.getNumberOfBondedDevices();
if (!count) {
Serial.println("No bonded devices found.");
} else {
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);
}
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() {}
@@ -0,0 +1,4 @@
fqbn_append: PartitionScheme=huge_app
requires:
- CONFIG_BT_SPP_ENABLED=y
+26
View File
@@ -0,0 +1,26 @@
#######################################
# Syntax Coloring Map For BluetoothSerial
#######################################
#######################################
# Library (KEYWORD3)
#######################################
BluetoothSerial KEYWORD3
#######################################
# Datatypes (KEYWORD1)
#######################################
BluetoothSerial KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
SerialBT KEYWORD2
hasClient KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
@@ -0,0 +1,9 @@
name=BluetoothSerial
version=3.3.7
author=Evandro Copercini
maintainer=Evandro Copercini
sentence=Simple UART to Classical Bluetooth bridge for ESP32
paragraph=
category=Communication
url=
architectures=esp32
+114
View File
@@ -0,0 +1,114 @@
/*
* BTAddress.cpp
*
* Created on: Jul 2, 2017
* Author: kolban
* Ported on: Feb 5, 2021
* Author: Thomas M. (ArcticSnowSky)
*/
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_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
BTAddress::BTAddress() {
bzero(m_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(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
BTAddress::operator bool() const {
for (int i = 0; i < ESP_BD_ADDR_LEN; i++) {
if (this->m_address[i]) {
return true;
}
}
return false;
} // operator ()
/**
* @brief Return the native representation of the address.
* @return The native representation of the address.
*/
esp_bd_addr_t *BTAddress::getNative() const {
return const_cast<esp_bd_addr_t *>(&m_address);
} // getNative
/**
* @brief Convert a BT address to a string.
* @param [in] capital changes the letter size
* By default the parameter `capital` == false and the string representation of an address is in the format:
* ```
* xx:xx:xx:xx:xx:xx
* ```
* When the parameter `capital` == true the format uses capital letters:
* ```
* XX:XX:XX:XX:XX:XX
* ```
* @return The string representation of the address.
*/
String BTAddress::toString(bool capital) const {
auto size = 18;
char *res = (char *)malloc(size);
if (capital) {
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]);
} else {
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]);
}
String ret(res);
free(res);
return ret;
} // toString
#endif
+40
View File
@@ -0,0 +1,40 @@
/*
* 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"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
#include <esp_gap_bt_api.h> // ESP32 BT
#include <Arduino.h>
/**
* @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();
BTAddress(esp_bd_addr_t address);
BTAddress(String stringAddress);
bool equals(BTAddress otherAddress);
operator bool() const;
esp_bd_addr_t *getNative() const;
String toString(bool capital = false) const;
private:
esp_bd_addr_t m_address;
};
#endif /* CONFIG_BT_ENABLED */
#endif /* COMPONENTS_CPP_UTILS_BTADDRESS_H_ */
@@ -0,0 +1,63 @@
/*
* BTAdvertisedDevice.h
*
* Created on: Feb 5, 2021
* Author: Thomas M. (ArcticSnowSky)
*/
#pragma once
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
#include "BTAddress.h"
#include <string>
class BTAdvertisedDevice {
public:
virtual ~BTAdvertisedDevice() = default;
virtual BTAddress getAddress() = 0;
virtual uint32_t getCOD() const = 0;
virtual std::string getName() const = 0;
virtual int8_t getRSSI() const = 0;
virtual bool haveCOD() const = 0;
virtual bool haveName() const = 0;
virtual bool haveRSSI() const = 0;
virtual std::string toString() = 0;
};
class BTAdvertisedDeviceSet : public virtual BTAdvertisedDevice {
public:
BTAdvertisedDeviceSet();
//~BTAdvertisedDeviceSet() = default;
BTAddress getAddress();
uint32_t getCOD() const;
std::string getName() const;
int8_t getRSSI() const;
bool haveCOD() const;
bool haveName() const;
bool haveRSSI() const;
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
@@ -0,0 +1,91 @@
/*
* BTAdvertisedDeviceSet.cpp
*
* Created on: Feb 5, 2021
* Author: Thomas M. (ArcticSnowSky)
*/
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_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() const {
return m_cod;
}
std::string BTAdvertisedDeviceSet::getName() const {
return m_name;
}
int8_t BTAdvertisedDeviceSet::getRSSI() const {
return m_rssi;
}
bool BTAdvertisedDeviceSet::haveCOD() const {
return m_haveCOD;
}
bool BTAdvertisedDeviceSet::haveName() const {
return m_haveName;
}
bool BTAdvertisedDeviceSet::haveRSSI() const {
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: " + std::string(getAddress().toString().c_str(), getAddress().toString().length());
if (haveCOD()) {
char val[7]; //6 hex digits + null
snprintf(val, sizeof(val), "%06lx", getCOD() & 0xFFFFFF);
res += ", cod: 0x";
res += val;
}
if (haveRSSI()) {
char val[6];
snprintf(val, sizeof(val), "%d", (int8_t)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 */
+44
View File
@@ -0,0 +1,44 @@
/*
* BTScan.h
*
* Created on: Feb 5, 2021
* Author: Thomas M. (ArcticSnowSky)
*/
#pragma once
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
#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) = 0;
virtual int getCount() = 0;
virtual BTAdvertisedDevice *getDevice(int i) = 0;
};
class BTScanResultsSet : public BTScanResults {
public:
void dump(Print *print = nullptr);
int getCount();
BTAdvertisedDevice *getDevice(int i);
bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true);
void clear();
std::map<std::string, BTAdvertisedDeviceSet> m_vectorAdvertisedDevices;
};
#endif
@@ -0,0 +1,99 @@
/*
* BTScanResultsSet.cpp
*
* Created on: Feb 5, 2021
* Author: Thomas M. (ArcticSnowSky)
*/
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_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(int i) {
if (i < 0) {
return nullptr;
}
int 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 = std::string(advertisedDevice.getAddress().toString().c_str(), advertisedDevice.getAddress().toString().length());
if (!unique || m_vectorAdvertisedDevices.count(key) == 0) {
m_vectorAdvertisedDevices.insert(std::pair<std::string, BTAdvertisedDeviceSet>(key, advertisedDevice));
return true;
} else {
return false;
}
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,120 @@
// Copyright 2018 Evandro Luis Copercini
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _BLUETOOTH_SERIAL_H_
#define _BLUETOOTH_SERIAL_H_
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
#include "Arduino.h"
#include "Stream.h"
#include <esp_gap_bt_api.h>
#include <esp_spp_api.h>
#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;
class [[deprecated("BluetoothSerial won't be supported in version 4.0.0 by default")]] BluetoothSerial : public Stream {
public:
BluetoothSerial(void);
~BluetoothSerial(void);
bool begin(String localName = String(), bool isMaster = false, bool disableBLE = false);
bool begin(unsigned long baud) { //compatibility
return begin();
}
int available(void);
int peek(void);
bool hasClient(void);
int read(void);
size_t write(uint8_t c);
size_t write(const uint8_t *buffer, size_t size);
void flush();
void end(void);
void memrelease();
void setTimeout(int timeoutMS);
void onData(BluetoothSerialDataCb cb);
esp_err_t register_callback(esp_spp_cb_t callback);
void onConfirmRequest(ConfirmRequestCb cb);
void onKeyRequest(KeyRequestCb cb);
void respondPasskey(uint32_t passkey);
void onAuthComplete(AuthCompleteCb cb);
void confirmReply(boolean confirm);
void enableSSP();
void enableSSP(bool inputCapability, bool outputCapability);
void disableSSP();
bool setPin(const char *pin, uint8_t pin_code_len);
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);
};
bool connect();
bool connected(int timeout = 0);
bool isClosed();
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();
std::map<int, std::string> getChannels(const BTAddress &remoteAddress);
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;
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;
};
#endif
#endif