Board: ESP32 Dev Module
Core Installation/update date: 22/dec/2017
IDE name: Platform.io Arduino framework
Flash Frequency: 40Mhz
Upload Speed: 115200
Using @nkolban BLE server example, I created successful a BLE server that I can connect to from my Android tablet as a client (with nRF connect) and receive data from the ESP32.
But if I try connect a second client, this second client cannot connect.
The error message on the client is _Error 133 (0x85) GATT ERROR_.
I set _-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG_ before building the ESP32 code. In the log I can see the first client connecting and receiving data and notifications. But the log doesn't show anything about a second client trying to connect.
From what I read about BLE, it should be possible to connect several clients to one server. Or did I misunderstand something or miss something in my code?
Sketch below includes the callbacks for server and characteristics. BLE is initialized at the end of setup() by a call to initBLE().
#include "setup.h"
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
// List of Service and Characteristic UUIDs
#define SERVICE_UUID 0x181A
#define NOTIFICATION_UUID 0x2A08
#define TEMP_UUID 0x2A1F
#define HUMID_UUID 0x2A6F
#define STATUS_UUID 0x2A3D
/** Characteristic for client notification */
BLECharacteristic *pCharacteristicNotify;
/** Characteristic for temperature in celsius */
BLECharacteristic *pCharacteristicTemp;
/** Characteristic for humidity in percent */
BLECharacteristic *pCharacteristicHumid;
/** Characteristic for environment status */
BLECharacteristic *pCharacteristicStatus;
/** BLE Advertiser */
BLEAdvertising* pAdvertising;
/** BLE Service */
BLEService *pService;
/** BLE Server */
BLEServer *pServer;
/** Flag if a client is connected */
bool bleConnected = false;
/** Last temperature reading */
float bleTemperature;
/** Last humidity reading */
float bleHumidity;
/** Last environment status */
String bleStatus;
/**
* MyServerCallbacks
* Callbacks for client connection and disconnection
*/
class MyServerCallbacks: public BLEServerCallbacks {
// TODO this doesn't take into account several clients being connected
void onConnect(BLEServer* pServer) {
bleConnected = true;
addMqttMsg("debug", "[INFO] " + digitalTimeDisplaySec() + " BLE connected", false);
};
void onDisconnect(BLEServer* pServer) {
bleConnected = false;
addMqttMsg("debug", "[INFO] " + digitalTimeDisplaySec() + " BLE disconnected", false);
}
};
/**
* MyCallbackHandler
* Callbacks for characteristic read and write events
*/
class MyCallbackHandler: public BLECharacteristicCallbacks {
void onRead(BLECharacteristic* pCharacteristic) {
// addMqttMsg("debug", " " + digitalTimeDisplaySec() + " BLE read request", false);
// addMqttMsg("debug", " " + digitalTimeDisplaySec() + " BLE sending: " + bleNewData, false);
if (pCharacteristic == pCharacteristicNotify) {
uint8_t notifData[8];
time_t now;
struct tm timeinfo;
time(&now); // get time (as epoch)
localtime_r(&now, &timeinfo); // update tm struct with current time
uint16_t year = timeinfo.tm_year+1900;
notifData[1] = year>>8;
notifData[0] = year;
notifData[2] = timeinfo.tm_mon+1;
notifData[3] = timeinfo.tm_mday;
notifData[4] = timeinfo.tm_hour;
notifData[5] = timeinfo.tm_min;
notifData[6] = timeinfo.tm_sec;
pCharacteristic->setValue(notifData, 8);
} else if (pCharacteristic == pCharacteristicTemp) {
uint8_t tempData[2];
uint16_t bleTemp100 = (uint16_t)(bleTemperature*10);
tempData[1] = bleTemp100>>8;
tempData[0] = bleTemp100;
pCharacteristic->setValue(tempData, 2);
} else if (pCharacteristic == pCharacteristicHumid) {
uint8_t humidData[2];
uint16_t bleHumid100 = (uint16_t)(bleHumidity*100);
humidData[1] = bleHumid100>>8;
humidData[0] = bleHumid100;
pCharacteristic->setValue(humidData, 2);
} else if (pCharacteristic == pCharacteristicStatus) {
size_t dataLen = bleStatus.length();
uint8_t bleData[dataLen+1];
bleStatus.toCharArray((char *)bleData,dataLen+1);
pCharacteristic->setValue(bleData, dataLen);
// pCharacteristic->setValue((uint8_t*)&bleStatus, dataLen);
}
}
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
int len = value.length();
String strValue = "";
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++) {
Serial.print(value[i]);
strValue += value[i];
}
Serial.println();
Serial.println("*********");
addMqttMsg("debug", "[INFO] " + digitalTimeDisplaySec() + " BLE received: " + strValue, false);
}
}
};
/**
* initBLE
* Setup BLE
* Setup callbacks for server and pCharacteristicStatus
* Start advertising the BLE service
*/
void initBLE() {
addMqttMsg("debug", "[INFO] " + digitalTimeDisplaySec() + " BLE initBLE()", false);
// Initialize BLE
BLEDevice::init(apName);
BLEDevice::setPower(ESP_PWR_LVL_P7);
// Create BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create BLE Service
pService = pServer->createService(BLEUUID((uint16_t)SERVICE_UUID));
// Create BLE Characteristic for Alert
pCharacteristicNotify = pService->createCharacteristic(
BLEUUID((uint16_t)NOTIFICATION_UUID),
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY
);
// Create a BLE Descriptor for Alert
pCharacteristicNotify->addDescriptor(new BLE2902());
// Create BLE Characteristic for Temperature
pCharacteristicTemp = pService->createCharacteristic(
BLEUUID((uint16_t)TEMP_UUID),
BLECharacteristic::PROPERTY_READ
);
// Create BLE Characteristic for Humidity
pCharacteristicHumid = pService->createCharacteristic(
BLEUUID((uint16_t)HUMID_UUID),
BLECharacteristic::PROPERTY_READ
);
// Create BLE Characteristic for Status
pCharacteristicStatus = pService->createCharacteristic(
BLEUUID((uint16_t)STATUS_UUID),
BLECharacteristic::PROPERTY_READ
);
// Start the service
pService->start();
// Start advertising
pAdvertising = pServer->getAdvertising();
pAdvertising->start();
// Setup callback handler
pCharacteristicNotify->setCallbacks(new MyCallbackHandler());
pCharacteristicTemp->setCallbacks(new MyCallbackHandler());
pCharacteristicHumid->setCallbacks(new MyCallbackHandler());
pCharacteristicStatus->setCallbacks(new MyCallbackHandler());
addMqttMsg("debug", "[INFO] " + digitalTimeDisplaySec() + " BLE active now", false);
}
/**
* bleStop
* Stop advertising the BLE service
*/
void bleStop() {
pAdvertising->stop();
}
Log from first client connecting:
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONNECT_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONNECT_EVT
[D][BLEUtils.cpp:1671] dumpGattServerEvent(): [conn_id: 0, remote_bda: f8:00:3d:62:49:be]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONNECT_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
Log when client requests data from the different characteristics:
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_RESPONSE_EVT
[D][BLEUtils.cpp:1748] dumpGattServerEvent(): [status: ESP_GATT_OK, handle: 0x31]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_RESPONSE_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_READ_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_READ_EVT
[D][BLEUtils.cpp:1741] dumpGattServerEvent(): [conn_id: 0, trans_id: 17, bda: f8:00:3d:62:49:be, handle: 0x31, is_long: 1, need_rsp:1]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_READ_EVT
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x2a
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x2d
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x2f
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x31
[D][BLECharacteristic.cpp:629] setValue(): >> setValue: length=50, data=436f6d666f72743a20546f6f20486f742050657263657074696f6e3a20536f6d65686f7720756e636f6d666f727461626c65, characteristic UUID=00002a3d-0000-1000-8000-00805f9b34fb
[D][BLECharacteristic.cpp:636] setValue(): << setValue
[D][BLECharacteristic.cpp:352] handleGATTServerEvent(): Sending a response (esp_ble_gatts_send_response)
[D][BLECharacteristic.cpp:387] handleGATTServerEvent(): - Data: length=22, data=7074696f6e3a20536f6d65686f7720756e636f6d666f, offset=22
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_RESPONSE_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_RESPONSE_EVT
[D][BLEUtils.cpp:1748] dumpGattServerEvent(): [status: ESP_GATT_OK, handle: 0x31]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_RESPONSE_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_READ_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_READ_EVT
[D][BLEUtils.cpp:1741] dumpGattServerEvent(): [conn_id: 0, trans_id: 18, bda: f8:00:3d:62:49:be, handle: 0x31, is_long: 1, need_rsp:1]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_READ_EVT
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x2a
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x2d
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x2f
[D][BLECharacteristic.cpp:324] handleGATTServerEvent(): - Testing: 0x31 == 0x31
[D][BLECharacteristic.cpp:629] setValue(): >> setValue: length=50, data=436f6d666f72743a20546f6f20486f742050657263657074696f6e3a20536f6d65686f7720756e636f6d666f727461626c65, characteristic UUID=00002a3d-0000-1000-8000-00805f9b34fb
[D][BLECharacteristic.cpp:636] setValue(): << setValue
[D][BLECharacteristic.cpp:352] handleGATTServerEvent(): Sending a response (esp_ble_gatts_send_response)
[D][BLECharacteristic.cpp:387] handleGATTServerEvent(): - Data: length=6, data=727461626c65, offset=44
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_RESPONSE_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_RESPONSE_EVT
[D][BLEUtils.cpp:1748] dumpGattServerEvent(): [status: ESP_GATT_OK, handle: 0x31]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_RESPONSE_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
No output on log when second client tries to connect.
Excellent report ... many thanks for taking the time to put this together so clearly. Am now starting to study the story to see if we can figure out what is going wrong.
I did some study and am finding conflicting answers to whether a single BLE Server (peripheral) can serve multiple BLE Clients (centrals) concurrently. Ive posted a question to the ESP32 to see if that chases out any answers/concepts. For more details, see:
I found out that after the first client connected to the ESP32 BLE server, the BLE server stopped advertising.
My workaround to this is to restart advertising in the BLEServerCallbacks _pAdvertising->start();_:
/**
* MyServerCallbacks
* Callbacks for client connection and disconnection
*/
class MyServerCallbacks: public BLEServerCallbacks {
// TODO this doesn't take into account several clients being connected
void onConnect(BLEServer* pServer) {
bleConnected = true;
pAdvertising->start();
};
void onDisconnect(BLEServer* pServer) {
bleConnected = false;
}
};
After that I was able to connect two BLE clients (both Android devices running nRF Connect).
Both clients can read the characteristics after being connected.
Still having problems:
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONNECT_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONNECT_EVT
[D][BLEUtils.cpp:1671] dumpGattServerEvent(): [conn_id: 0, remote_bda: 43:b2:46:e0:52:c6]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONNECT_EVT
[D][BLEAdvertising.cpp:86] start(): >> start
[D][BLEAdvertising.cpp:105] start(): - no services advertised
[D][BLEAdvertising.cpp:137] start(): << start
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEUtils.cpp:1067] dumpGapEvent(): Received a GAP event: ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
[D][BLEUtils.cpp:1075] dumpGapEvent(): [status: 0]
[D][BLEServer.cpp:134] handleGAPEvent(): BLEServer ... handling GAP event!
[D][BLEUtils.cpp:1067] dumpGapEvent(): Received a GAP event: ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT
[D][BLEUtils.cpp:1261] dumpGapEvent(): [status: 0]
[D][BLEServer.cpp:134] handleGAPEvent(): BLEServer ... handling GAP event!
[D][BLEUtils.cpp:1067] dumpGapEvent(): Received a GAP event: ESP_GAP_BLE_ADV_START_COMPLETE_EVT
[D][BLEUtils.cpp:1099] dumpGapEvent(): [status: 0]
[D][BLEServer.cpp:134] handleGAPEvent(): BLEServer ... handling GAP event!
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONNECT_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONNECT_EVT
[D][BLEUtils.cpp:1671] dumpGattServerEvent(): [conn_id: 1, remote_bda: f8:00:3d:62:49:be]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONNECT_EVT
[D][BLEAdvertising.cpp:86] start(): >> start
[D][BLEAdvertising.cpp:105] start(): - no services advertised
[D][BLEAdvertising.cpp:137] start(): << start
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEUtils.cpp:1067] dumpGapEvent(): Received a GAP event: ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
[D][BLEUtils.cpp:1075] dumpGapEvent(): [status: 0]
[D][BLEServer.cpp:134] handleGAPEvent(): BLEServer ... handling GAP event!
[D][BLEUtils.cpp:1067] dumpGapEvent(): Received a GAP event: ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT
[D][BLEUtils.cpp:1261] dumpGapEvent(): [status: 0]
[D][BLEServer.cpp:134] handleGAPEvent(): BLEServer ... handling GAP event!
[D][BLEUtils.cpp:1067] dumpGapEvent(): Received a GAP event: ESP_GAP_BLE_ADV_START_COMPLETE_EVT
[D][BLEUtils.cpp:1099] dumpGapEvent(): [status: 0]
[D][BLEServer.cpp:134] handleGAPEvent(): BLEServer ... handling GAP event!
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONF_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONF_EVT
[D][BLEUtils.cpp:1656] dumpGattServerEvent(): [status: ESP_GATT_OK, conn_id: 0x00]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONF_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONF_EVT
[D][BLEUtils.cpp:1656] dumpGattServerEvent(): [status: ESP_GATT_OK, conn_id: 0x01]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLECharacteristic.cpp:629] setValue(): >> setValue: length=8, data=e1070c170b01303f, characteristic UUID=00002a08-0000-1000-8000-00805f9b34fb
[D][BLECharacteristic.cpp:636] setValue(): << setValue
[D][BLECharacteristic.cpp:490] notify(): >> notify: length: 8
[D][BLECharacteristic.cpp:531] notify(): << notify
[D][BLEDevice.cpp:80] gattServerEventHandler(): gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONF_EVT
[D][BLEUtils.cpp:1611] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONF_EVT
[D][BLEUtils.cpp:1656] dumpGattServerEvent(): [status: ESP_GATT_OK, conn_id: 0x01]
[D][BLEServer.cpp:175] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
[D][BLEServer.cpp:287] handleGATTServerEvent(): << handleGATTServerEvent
[D][BLECharacteristic.cpp:629] setValue(): >> setValue: length=8, data=e1070c170b06083f, characteristic UUID=00002a08-0000-1000-8000-00805f9b34fb
[D][BLECharacteristic.cpp:636] setValue(): << setValue
[D][BLECharacteristic.cpp:490] notify(): >> notify: length: 8
[D][BLECharacteristic.cpp:509] notify(): << notifications disabled; ignoring
Then I was looking into BLECharacteristics::notify(). I think what is needed is that the descriptor needs to be aware if several clients are attached and which clients have subscribed to notifications. Because this code returns only the notification status of the last client connected:
// Test to see if we have a 0x2902 descriptor. If we do, then check to see if notification is enabled
// and, if not, prevent the notification.
BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902);
if (p2902 != nullptr && !p2902->getNotifications()) {
ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring");
return;
}
and here (I guess) it should be a loop that sends the notifications to all clients that have subscribed???:
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
getService()->getServer()->getGattsIf(),
getService()->getServer()->getConnId(),
getHandle(), length, (uint8_t*)m_value.getValue().data(), false); // The need_confirm = false makes this a notify.
if (errRc != ESP_OK) {
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
return;
}
I made a very dirty quick patch in BLECharacteristics, BLEDescriptor and BLE2902 to support multiple clients notify subscriptions and it works. My patch limits the number of client subscriptions to 10 and I think it is unfortunately not good enough for release.
But it is at least a proof that multiple clients can be connect and multiple clients can subscribe to notify or indicate.
I created a gist with all the changes I made.
Hi, can you elaborate what changes have you made?
@chegewara check the gist
BLE2902.cpp
Check lines 23, 24, 25, 34, 35, 43, 44, 52, 53, 55, 57, 66, 67, 69, 71
BLE2902.h
Check lines 30 to 33
BLECharacteristic.cpp
Check functions * void BLECharacteristic::indicate() and * void BLECharacteristic::notify()
BLEDescriptor.cpp
Check lines 37, 43 and 44
ble_server_example.cpp
is an example how to restart the advertising after a client has connected, see class MyServerCallbacks: public BLEServerCallbacks line 54
However @nkolban did some research (and I was searching as well) and it seems that by definition BLE supports only one client connection on a server. Still not 100% confirmed though.
And another thing I found while testing my multi client connections (2 Android phones) to one server (ESP32). If you have characteristics (on the server) which have values longer than 22 bytes (max length for transmission), these values are send from the server to the client in several transmissions. In the case where 2 clients tried to read such a characteristic at the same time I experienced that the transmitted values got mixed up. E.g. one of my characteristics value a string that can be up to 50 bytes long, e.g. "_Perception: Somehow uncomfortable_". When two clients try to read this characteristic value at the same time I saw that one client received "_Perception: Soable_" while the other one received "_Perception: Somehow uncomfortmehow uncomfortable_". So if multiple client connections are possible, there is more stuff to be changed in BLECharacteristic.cpp void BLECharacteristic::handleGATTServerEvent() case ESP_GATTS_READ_EVT: to handle these parallel read requests of long values. But it works fine for values that are shorter than 22 bytes.
What I did not try is what happens if a server characteristic has a value that a client can write to. Not sure how to handle if 2 clients write different values to such a characteristic.
I will do some more research when i end with current project, which is HID over gatt. In mean time i will lok at your changes in code. Thanks for comprehensive description.
This is not compatible anymore with latest BLE library cannot compile anymore with below errors
BLE2902.cpp:20:36: error: no matching function for call to 'BLE2902::setValue(uint8_t, int, int&)' setValue((uint8_t)data, 2, index);
In BLEDescriptor there is no function setValue() with 3 parameters. Closest one that match is:
https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEDescriptor.cpp#L286
I am trying to calculate the throughput of ESP32 BLE in star connection. I was able to connect more than one client to a serer. To calculate throughput i am simultaneously sending characters from one client to another through server, and calculating the time difference between the arrival time of two characters. The problem that i am facing is that readValue() function in client side is not able to read characters fast enough. It is producing some delay before it receives second character. Due to this i am not getting correct receiving time.
So i tried using notify(). I am receiving the characters right after one another ans is thus able to calculate the correct time . This gives me a correct throughput. But the problem is i am able to notify only one client (the latest one which was connected to network). How can i notify two different clients using same server? I tried the instructions given above but it is giving me compling error in setValue() function as stated above.
Can anyone please help me?
Hi @sizen801
i just did some library modifications to allow connect multiple clients to one esp32 wrover server. Because i am working now on many enhancements and bugfixes i didnt create PR yet. It seems to works. My test:
If you are interested i can post required code on gist and you will change files in library to perform tests.
Receive write request:
I (3799749) BT_GATT: GATT_GetConnectionInfor conn_id=259
D (3799749) BLEDevice: gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_WRITE_EVT
D (3799752) BLEUtils: GATT ServerEvent: ESP_GATTS_WRITE_EVT
D (3799757) BLEUtils: [conn_id: 1, trans_id: 1, bda: 78:1f:db:c0:c7:f3, handle: 0x2a, offset: 0, need_rsp: 1, is_prep: 0, len: 1]
D (3799770) BLEUtils: [Data: 44]
D (3799773) BLEServer: >> handleGATTServerEvent: ESP_GATTS_WRITE_EVT
D (3799779) BLECharacteristic: >> handleGATTServerEvent: ESP_GATTS_WRITE_EVT
D (3799786) BLECharacteristic: >> setValue: length=1, data=44, characteristic UUID=beb5483e-36e1-4688-b7f5-ea07361b26a8
D (3799797) BLECharacteristic: << setValue
D (3799801) BLECharacteristic: - Response to write event: New value: handle: 2a, uuid: beb5483e-36e1-4688-b7f5-ea07361b26a8
D (3799812) BLECharacteristic: - Data: length: 1, data: 44
I (3799818) SampleServer: write to char:
Send notification to every client:
D (3799823) BLECharacteristic: >> notify: length: 1
D (3799823) BLECharacteristic: << handleGATTServerEvent
D (3799833) BLEServer: << handleGATTServerEvent
I (3799838) BT_GATT: GATTS_SendRsp: conn_id: 259 trans_id: 1 Status: 0x0000
D (3799847) BLEDevice: gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_RESPONSE_EVT
D (3799854) BLEUtils: GATT ServerEvent: ESP_GATTS_RESPONSE_EVT
D (3799860) BLEUtils: [status: ESP_GATT_OK, handle: 0x2a]
D (3799865) BLEServer: >> handleGATTServerEvent: ESP_GATTS_RESPONSE_EVT
D (3799872) BLECharacteristic: >> handleGATTServerEvent: ESP_GATTS_RESPONSE_EVT
D (3799879) BLECharacteristic: << handleGATTServerEvent
D (3799884) BLEServer: << handleGATTServerEvent
I (3799889) BT_GATT: GATT_GetConnectionInfor conn_id=3
I (3799895) BT_GATT: GATTS_HandleValueNotification
D (3799901) BLEDevice: gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONF_EVT
D (3799908) BLEUtils: GATT ServerEvent: ESP_GATTS_CONF_EVT
D (3799914) BLEUtils: [status: ESP_GATT_OK, conn_id: 0x00]
D (3799919) BLEServer: >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
D (3799926) BLECharacteristic: >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
D (3799933) BLECharacteristic: << handleGATTServerEvent
D (3799938) BLEServer: << handleGATTServerEvent
I (3799943) BT_GATT: GATT_GetConnectionInfor conn_id=259
I (3799949) BT_GATT: GATTS_HandleValueNotification
D (3799955) BLEDevice: gattServerEventHandler [esp_gatt_if: 3] ... ESP_GATTS_CONF_EVT
D (3799962) BLEUtils: GATT ServerEvent: ESP_GATTS_CONF_EVT
D (3799968) BLEUtils: [status: ESP_GATT_OK, conn_id: 0x01]
D (3799973) BLEServer: >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
D (3799980) BLECharacteristic: >> handleGATTServerEvent: ESP_GATTS_CONF_EVT
D (3799987) BLECharacteristic: << handleGATTServerEvent
D (3799987) BLECharacteristic: << notify
D (3799992) BLEServer: << handleGATTServerEvent
Hi @chegewara
Yes i would like to see your code. I don't need to send characters to two different clients at a same time. So i think this will work for me. Can you please post the required code in gist?
Thank you so much for your help.
I am preparing git repo with enhancements. It will be with client and server example. I can send notifications to multiple clients with high rate (every 50 ms or faster).
Thanks chegewara :)
Thank you Chegewara. I will try to implement the code provided by you and will let you know about my findings.
I am testing it with 2 and 3 client devices for about 9 hours now. Still working:
I (32107453) SampleClient: 8--> 7400
E (32107481) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 32107.420674 length 34
E (32107486) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 32106.592524 length 33
I (32107506) SampleClient: 8--> 7400
E (32107525) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 32106.112571 length 34
E (32107540) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 32107.473723 length 34
I (32107559) SampleClient: 8--> 7400
E (32107586) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 32107.526673 length 34
E (32107591) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 32106.172005 length 34
EDIT 3 clients is send write request every 50 ms each and server is sending back this message with notification to every connected client.
E (37158522) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 1986.656204 length 33
E (37158528) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com 11: 613.810461 length 34
E (37158542) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 37158.418603 length 34
I (37158561) SampleClient: 8--> 7392
E (37158565) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com 11: 613.863372 length 34
E (37158596) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 1986.7143572 length 33
I (37158613) SampleClient: 8--> 7392
E (37158625) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 37158.504139 length 34
E (37158657) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 1986.7673869 length 33
E (37158661) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com 11: 613.925312 length 34
I (37158665) SampleClient: 8--> 7392
E (37158676) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 37158.556139 length 34
E (37158700) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 1986.827338 length 33
E (37158731) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com 11: 614.33708 length 32
I (37158746) SampleClient: 8--> 7392
E (37158762) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 37158.622899 length 34
E (37158767) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com9: 1986.8873439 length 33
E (37158781) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com 11: 614.563609 length 33
E (37158795) SampleClient: Notify callback for characteristic beb5483e-36e1-4688-b7f5-ea07361b26a8 of data Time since boot com3: 37158.689144 length 34
Hey @chegewara ,
I am getting compile error.
Arduino: 1.8.5 (Windows 10), Board: "ESP32 Dev Module, Disabled, Default, QIO, 80MHz, 4MB (32Mb), 921600, None"
C:\Users\sizenn.HLI\Documents\Arduino\hardware\espressif\esp32\libraries\BLE\src\BLEUtils.cpp: In static member function 'static std::__cxx11::string BLEUtils::gattServerEventTypeToString(esp_gatts_cb_event_t)':
C:\Users\sizenn.HLI\Documents\Arduino\hardware\espressif\esp32\libraries\BLE\src\BLEUtils.cpp:1061:7: error: 'ESP_GATTS_SEND_SERVICE_CHANGE_EVT' was not declared in this scope
case ESP_GATTS_SEND_SERVICE_CHANGE_EVT:
^
exit status 1
Error compiling for board ESP32 Dev Module.
I used the .cpp and .h files inside your cpp_utils(). The original BLE library was giving me compiling error while trying to connect, since BLEServer class didn't have connect() function in it. I can mess with .cpp and .h files to try to fix this problem. But before doing that i want your suggestion in this problem?
Sorry, but i have not tested it against arduino yet.
Thanks for your help. Please let me know when you test with Arduino.
Thanks,
Sizen
On Tue, Oct 9, 2018 at 11:06 PM chegewara notifications@github.com wrote:
Sorry, but i have not tested it against arduino yet.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/nkolban/esp32-snippets/issues/307#issuecomment-428422553,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AYlgcTOxgsVyPtCCoDTvoXCTmph2schdks5ujWQsgaJpZM4RK9h2
.
Its implemented in https://github.com/nkolban/esp32-snippets/tree/features, but still have no time to test it with arduino.
Hello Is this supported with latest esp32 for Arduino
Yes.
Thanks I see no example for Multiple clients
I am looking for the exact same thing, could not find any changes in the library to support.
Can connect multiple devices after starting to advertise again but notifications will not work.
Thanks I see no example for Multiple clients
There is no "official" example i think.
I am looking for the exact same thing, could not find any changes in the library to support.
Some time ago, when i added multiple connection functionality, bot client and server, i tested and it worked fine.
Maybe i missed some bug or few in my tests, but IIRC notifications worked.
EDIT in case something is not working logs would help
Hi Chegewara, thanks for your support!
What kind of logs would you like me to provide?
I am using a basic example with a write callback.
It is switching a relay on and off for a personal project.
`// Relay Callback
class RelayCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *customCharacteristic) {
std::string rcvString = customCharacteristic->getValue();
if (rcvString.length() > 0) {
for (int i = 0; i < rcvString.length(); ++i)
{
value[i] = rcvString[i];
}
for (int i = rcvString.length(); i < 50; ++i)
{
value[i] = NULL;
}
int checkrelayno;
checkrelayno = checkRelay((char*)customCharacteristic->getUUID().toString().c_str());
// Check if the value changed
if (memcmp(relays[checkrelayno][4], value, 50) != 0) {
Serial.print("Value Received for BLEUUID: ");
Serial.println(customCharacteristic->getUUID().toString().c_str());
Serial.print("We have new value: ");
Serial.println(value);
strcpy(relays[checkrelayno][4], value);
SwitchRelay(value, relays[0][3]);
}
else {
Serial.print("Value Received for BLEUUID: ");
Serial.println(customCharacteristic->getUUID().toString().c_str());
Serial.println("Stayed the same");
}
// Set new value in BLE Characteristic
customCharacteristic->setValue((char*)&value);
}
else {
Serial.println("Empty Value Received!");
}
}
};
`
I am using the lightblue app to write to the esp32, everything works as intended.
Just did notice somethings strange when listening for notifications the device only recieved their own write actions but not the other ones. When I click read value it gives the correct one, so I am sure the connection is still live.
This is base code to start with and you can safely add your callbacks:
https://github.com/espressif/arduino-esp32/blob/master/libraries/BLE/examples/BLE_server_multiconnect/BLE_server_multiconnect.ino
Device cant receive its own notifications, never ever. Device can send notifications to connected peer devices, like smartphone with lightblue.
I dont see notifications code in snippets you pasted so its hard to say why its not working.
Thanks for putting me on the right path, it seems the app lightblue pushes it's own message back as a "notification" which threw me off. Added the notify to the callback and works like a charm.
thanks again.
Most helpful comment
Another Update
I made a very dirty quick patch in BLECharacteristics, BLEDescriptor and BLE2902 to support multiple clients notify subscriptions and it works. My patch limits the number of client subscriptions to 10 and I think it is unfortunately not good enough for release.
But it is at least a proof that multiple clients can be connect and multiple clients can subscribe to notify or indicate.
I created a gist with all the changes I made.