Comments (18)
Hi, this program is sort of working but need further improvement:
- on starting and stopping scan...
- on connection
IMPORTANT: might not work with older version
Arduino Version: 2.0.1-nightly-20221024
ESP32 2.0.5
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* Copyright © 2022 Arduino SA
* author unknown
* updated by chegewara
* modified for 3 connections by Sylvain Lareau
* usefull exemple https://www.youtube.com/watch?v=iCKIIMrphtg
* IMPORTANT: might not work with older version
Arduino Version: 2.0.1-nightly-20221024
ESP32 2.0.5
The program is not final and could easely be improve and simplified...
*/
#include "BLEDevice.h"
int LED_BUILTIN = 2;
bool toggle;
// The remote service we wish to connect to
//static BLEUUID0 serviceUUID("0000180d-0000-1000-8000-00805f9b34fb"); //0x180D
//BLEUUID become a type, like int or boolean
static BLEUUID serviceUUID0(BLEUUID((uint16_t)0x180D )); //Heart Rate
static BLEUUID charUUID0(BLEUUID((uint16_t)0x2A37));
static BLEUUID serviceUUID1(BLEUUID((uint16_t)0x1818 )); // Cycling Power
static BLEUUID charUUID1(BLEUUID((uint16_t)0x2A63));
static BLEUUID serviceUUID2(BLEUUID((uint16_t)0xFEE0 )); // SPO2
static BLEUUID charUUID2(BLEUUID((uint16_t)0xFEE1));
static boolean doConnect0 = false;
static boolean connected0 = false;
static boolean doConnect1 = false;
static boolean connected1 = false;
static boolean doConnect2 = false;
static boolean connected2 = false;
static boolean doScan0 = false;
static boolean doScan1 = false;
static boolean doScan2 = false;
static boolean notification0 = false;
static boolean notification1 = false;
static boolean notification2 = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;
static void notifyCallback0(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
//Serial.print("Notify callback for characteristic ");
// Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
// Serial.print(" of data length ");
// Serial.println(length);
// Serial.print("data: ");
//Serial.println((char*)pData);
Serial.print("HR_sensor value: ");
Serial.print(pData[1], DEC);
}
static void notifyCallback1(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
int CPower = pData[2] + 256 * pData[3];
Serial.print("Power value: ");
Serial.println(CPower);
}
static void notifyCallback2(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
if (length == 4) {
int SPO2 = pData[2];
Serial.print("SPO2: "); Serial.println(SPO2);
int PR = pData[3]; // pulse rate
Serial.print("PI: "); Serial.println(PR);
}
}
class MyClientCallback0 : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}
void onDisconnect(BLEClient* pclient) {
connected0 = false;
notification0 = false;
Serial.println("onDisconnect 0 ");
}
};
class MyClientCallback1 : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}
void onDisconnect(BLEClient* pclient) {
connected1 = false;
notification1 = false;
Serial.println("onDisconnect 1 ");
}
};
class MyClientCallback2 : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}
void onDisconnect(BLEClient* pclient) {
connected2 = false;
notification2 = false;
Serial.println("onDisconnect 2");
}
};
bool connectToServer(int sensor, BLEUUID serviceUUID, BLEUUID charUUID) {// BLEUUID = type like integer
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
if (sensor == 0) pClient->setClientCallbacks(new MyClientCallback0());
else if (sensor == 1) pClient->setClientCallbacks(new MyClientCallback1());
else if (sensor == 2) pClient->setClientCallbacks(new MyClientCallback2());
// Connect to the remove BLE Server.
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
Serial.print(" - Connected to server ");
Serial.println(sensor);
pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID sensor ");
Serial.print (sensor);
Serial.print (" : ");
Serial.println(serviceUUID0.toString().c_str());
pClient->disconnect();
return false;
}
Serial.print(" - Found our service ");
Serial.println (sensor);
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID0.toString().c_str());
pClient->disconnect();
return false;
}
Serial.print(" - Found our characteristic ");
Serial.println (sensor);
// Read the value of the characteristic.
if(pRemoteCharacteristic->canRead()) {
std::string value = pRemoteCharacteristic->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
}
if (sensor == 0) {
if(pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback0);
connected0 = true;
return true;
}
else if (sensor == 1) {
if(pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback1);
connected1 = true;
return true;
}
else if (sensor == 2) {
if(pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback2);
connected2 = true;
return true;
}
}
/**
* Scan for BLE servers and find the one that advertises the service we are looking for.
*/
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service we are looking for.
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID0)) {
//BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice); // not used?
doConnect0 = true;
doScan0 = true;
Serial.print("Found serviceUUID0");
} // Found our server
// We have found a device, let us now see if it contains the service we are looking for.
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID1)) {
//BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect1 = true;
doScan1 = true;
Serial.print("Found serviceUUID1");
} // Found our server1
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID2)) {
//BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect2 = true;
doScan2 = true;
Serial.print("Found serviceUUID2");
} // Found our server2
} // onResult
}; // MyAdvertisedDeviceCallbacks
//*********************************
void setup() {
Serial.begin(1000000);
Serial.println("Starting Arduino BLE Client application...");
pinMode (LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
BLEDevice::init("");
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
// I have played with those value, but lack good documentation... Help needed
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(10000); // millisec , will affect the program main loop frequency 10000 = 10sec
pBLEScan->setWindow(400); // millisec
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false); // sec
//pBLEScan->start(0);
} // End of setup.
// This is the Arduino main loop function.
void loop() {
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
/*Serial.print("doConnect0 ");
Serial.println(doConnect0);
Serial.print("doConnect1 ");
Serial.println(doConnect1);
Serial.print("doConnect2 ");
Serial.println(doConnect2);*/
if (toggle) digitalWrite(LED_BUILTIN, HIGH);
else digitalWrite(LED_BUILTIN, LOW);
toggle = !toggle;
if (doConnect0 == true) {
if (connectToServer(0, serviceUUID0, charUUID0)) {
Serial.println("We are now connected to the BLE Server 0.");
} else {
Serial.println("We have failed to connect to the server 0; there is nothin more we will do.");
}
doConnect0 = false;
}
if (doConnect1 == true) {
if (connectToServer(1, serviceUUID1, charUUID1)) {
Serial.println("We are now connected to the BLE Server 1.");
} else {
Serial.println("We have failed to connect to the server 1; there is nothin more we will do.");
}
doConnect1 = false;
}
if (doConnect2 == true) {
if (connectToServer(2, serviceUUID2, charUUID2)) {
Serial.println("We are now connected to the BLE Server 2.");
} else {
Serial.println("We have failed to connect to the server 2 ; there is nothin more we will do.");
}
doConnect2 = false;
}
/*
Serial.print("connected0 "); Serial.println(connected0);
Serial.print("connected1 ");Serial.println(connected1);
Serial.print("connected2 ");Serial.println(connected2);
Serial.print("notification0 ");Serial.println(notification0);
Serial.print("notification1 ");Serial.println(notification1);
Serial.print("notification2 ");Serial.println(notification2);
*/
/*Serial.print("doScan0 ");
Serial.println(doScan0);
Serial.print("doScan1 ");
Serial.println(doScan1);
Serial.print("doScan1 ");
Serial.println(doScan1);*/
// Need to repeat getScan()->start or it wont connect to the second+ server:
if (connected0 && connected1 && connected2) BLEDevice::getScan()->stop();
else BLEDevice::getScan()->start(5, false);
// Turn notification on
if (connected0) {
if (notification0 == false) {
Serial.println(F("Turning Notification On for sensor 0")); // F is an optimisation thing...
const uint8_t onPacket[] = {0x1, 0x0}; // not shure about these number but it works
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)onPacket, 2, true);
notification0 = true;
} }
else if(doScan0){ // try to reconnect
// BLEDevice::getScan()->start(0);
BLEDevice::getScan()->start(5, false);
}
if (connected1) {
if (notification1 == false) {
Serial.println(F("Turning Notification On for sensor 1"));
const uint8_t onPacket[] = {0x1, 0x0}; // not shure about these number but it works
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)onPacket, 2, true);
notification1 = true;
} }
else if(doScan1){
BLEDevice::getScan()->start(5, false); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
}
if (connected2) {
if (notification2 == false) {
Serial.println(F("Turning Notification On for sensor 2"));
const uint8_t onPacket[] = {0x1, 0x0}; // not shure about these number but it works
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)onPacket, 2, true);
notification2 = true;
} }
else if(doScan2){
BLEDevice::getScan()->start(5, false); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
}
delay(1000); // Delay a second between loops.
} // End of loop
from arduino-esp32.
Is there any proper example that connects multiple BLE servers to ESP-32 BLE client?? Suggests me.
There is an IDF example of GATTC connecting to 3 BLE Servers: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/gattc_multi_connect
Tutorial and explanation: https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md
I think UmangSuthar101 was interested in using Arduino API not IDF. I have the same question and have not found any good example so far.
from arduino-esp32.
SL06 BLEDevice::createClient(); overwrites a pointer in BLEdevice so making second client will likely break some callback events to 1st one going through that pointer and create memory leaks. The BLEDevice does not support multiple instances either. There is no reference to the client instance in call backs so I do not see how the connection is managed. The lack of any example lets me to conclusion that was not written to support multiple server connections properly.
I have tried to create the instance using "new BLEClient()" and it does work so far. but it needs a wrapper to all callbacks to be aware to what client is the message from/to. I can post the code here when finished if anyone is interested.
from arduino-esp32.
@UmangSuthar101
The issue header says you are using Arduino Core 1.0.6. It is based on an old IDF version for BLE.
Could you please update your Arduino Core to the latest version in the Arduino IDE.
Current Core version is 2.0.3.
Let me know is the issue still occurs.
Thanks.
from arduino-esp32.
@SuGlider , as you mentioned I update the esp-arduino to latest version 2.0.3 and again I got the following log check this:
Pulse: 84
SPO2: 99
Disconnect to Spo2 Device
Connect to Temp. Device
Connected to Temp.
We are now connected to the Temp. BLE Server.
Temp. : 98.26
lld_pdu_get_tx_flush_nb HCI packet count mismatch (0, 1)
Connect to BP Device
Connected to BP
lld_pdu_get_tx_flush_nb HCI packet count mismatch (1, 2)
Disconnect to BP Device
We have failed to connect to the BP server; there is nothin more we will do.
Disconnect to Temp. Device
from arduino-esp32.
@chegewara - Could you please help @UmangSuthar101 on this issue? Thanks!
from arduino-esp32.
Greetings of the day,
@SuGlider & @chegewara could you plz help me with this issue, its very difficult for me to get multiple ble server data to ESP-32 ble client !!!
from arduino-esp32.
This is low level error/warning log. I can only guessing it may be related to low memory, but this should be asked on esp-idf.
from arduino-esp32.
@chegewara I asked espriff team and they suggested me asking on esp-Arduino.
And this is not a warning log because after this line I cann't able to connect any BLE servers.
I also try this code on 8MB module but the same error show me, whenever I connect multiple BLE servers.
Is there any proper example that connects multiple BLE servers to ESP-32 BLE client?? Suggests me.
from arduino-esp32.
Again, lld_pdu_*
are low level library messages, and we dont even have access to source code to ungerstand what it means.
If espressif is not willing to help you then maybe you should switch to nordic.
This is not problem with flash, so 4MB or 8MB makes no difference, but you should try to switch to NimBLE library.
Its easy, and ive read its working better, has better support and most important its using less RAM.
from arduino-esp32.
@chegewara ok, get it!! I'll check NimBLE.
But is there any example or reference link(with ArduinoBLE library) which already connects multiple servers to the ESP BLE client, if that one gives me success then I will go through it?
from arduino-esp32.
Im pretty sure you can find some, but nothing i am aware of.
from arduino-esp32.
Is there any proper example that connects multiple BLE servers to ESP-32 BLE client?? Suggests me.
There is an IDF example of GATTC connecting to 3 BLE Servers:
https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/gattc_multi_connect
Tutorial and explanation:
https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md
from arduino-esp32.
@UmangSuthar101
I believe that it's necessary to instantiate one BLEClient object per Server connection in BLE Arduino Layer in order to make it work the way you need it.
from arduino-esp32.
The best and more stable BLE stack is the "NimbleBLE"....
try using it from the link: https://github.com/h2zero/NimBLE-Arduino.git
from arduino-esp32.
petrrpancon - I would be interested in the code when finished. I'm trying to connect a single ESP32 client to multiple identical BLE motion sensors (with different addresses) at the same time and read their notification data; Arduino IDE.
from arduino-esp32.
@petrrpancon could share the code please, I'm trying to connect more than two clients and get their rssi continously
from arduino-esp32.
Hi, the code is part of a project and I can not easily extract it, but let me show what i did.
getScan is singleton so it will give you the same instance every time. I would run it only from 1 thread anyway.
I call this once at start:
{
BLEDevice::init("");
BLEScan *scn = BLEDevice::getScan();
scn->setAdvertisedDeviceCallbacks(&scan_cb);
scn->setActiveScan(false);
}
then I have 2 clients as example:
ClientExt1 client1;
ClientExt2 client2;
then call this in loop task
for(;;)
{
if (should_scan_for_connection(client)) // what ever condition to start the search
{
BLEScan *scn = BLEDevice::getScan();
scn->start(2, false);
if (check_for_found_device(client1)) // BLEAdvertisedDeviceCallbacks was called
{
here you can use
client1.connect(BLEAddress address, esp_ble_addr_type_t type)
with data from the event advertisedDevice.getAddress()
}
if (check_for_found_device(client2)) // BLEAdvertisedDeviceCallbacks was called
{
same here for the other client
}
}
else
{
block the thread until something changes
}
}
scan_cb is the instance class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
for event when device is found and you need to check if it is something compatible in this method:
void MyAdvertisedDeviceCallbacks::onResult(BLEAdvertisedDevice advertisedDevice)
{
check uuid or some other stuff matching your device here
if you find the device you can stop the scan here immediately and store the address.
}
the advertisedDevice contains address to make connection advertisedDevice.getAddress()
so you can use that to connect to client.
you can create multiple instance of BLEClient, even extend this class with you own data. It woks as global instance or on heap with "new BLEClient". However managing dynamic data is harder to do right. Just do not use createClient. If you make more instances of the same ClientExt1 you check the client pointer inside any share callback so it still works for multiples.
class ClientExt1 : public BLEClient
{
// data specific to your client
}
After the connection i run each client in its thread. It seem to work fine but don't expect a production quality from the arduino code. especially with threads. Esp32 had limit of 4 connections so be aware of that too.
from arduino-esp32.
Related Issues (20)
- Legacy integration in Arduino IDE HOT 14
- 3.0.0 alpha disappeared from dev update site HOT 8
- v3.0.0-RC1 possible regression - WiFi not declared in this scope (was in 3.0.0-alpha3) HOT 3
- UART: Serial2 wont work on Arduino Core v2.0.15 HOT 8
- ESP32 board only returning 0.0.0.0 as Access point when trying to use cam webserver HOT 1
- ESP32 pin checking macro contraints error HOT 1
- esp32 arduino release "2.0.15" does not show up in boards manager both in 1.8.x and 2.x HOT 5
- WiFi.macAddress(uint8_t mac) doesn't work anymore to retrieve mac, it returns 00:00:00:00:00:00 - Network.macAddress does perform as expected. HOT 9
- S3 Mini - After upgrade from 2.0.15 to 3.0.0rc1 "Compilation error: 'ledcSetup' was not declared in this scope" HOT 2
- Failed to allocate RSA interrupt 261 HOT 1
- Getting core dump in with 2.0.15 ESP32-D0WD-V3 HOT 8
- tflite-micro is breaking complex.h HOT 15
- AsyncTCP crash after 1-2 days HOT 2
- HTTPUpdate stuck at 9% or 10%. HOT 10
- V2.0.15 USB OTG Serial.println() works WITHOUT a Serial.begin() HOT 3
- LittleFS directory wrong date 1970
- libraries/BluetoothSerial - getRSSI
- Arduino ESP32 core consumes more and more RAM with every version... HOT 1
- ESP32 C3 Supermini only boots when USB is connected and Serial is used. HOT 3
- printf format warnings (-Wformat) regarding type definition change from Arduino 2 to Arduino 3 for uint32_t and int32_t HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from arduino-esp32.