This commit is contained in:
2026-05-22 21:52:50 +03:00
commit be7c60e4dd
1854 changed files with 583428 additions and 0 deletions
@@ -0,0 +1,276 @@
/**
* A BLE client example that connects to multiple BLE servers simultaneously.
*
* This example demonstrates how to:
* - Scan for multiple BLE servers
* - Connect to multiple servers at the same time
* - Interact with characteristics on different servers
* - Handle disconnections and reconnections
*
* The example looks for servers advertising the service UUID: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
* and connects to up to MAX_SERVERS servers.
*
* Created by lucasssvaz
* Based on the original Client example by Neil Kolban and chegewara
*/
#include "BLEDevice.h"
// The remote service we wish to connect to.
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
// The characteristic of the remote service we are interested in.
static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
// Maximum number of servers to connect to
#define MAX_SERVERS 3
// Structure to hold information about each connected server
struct ServerConnection {
BLEClient *pClient;
BLEAdvertisedDevice *pDevice;
BLERemoteCharacteristic *pRemoteCharacteristic;
bool connected;
bool doConnect;
String name;
};
// Array to manage multiple server connections
ServerConnection servers[MAX_SERVERS];
int connectedServers = 0;
static bool doScan = true;
// Callback function to handle notifications from any server
static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify) {
// Find which server this notification came from
for (int i = 0; i < MAX_SERVERS; i++) {
if (servers[i].connected && servers[i].pRemoteCharacteristic == pBLERemoteCharacteristic) {
Serial.print("Notify from server ");
Serial.print(servers[i].name);
Serial.print(" - Characteristic: ");
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.print(" | Length: ");
Serial.print(length);
Serial.print(" | Data: ");
Serial.write(pData, length);
Serial.println();
break;
}
}
}
// Client callback class to handle connect/disconnect events
class MyClientCallback : public BLEClientCallbacks {
int serverIndex;
public:
MyClientCallback(int index) : serverIndex(index) {}
void onConnect(BLEClient *pclient) {
Serial.print("Connected to server ");
Serial.println(servers[serverIndex].name);
}
void onDisconnect(BLEClient *pclient) {
servers[serverIndex].connected = false;
connectedServers--;
Serial.print("Disconnected from server ");
Serial.print(servers[serverIndex].name);
Serial.print(" | Total connected: ");
Serial.println(connectedServers);
doScan = true; // Resume scanning to find replacement servers
}
};
// Function to connect to a specific server
bool connectToServer(int serverIndex) {
Serial.print("Connecting to server ");
Serial.print(serverIndex);
Serial.print(" at address: ");
Serial.println(servers[serverIndex].pDevice->getAddress().toString().c_str());
servers[serverIndex].pClient = BLEDevice::createClient();
Serial.println(" - Created client");
// Set the callback for this specific server connection
servers[serverIndex].pClient->setClientCallbacks(new MyClientCallback(serverIndex));
// Connect to the remote BLE Server
servers[serverIndex].pClient->connect(servers[serverIndex].pDevice);
Serial.println(" - Connected to server");
servers[serverIndex].pClient->setMTU(517); // Request maximum MTU from server
// Obtain a reference to the service we are after in the remote BLE server
BLERemoteService *pRemoteService = servers[serverIndex].pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find service UUID: ");
Serial.println(serviceUUID.toString().c_str());
servers[serverIndex].pClient->disconnect();
return false;
}
Serial.println(" - Found service");
// Obtain a reference to the characteristic in the service
servers[serverIndex].pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (servers[serverIndex].pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
servers[serverIndex].pClient->disconnect();
return false;
}
Serial.println(" - Found characteristic");
// Read the value of the characteristic
if (servers[serverIndex].pRemoteCharacteristic->canRead()) {
String value = servers[serverIndex].pRemoteCharacteristic->readValue();
Serial.print("Initial characteristic value: ");
Serial.println(value.c_str());
}
// Register for notifications if available
if (servers[serverIndex].pRemoteCharacteristic->canNotify()) {
servers[serverIndex].pRemoteCharacteristic->registerForNotify(notifyCallback);
Serial.println(" - Registered for notifications");
}
servers[serverIndex].connected = true;
connectedServers++;
Serial.print("Successfully connected! Total servers connected: ");
Serial.println(connectedServers);
return true;
}
// Scan callback class to find BLE servers
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// Check if this device has the service we're looking for
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
Serial.println(" -> This device has our service!");
// Check if we already know about this device
String deviceAddress = advertisedDevice.getAddress().toString().c_str();
bool alreadyKnown = false;
for (int i = 0; i < MAX_SERVERS; i++) {
if (servers[i].pDevice != nullptr) {
if (servers[i].pDevice->getAddress().toString() == deviceAddress) {
alreadyKnown = true;
break;
}
}
}
if (alreadyKnown) {
Serial.println(" -> Already connected or connecting to this device");
return;
}
// Find an empty slot for this server
for (int i = 0; i < MAX_SERVERS; i++) {
if (servers[i].pDevice == nullptr || (!servers[i].connected && !servers[i].doConnect)) {
servers[i].pDevice = new BLEAdvertisedDevice(advertisedDevice);
servers[i].doConnect = true;
servers[i].name = "Server_" + String(i);
Serial.print(" -> Assigned to slot ");
Serial.println(i);
// If we've found enough servers, stop scanning
int pendingConnections = 0;
for (int j = 0; j < MAX_SERVERS; j++) {
if (servers[j].connected || servers[j].doConnect) {
pendingConnections++;
}
}
if (pendingConnections >= MAX_SERVERS) {
Serial.println("Found enough servers, stopping scan");
BLEDevice::getScan()->stop();
doScan = false;
}
break;
}
}
}
}
};
void setup() {
Serial.begin(115200);
Serial.println("=================================");
Serial.println("BLE Multi-Client Example");
Serial.println("=================================");
Serial.print("Max servers to connect: ");
Serial.println(MAX_SERVERS);
Serial.println();
// Initialize all server connections
for (int i = 0; i < MAX_SERVERS; i++) {
servers[i].pClient = nullptr;
servers[i].pDevice = nullptr;
servers[i].pRemoteCharacteristic = nullptr;
servers[i].connected = false;
servers[i].doConnect = false;
servers[i].name = "";
}
// Initialize BLE
BLEDevice::init("ESP32_MultiClient");
// Set up BLE scanner
BLEScan *pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
Serial.println("Scanning for BLE servers...");
}
void loop() {
// Process any pending connections
for (int i = 0; i < MAX_SERVERS; i++) {
if (servers[i].doConnect) {
if (connectToServer(i)) {
Serial.println("Connection successful");
} else {
Serial.println("Connection failed");
// Clear this slot so we can try another server
delete servers[i].pDevice;
servers[i].pDevice = nullptr;
}
servers[i].doConnect = false;
}
}
// If we're connected to servers, send data to each one
if (connectedServers > 0) {
for (int i = 0; i < MAX_SERVERS; i++) {
if (servers[i].connected && servers[i].pRemoteCharacteristic != nullptr) {
// Create a unique message for each server
String newValue = servers[i].name + " | Time: " + String(millis() / 1000);
Serial.print("Sending to ");
Serial.print(servers[i].name);
Serial.print(": ");
Serial.println(newValue);
// Write the value to the characteristic
servers[i].pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
}
}
} else {
Serial.println("No servers connected");
}
// Resume scanning if we have room for more connections
if (doScan && connectedServers < MAX_SERVERS) {
Serial.println("Resuming scan for more servers...");
BLEDevice::getScan()->start(5, false);
doScan = false;
delay(5000); // Wait for scan to complete
}
delay(2000); // Delay between loop iterations
}
@@ -0,0 +1,5 @@
fqbn_append: PartitionScheme=huge_app
requires_any:
- CONFIG_SOC_BLE_SUPPORTED=y
- CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y