Passing a floating point number via BLE

I am just learning BLE and have modified a sketch in order to pass the temperature recorded by the Nano 33 BLE Sense over BLE as a floating point number. When I connect via my Android app "nRF Connect" the correct values appear in the serial monitor but in the app the values appear to be random values such as -323,71°C and 46.75°C and 223.5% and 26,43%. Here is the sketch:

#include <ArduinoBLE.h>
#include <Arduino_HTS221.h>
#include <Arduino_LSM9DS1.h>


BLEService sensorService("181A");
BLEFloatCharacteristic temperatureSensorLevel("2A6E", BLENotify );
BLEFloatCharacteristic humiditySensorLevel("2A6F", BLENotify );

float oldTemperature = 0;
float oldHumidity = 0;

void setup() {
  Serial.begin(9600);
  //while (!Serial);
  delay(10);
  // set the LEDs pins as outputs
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  // turn all the LEDs off
  digitalWrite(LEDR, LOW);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);

  if (!HTS.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }

  pinMode(LED_BUILTIN, OUTPUT);

  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }

  BLE.setLocalName("SteveTempHumidity2");
  BLE.setAdvertisedService(sensorService);
  sensorService.addCharacteristic(temperatureSensorLevel);
  sensorService.addCharacteristic(humiditySensorLevel);
  BLE.addService(sensorService);
  temperatureSensorLevel.writeValue( oldTemperature);
  humiditySensorLevel.writeValue( oldHumidity);

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

