Sending Data from BLE SENSE Rev2 To ESP32

Hello everyone here I hope you are doing amazing.

I am developing a program where I can send the temperature readings from a BLE SENSE 33 REV2 to an ESP32. I have already successfully made the connection using the libraries: ArduinoBLE and ESP32 BLE Arduino. I am currently using a modified version of the battery monitor from the ArduinoBLE library which has allowed me to take the reading from the built-in sensor "HS300x" I've checked already with my phone and other devices and it is successfully sending the information so any terminal can nRF terminal can read.

I am also using the ESP32 client example to read the values from the BLE SENSE but even when I am having a good connection between the 2 devices, the results print look like this:

Notify callback for characteristic 00002a19-0000-1000-8000-00805f9b34fb of data length 1
data: ?��?

As I said before I am Using the Battery monitor example and I am also using the same UUIDs that probably do not allow to me get the readings. I am new to this topic and also this example is kind of new to me. I am happy I could make the connection between those 2 devices. I would highly appreciate any advice or example or explanation anything would be super welcome.

Here are my two sketches

/*
  Temperature Monitor

  This example creates a Bluetooth® Low Energy peripheral with the standard battery service and
  level characteristic. The A0 pin is used to calculate the battery level.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  You can use a generic Bluetooth® Low Energy central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#include <Arduino_HS300x.h>

 // Bluetooth® Low Energy Battery Service
BLEService temperatureService("180F");

// Bluetooth® Low Energy Battery Level Characteristic
BLEUnsignedCharCharacteristic temperatureLevelChar("2A19",  // standard 16-bit characteristic UUID
    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes

float old_temp = 0;
float old_hum = 0; 
  // last battery level reading from analog input
long previousMillis = 0; // last battery level reading from analog input
  // last time the battery level was checked, in ms

void setup() {
  Serial.begin(9600);    // initialize serial communication
  while (!Serial);

pinMode(LED_BUILTIN, OUTPUT);

   if (!HS300x.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }
  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  /* Set a local name for the Bluetooth® Low Energy device
     This name will appear in advertising packets
     and can be used by remote devices to identify this Bluetooth® Low Energy device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("TemperatureMonitor");
  BLE.setAdvertisedService(temperatureService); // add the service UUID
  temperatureService.addCharacteristic(temperatureLevelChar); // add the battery level characteristic
  BLE.addService(temperatureService); // Add the battery service
  temperatureLevelChar.writeValue(old_temp); // set initial value for this characteristic

  /* Start advertising Bluetooth® Low Energy.  It will start continuously transmitting Bluetooth® Low Energy
     advertising packets and will be visible to remote Bluetooth® Low Energy central devices
     until it receives a new connection */

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth® device active, waiting for connections...");
}

void loop() {
  // wait for a Bluetooth® Low Energy central
  BLEDevice central = BLE.central();

  // if a central is connected to the peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    // turn on the LED to indicate the connection:
    digitalWrite(LED_BUILTIN, HIGH);

    // check the battery level every 200ms
    // while the central is connected:
    while (central.connected()) {
     long currentMillis = millis();
    if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
      
        updatetemperatureLevel();
      }
    }
    // when the central disconnects, turn off the LED:
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

void updatetemperatureLevel() {
  /* Read the current voltage level on the A0 analog input pin.
     This is used here to simulate the charge level of a battery.
  */
  float temperature = HS300x.readTemperature();
  // print each of the sensor values
  Serial.print("Temperature = ");
  Serial.print(temperature);
  Serial.println(" °C");
  temperatureLevelChar.writeValue(temperature);  // and update the battery level characteristic
  old_temp = temperature;  
  delay(1000);
            
  
}

ESP32

/**
 * A BLE client example that is rich in capabilities.
 * There is a lot new capabilities implemented.
 * author unknown
 * updated by chegewara
 */

#include "BLEDevice.h"
//#include "BLEScan.h"

// The remote service we wish to connect to.
static BLEUUID serviceUUID("180F");
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("2A19");

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;

static void notifyCallback(
  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);
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // 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.println(" - Connected to server");

    // 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: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // 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(charUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    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());
    }

    if(pRemoteCharacteristic->canNotify())
      pRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
}
/**
 * Scan for BLE servers and find the first 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(serviceUUID)) {

      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks


void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  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.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
} // 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.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    String newValue = "Time since boot: " + String(millis()/1000);
    Serial.println("Setting new characteristic value to \"" + newValue + "\"");
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
  }else if(doScan){
    BLEDevice::getScan()->start(0);  // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
  }
  
  delay(5000); // Delay a second between loops.
} // End of loop

1 Like

I don't think pData is null terminated and in my notification callbacks I have always used

static void notifyCallback(
  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);
    for (int i = 0; i < length; i++) {
    Serial.print(pData[i]);
    Serial.print(" ");
  }
  Serial.println();
}
1 Like

Works perfectly thank u very much. Just my last question here, I wanna get decimal values in order to have an accurate measurement for temperature. The serial monitor of the BLE SENSE shows decimals but the readings from the ESP32 just show the integer. Is there any way I can read with the decimals as well? I am using the battery monitor UUIDs, Could that be one of the problems????

Notify callback for characteristic 00002a19-0000-1000-8000-00805f9b34fb of data length 1
data: 21

1 Like

The most simple way to change your program is to send a 2 decimal place float value as text.

The Nano33 BLE sending program need a different characteristic to send the character array

//BLEUnsignedCharCharacteristic temperatureLevelChar("2A19",  // standard 16-bit characteristic UUID
 //   BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLECharacteristic temperatureLevelChar("2A19",  
    BLERead | BLENotify, 7);  //limit of "xxx.xx" + null terminator

eliminate this line as it is not compatible with the new format

//temperatureLevelChar.writeValue(old_temp); // set initial value for this characteristic

Then use sprintf and a character array in your update.

void updatetemperatureLevel() {
  /* Read the current voltage level on the A0 analog input pin.
     This is used here to simulate the charge level of a battery.
  */
  float temperature = HS300x.readTemperature();
  // print each of the sensor values
  Serial.print("Temperature = ");
  Serial.print(temperature);
  Serial.println(" °C");
  static char temperatureCTemp[7]; //"xxx.xx" + null terminator
  sprintf(temperatureCTemp, "%.2f", temperature);//two places after dp
  temperatureLevelChar.writeValue(temperatureCTemp);  // and update the battery level characteristic
  old_temp = temperature;  
  delay(1000);  
}

For the ESP32 receiver, you can go back to the use pData and drop the single byte printing.

Serial.println((char*)pData);
  /*
  for (int i = 0; i < length; i++)
  {
    Serial.print(pData[i]);
    Serial.print(" ");
  }
  */
2 Likes

Man, you are more than amazing. It perfectly worked. Where did you learn all of this I am good with Arduino in general but I wanna know the more specific stuff like you.

Thank you again you are a lifesaver

Hello bro, can u send the final code about this topic, because i need reference about swnd data from nano 33 ble to eso32

1 Like

Hello bro, can u make a code about send data lsm9ds1 from nano 33 ble to esp32?

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.