Open hientv1999 opened 3 years ago
From your description i am suggesting to use nimble. It wont solve that issue, but will help you with future problems related to heap shortage.
From your description i am suggesting to use nimble. It wont solve that issue, but will help you with future problems related to heap shortage.
Thank you for your great recommendation. I never heard about NimBLE before but I just read it and it should be an amazing alternative for traditional BLE.
I tried NimBLE but the issue still exists and it even causes a new issue. The serviceUUIDs of other server ESP32 are not shown by the client ESP32.
Below is the code I changed into NimBLE way.
unsigned int DeviceOrder = 1;
#define ORDER "1"
#include <NimBLEDevice.h>
#include "esp_bt_main.h"
#include "esp_bt_device.h"
BLECharacteristic *pCharacteristic2;
#define SERVICE_UUID "b596e525-c3c6-45b3-a8bb-b8cddcc62a61"
static NimBLEUUID serviceUUID("b596e525-c3c6-45b3-a8bb-b8cddcc62a61");
#define CHARACTERISTIC_UUID "f364c9cb-2d2c-4eb6-92d3-28db399a09ee"
class MyAdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks
{
void onResult(NimBLEAdvertisedDevice advertisedDevice){}
};
class MyClientCallback : public NimBLEClientCallbacks {
void onConnect(NimBLEClient* pclient) {}
void onDisconnect(NimBLEClient* pclient) {
pclient->disconnect();
}
};
int ConnectToESP32(NimBLEAdvertisedDevice device){
BLEClient* pClient = NimBLEDevice::createClient();
Serial.println(" - Created client");
// Connect to the remove BLE Server.
pClient->connect(&device); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
// Obtain a reference to the service we are after in the remote BLE server.
if (pClient->getService(SERVICE_UUID) == nullptr) {
pClient->disconnect();
return 0;
}
Serial.println(" - Found our service");
NimBLERemoteService* pRemoteService = pClient->getService(SERVICE_UUID);
// Obtain a reference to the characteristic in the service of the remote BLE server.
NimBLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID);
if (pRemoteCharacteristic == nullptr) {
pClient->disconnect();
return 0;
}
Serial.println(" - Found our characteristic");
// 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());
return atoi(value.c_str());
pClient->connect(&device);
}
return 0;
}
long long int scanTimer;
const int CUTOFF = -74;
void setup()
{
Serial.begin(115200);
NimBLEDevice::init("MyESP"); //initialzie the local BLE environment as COVID_Alert_Device client device
NimBLEServer *pServer = NimBLEDevice::createServer(); //create server
NimBLEService *pService = pServer->createService(SERVICE_UUID);
NimBLECharacteristic *Sending_Characteristic = pService->createCharacteristic( //characteristic for sending data
CHARACTERISTIC_UUID,
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE
);
Sending_Characteristic ->setValue(ORDER);
pService->start();
pServer->getAdvertising()->start();
NimBLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
NimBLEDevice::startAdvertising();
scanTimer = millis();
}
void loop(){
if (scanTimer + 5000 < millis()){
BLEScan* pBLEScan = NimBLEDevice::getScan(); //create new scan
BLEScanResults scanResults = pBLEScan->start(3, false); //scan for 3 seconds, not continuous
Serial.print("Number of devices found this loop:");
Serial.println(scanResults.getCount());
Serial.println("List of devices found: ");
for (int i=0 ; i < scanResults.getCount(); i++){ //check each new BluetoothID found
BLEAdvertisedDevice device = scanResults.getDevice(i);
Serial.println(device.toString().c_str());
if (device.getRSSI() > CUTOFF && device.haveServiceUUID () && device.getServiceUUID().equals(serviceUUID)){ //check the Bluetooth signal is strong enough and have correct ServiceUUID
unsigned int ToDevice = ConnectToESP32(device);
if (ToDevice != 0){
}
}
}
NimBLEDevice::getScan()->clearResults();
scanTimer = millis();
}
}
And here is the output:
List of devices found:
Name: , Address: 65:c2:ae:c8:2f:08, manufacturer data: 4c000c0e00d43ee5e4e9693ac51ac17ae4da, txPower: 12
Name: , Address: 1a:1f:08:5e:bb:a7, manufacturer data: 06000109200220d68373afcb336ccabcc8c9d056214c53e5ed973245a1
Name: , Address: 24:93:0d:4c:2f:4a, manufacturer data: 060001092002c97d4abd0b1be7882721186b459fa7a1c7a5cbe3c974e2
Name: , Address: 40:cc:ba:63:87:a8, manufacturer data: 4c001005381c8be8bd, txPower: 7
Name: MyESP, Address: 24:0a:c4:61:35:8a
Name: , Address: 58:51:e0:ff:15:48, manufacturer data: 4c001006471d1f9cfe08, txPower: 12
Name: , Address: 41:6c:fb:7f:ed:3b, manufacturer data: 4c001005481c344d27, txPower: 12
Name: , Address: 03:99:bf:f4:3c:36, manufacturer data: 4c0005120000000000000000013de44f1d655ac9de00
Name: , Address: 23:e2:da:20:c9:49, serviceUUID: 0xfd6f
Service Data:
UUID: 0xfd6f, Data: x^⸮⸮2T⸮0
$
Name: , Address: 4d:03:d1:ee:9a:c4, manufacturer data: 4c0010055118263eb7, txPower: 12
Number of devices found this loop:10
Did I miss anything here or did I make any mistake here?
I'm not sure if this is a dumb question but for example, if I develop my program in a way that it will have several switch cases and some of them do not want to use BLE at all, and if I implement the callback function in a switch case for scanning, does it interrupt the program whenever an advertiser is found? Since there should be some points in the program I don't want either the callback or BLE work to be invoked.
I have changed the program into the callback way but only the txPower appears, the serviceUUID still disappears.
Here is my program:
unsigned int DeviceOrder = 1;
#define ORDER "1"
#include <NimBLEDevice.h>
#include "esp_bt_main.h"
#include "esp_bt_device.h"
BLECharacteristic *pCharacteristic2;
#define SERVICE_UUID "b596e525-c3c6-45b3-a8bb-b8cddcc62a61"
static NimBLEUUID serviceUUID("b596e525-c3c6-45b3-a8bb-b8cddcc62a61");
#define CHARACTERISTIC_UUID "f364c9cb-2d2c-4eb6-92d3-28db399a09ee"
int ConnectToESP32(NimBLEAdvertisedDevice device){
BLEClient* pClient = NimBLEDevice::createClient();
Serial.println(" - Created client");
// Connect to the remove BLE Server.
pClient->connect(&device); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
// Obtain a reference to the service we are after in the remote BLE server.
if (pClient->getService(SERVICE_UUID) == nullptr) {
pClient->disconnect();
return 0;
}
Serial.println(" - Found our service");
NimBLERemoteService* pRemoteService = pClient->getService(SERVICE_UUID);
// Obtain a reference to the characteristic in the service of the remote BLE server.
NimBLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID);
if (pRemoteCharacteristic == nullptr) {
pClient->disconnect();
return 0;
}
Serial.println(" - Found our characteristic");
// 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());
return atoi(value.c_str());
pClient->connect(&device);
}
return 0;
}
long long int scanTimer;
const int CUTOFF = -74;
/** Define a class to handle the callbacks when advertisments are received */
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
Serial.print("Advertised Device found: ");
Serial.println(advertisedDevice->toString().c_str());
if (advertisedDevice->haveServiceUUID() && advertisedDevice->getServiceUUID().equals(serviceUUID)){
unsigned int ToDevice = ConnectToESP32(*advertisedDevice);
Serial.print("I got the characteristic value: ");
Serial.println(ToDevice);
}
};
};
/** Callback to process the results of the last scan or restart it */
void scanEndedCB(NimBLEScanResults results){
Serial.println("Scan Ended");
}
void setup()
{
Serial.begin(115200);
NimBLEDevice::init("MyESP"); //initialzie the local BLE environment as COVID_Alert_Device client device
NimBLEServer *pServer = NimBLEDevice::createServer(); //create server
NimBLEService *pService = pServer->createService(SERVICE_UUID);
NimBLECharacteristic *Sending_Characteristic = pService->createCharacteristic( //characteristic for sending data
CHARACTERISTIC_UUID,
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE
);
Sending_Characteristic ->setValue(ORDER);
pService->start();
pServer->getAdvertising()->start();
NimBLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
NimBLEDevice::startAdvertising();
scanTimer = millis();
}
void loop(){
if (scanTimer + 5000 < millis()){
/** create new scan */
NimBLEScan* pScan = NimBLEDevice::getScan();
/** create a callback that gets called when advertisers are found */
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
/** Set scan interval (how often) and window (how long) in milliseconds */
pScan->setInterval(45);
pScan->setWindow(15);
/** Active scan will gather scan response data from advertisers
* but will use more energy from both devices
*/
pScan->setActiveScan(true);
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever
* Optional callback for when scanning stops.
*/
pScan->start(3, scanEndedCB);
scanTimer = millis();
}
}
and here is the output of Serial Monitor:
Advertised Device found: Name: MyESP, Address: 24:0a:c4:61:35:8a, txPower: 3
Advertised Device found: Name: , Address: 19:4b:e1:01:dc:ab, manufacturer data: 0600010920021d14837e67876156c9700bd826284fac33b6d455e261c4
Advertised Device found: Name: , Address: 6a:2a:ee:7f:be:4c, manufacturer data: 4c0010053e1c09ecd7, txPower: 7
Advertised Device found: Name: , Address: 16:f3:09:e5:9e:f1, serviceUUID: 0xfd6f
Service Data:
UUID: 0xfd6f, Data: Uc J
⸮⸮*⸮R⸮⸮
⸮⸮⸮_⸮?
Scan Ended
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
you didnt set second parameter to true (wants duplicates), which by default is false.
My plan is to make a bunch of esp32 with the almost same code that both advertises and scans for each other. However, each device will have a different characteristic value to specify each device. Below is the code of my main.ino
Here is the output on Serial Monitor:
I have tested them more than 20 times and the longest it can hold is 3 scans. Sometimes, it can only do 1 or 2 scans. It will never find the device again until I reboot the device it cannot find. I suspect it could be the esp32 saves the paired devices and ignore it after a few cycles. Is there any way I can overcome this issue. There will be at least 100 esp32 working in my configuration. I just tested it with 2 esp32 already. *I have changed the waiting time for client to connect to server down to 3 seconds (the default setting is 40-50 days I believe)