void loop() {
  BLEDevice central = BLE.central();
  if (central) {
    Serial.print("Connected to central: ");
    Serial.println(central.address());
    //digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(LEDR, HIGH);
    digitalWrite(LEDG, HIGH);
    digitalWrite(LEDB, LOW);

    while (central.connected()) {
      //long currentMillis = millis();
      updateHumidityLevel();
      delay (300);
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

void updateHumidityLevel() {
  float temp, hum;
  temp = HTS.readTemperature();
  hum = HTS.readHumidity();
  Serial.print("********");
  Serial.print(temp);

  if (temp != oldTemperature) {
    temperatureSensorLevel.writeValue(temp);
   
    oldTemperature  = temp;
  }

  if (hum != oldHumidity) {
    humiditySensorLevel.writeValue(hum);
    oldHumidity  = hum;
  }

  Serial.print("Temp = ");
  Serial.print(temp);
  Serial.println("°C");
  Serial.print("Humidity = ");
  Serial.print(hum);
  Serial.println("%");
  delay(1000);
}

There is almost never a need to send sensor data as float values, as the actual measurement is usually a small integer.

Multiply by a convenient scale factor (e.g. 100) and send the truncated integer value instead.

Ok I'll try that, but why is sending a float value causing such a mess?

Even if you transfer the binary float representation correctly, keep in mind that there are different representations on different machines (one of them is byte order: big or little endian) and conversions are sometimes required.

I changed the float values to int and the BLE characteristics to BLEIntCharacteristic but now I get no value at all in the "nRF Connect" app. I have been trying for over two days now to send the temperature data from the Nano 33 BLE sense over BLE as anything other than a string. This is most frustrating. Any tips would be greatly appreciated.

You can always convert the int to a string and send that.

To make a standard C-string, a zero terminated character array, requires two lines of code (see itoa() among other options):

char stringvalue[8]={0};
itoa(value, stringvalue,10);

That can also be done with the original float variable.

True, dtostrf() would be a good choice for that.

You can always convert the int to a string and send that.

That's what the original sketch did, but I want to use the value on another Arduino acting as the BLE Central. It is much easier to write a sketch manipulating an integer or float than a sring. Ie >, <, +,*. Which is why I want to send a number.

Your original post mentioned nothing about that. You asked about displaying the value in an Android app.

I can not confirm your issue. I don't have your sensors, but when I use a set value in the sketch I can see them in nrfConnect (and LightBlue, which I prefer). Are you seeing the correct sensor values in you serial output?

#include <ArduinoBLE.h>
#include <Arduino_HTS221.h>
#include <Arduino_LSM9DS1.h>

BLEService sensorService("181A");

BLEIntCharacteristic temperatureSensorLevel("2A6E", BLENotify);
BLEIntCharacteristic humiditySensorLevel("2A6F", BLENotify);
int oldTemperature = 0;
int oldHumidity = 0;

void setup() {
  Serial.begin(9600);
  //while (!Serial);
  delay(10);
  // set the LEDs pins as outputs
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  // turn all the LEDs off
  digitalWrite(LEDR, LOW);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);

  //if (!HTS.begin()) {
  //  Serial.println("Failed to initialize humidity temperature sensor!");
  //  while (1);
  //}

  pinMode(LED_BUILTIN, OUTPUT);

  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }

  BLE.setLocalName("SteveTempHumidity2");
  BLE.setAdvertisedService(sensorService);
  sensorService.addCharacteristic(temperatureSensorLevel);
  sensorService.addCharacteristic(humiditySensorLevel);
  BLE.addService(sensorService);
  temperatureSensorLevel.writeValue( oldTemperature);
  humiditySensorLevel.writeValue( oldHumidity);

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

void loop() {
  BLEDevice central = BLE.central();
  if (central) {
    Serial.print("Connected to central: ");
    Serial.println(central.address());
    //digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(LEDR, HIGH);
    digitalWrite(LEDG, HIGH);
    digitalWrite(LEDB, LOW);

    while (central.connected()) {
      //long currentMillis = millis();
      updateHumidityLevel();
      delay (300);
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

void updateHumidityLevel() {
  static int temp = 23; 
  static int hum = 55;
  //temp = HTS.readTemperature();
  //hum =  HTS.readHumidity();
  Serial.print("********");
  temp = temp +1; //increment value for testing
  
  if (temp != oldTemperature) {
    temperatureSensorLevel.writeValue(temp);
   
    oldTemperature  = temp;
  }

  if (hum != oldHumidity) {
    humiditySensorLevel.writeValue(hum);
    oldHumidity  = hum;
  }

  Serial.print("Temp = ");
  Serial.print(temp);
  Serial.println("°C");
  Serial.print("Humidity = ");
  Serial.print(hum);
  Serial.println("%");
  delay(1000);
}

Yes I am getting the correct (integer) sensor values in the serial monitor. I left the app nRF Connect running on my phone and after a while I noticed that the humidity value was showing correctly and a few minuteslater the temperature value appeared correctly too. I restarted the Nano and reconnected but the values have not appeared yet.

"I changed the float values to int"
Rather than changing them, take a copy in to an int variable and then transmit that int copy, like this:

float myFloat=function_which_does_measurement_from_hardare();
int convertedValue=(int)myFloat*any_scaling_factor_needed;
//now use convertedValue

Simply changing a float to an int could easily break other things done with it, particularly anything which relies on the decimal parts of it.

Using your code I still had the same problems. I changed the BLEIntCharacteristics from BLENotify to BLERead and got the values of 24°C (23+1) and 55% in the app! Great! I reset the temp and hum to int and uncommented the following two lines

 temp = HTS.readTemperature();
  hum =  HTS.readHumidity();

I now get a reading from the sensors.

Now, why should BLERead work and BLENotify not?

I don't know why you are having issues with Notify. I would try using Light Blue and use the "subscribe" button. I think I one point I did have issues with Notify (without Read) and nrfConnect

When I first started with your program I thought Read was going to be needed as well. But I later determined that Notify alone was working OK.

BLEIntCharacteristic temperatureSensorLevel("2A6E", BLENotify | BLERead );

I don't know why you are having issues with Notify, but I think I one point I did have issues with Notify (without Read) and nrfConnect.

I would try using Light Blue and use the "subscribe" button.

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