I have two ESP32. I am trying to get two characteristics sent over bluetooth, but the 2nd one seems to be overwriting the first one on the client side.
ble app LightBlue shows the two different values. But if I use my client, it doesn't work. I tried printing the client's data's address, and the pointers seem to be pointing to the same character array.
I got help on this thread about character array not working on my server side. Before this fix and some other modifications, client side was getting data usually, but about 10% of the time the 1st characteristic got overwritten. Now it is overwritten all the time.
client code:
/*********
Rui Santos
Complete instructions at https://RandomNerdTutorials.com/esp32-ble-server-client/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
float myTime;
#include "BLEDevice.h"
//BLE Server name (the other ESP32 name running the server sketch)
#define bleServerName "Simple_ESP32"
/* UUID's of the service, characteristic that we want to read*/
// BLE Service
static BLEUUID dhtServiceUUID("5106ba9c-a085-4bea-b210-0272d8cd40dd");
// BLE Characteristics
//Temperature Celsius Characteristic
static BLEUUID temperatureCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");
// Humidity Characteristic
static BLEUUID humidityCharacteristicUUID("ca73b3ba-39f6-4ab3-91ae-186dc9577d99");
//Flags stating if should begin connecting and if the connection is up
static boolean doConnect = false;
static boolean connected = false;
//Address of the peripheral device. Address will be found during scanning...
static BLEAddress *pServerAddress;
//Characteristicd that we want to read
static BLERemoteCharacteristic* temperatureCharacteristic;
static BLERemoteCharacteristic* humidityCharacteristic;
//Activate notify
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};
//Variables to store temperature and humidity
char* temperatureChar;
char* humidityChar;
//Flags to check whether new temperature and humidity readings are available
boolean newTemperature = false;
boolean newHumidity = false;
//Connect to the BLE Server that has the name, Service, and Characteristics
bool connectToServer(BLEAddress pAddress) {
BLEClient* pClient = BLEDevice::createClient();
// Connect to the remove BLE Server.
pClient->connect(pAddress);
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(dhtServiceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(dhtServiceUUID.toString().c_str());
return (false);
}
// Obtain a reference to the characteristics in the service of the remote BLE server.
temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
humidityCharacteristic = pRemoteService->getCharacteristic(humidityCharacteristicUUID);
if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID");
return false;
}
Serial.println(" - Found our characteristics");
//Assign callback functions for the Characteristics
temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
humidityCharacteristic->registerForNotify(humidityNotifyCallback);
return true;
}
//Callback function that gets called, when another device's advertisement has been received
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
if (advertisedDevice.getName() == bleServerName) { //Check if the name of the advertiser matches
advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
pServerAddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
doConnect = true; //Set indicator, stating that we are ready to connect
Serial.println("Device found. Connecting!");
}
}
};
//When the BLE Server sends a new temperature reading with the notify property
static void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
//store temperature value
temperatureChar = (char*)pData;
Serial.print("temp notified:");Serial.println(temperatureChar);
newTemperature = true;
}
//When the BLE Server sends a new humidity reading with the notify property
static void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
//store humidity value
humidityChar = (char*)pData;
Serial.print("humidity notified:");Serial.println(humidityChar);
newHumidity = true;
}
//function that prints the latest sensor readings in the OLED display
void printReadings() {
myTime = float(millis());
Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
Serial.print("humidity_Server address:"); Serial.print((int)humidityChar); Serial.print(", ");
Serial.print("tempC_Server address:"); Serial.print((int)temperatureChar); Serial.print(", ");
Serial.println();
Serial.print("humidity_Server:"); Serial.print(humidityChar); Serial.print(", ");
Serial.print("tempC_Server:"); Serial.print(temperatureChar); Serial.print(", ");
Serial.println();
}
void setup() {
//Start serial communication
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
//Init BLE device
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 30 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(30);
}
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.
if (doConnect == true) {
if (connectToServer(*pServerAddress)) {
Serial.println("We are now connected to the BLE Server.");
//Activate the Notify property of each Characteristic
temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
humidityCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2903))->writeValue((uint8_t*)notificationOn, 2, true);
connected = true;
} else {
Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
}
doConnect = false;
}
//if new temperature readings are available, print in the OLED
if (newTemperature && newHumidity) {
// Reading temperature or humidity takes about 250 milliseconds!
Serial.print("time:"); Serial.print(myTime / 1000 / 60 / 60 / 24, 6); Serial.print(", ");
Serial.print("humidity_Client:"); Serial.print(88); Serial.print(", ");
Serial.print("tempC_Client:"); Serial.print(10); Serial.print(", ");
printReadings();
newTemperature = false;
newHumidity = false;
}
delay(1000); // Delay a second between loops.
}
server code:
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
Ported to Arduino ESP32 by Evandro Copercini
updates by chegewara
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define bleServerName "Simple_ESP32"
// Timer variables
long myTime;
unsigned long lastTime = 0;
unsigned long timerDelay = 6000;
bool deviceConnected = false;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "5106ba9c-a085-4bea-b210-0272d8cd40dd"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic tempCharacteristic("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor tempCharacteristicDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic humidityCharacteristic("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor humidityCharacteristicDescriptor(BLEUUID((uint16_t)0x2903));
//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void setup() {
BLEDevice::init(bleServerName);
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks()); //new
BLEService *pService = pServer->createService(SERVICE_UUID);
/*
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setValue("Hello World says Neil");
*/
pService->addCharacteristic(&tempCharacteristic);//new
tempCharacteristicDescriptor.setValue("temperature Celsius");
tempCharacteristic.addDescriptor(&tempCharacteristicDescriptor);
pService->addCharacteristic(&humidityCharacteristic);
humidityCharacteristicDescriptor.setValue("humidity");
humidityCharacteristic.addDescriptor(&humidityCharacteristicDescriptor);
//humidityCharacteristic.addDescriptor(new BLE2902());
pService->start();
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
}
void loop() {
myTime = float(millis());
if (deviceConnected) {
if ((millis() - lastTime) > timerDelay) {
int h = 99;
int t = 20;
static char temperatureCTemp[7];
dtostrf(t, 6, 2, temperatureCTemp);
tempCharacteristic.setValue(temperatureCTemp);
tempCharacteristic.notify();
delay(1000);
static char humidity[7];
dtostrf(h, 6, 2, humidity);
humidityCharacteristic.setValue(humidity);
humidityCharacteristic.notify();
lastTime = millis();
}
}
}