Skip to content

BLEEddystoneTLM wrong handling of temperature field of beacon data #3833

Closed
@beegee-tokyo

Description

@beegee-tokyo

Hardware:

Board: ESP32 Dev Module
Core Installation version: 1.0.3
IDE name: Arduino IDE & Platform.io
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 115200
Computer OS: Windows 7

Description:

@chegewara , can you confirm?
EddystoneTLM has a temperature value.
According to Google definition the format is 8.8 fixed-point notation. But in the BLEEddystoneTLM class the temperature is declared as float, and the two bytes of the temperature value is just interpreted as an float value which gives complete wrong values. I found one Eddystone TLM example, and there the setting the temperature values is done wrong as well. The wrong value can be seen in nRFConnect, where it shows impossible temperatures.

The correct conversion from float to 8.8 fixed-point and back is shown in Fixed Point Maths.

The correct conversion on the beacon side would be (as example read temperature from a DHT sensor)

float tempFloat = dht.getTemperature();
int temp = (int)(tempFloat * 256);
...
beacon_data[5] = (temp & 0xFF);					   // Beacon temperature
beacon_data[4] = (temp >> 8);					   //
...

And in BLEEddystoneTLM class the getTemp() function should be

float NimBLEEddystoneTLM::getTemp() {
	return ((((m_eddystoneData.temp) & 0xFF00) >> 8) + (((m_eddystoneData.temp) & 0xFF) << 8)) / 256.0f;
} // getTemp

Sketch: Modified BLE scanner example

#include <Arduino.h>

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

#include "BLEEddystoneURL.h"
#include "BLEEddystoneTLM.h"
#include "BLEBeacon.h"

#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))

int scanTime = 5; //In seconds
BLEScan *pBLEScan;

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
    void onResult(BLEAdvertisedDevice advertisedDevice) {
	{
		if (advertisedDevice.haveName())
		{
			Serial.print("Device name: ");
			Serial.println(advertisedDevice.getName().c_str());
			Serial.println("");
		}

		if (advertisedDevicehaveServiceUUID())
		{
			BLEUUID devUUID = advertisedDevice.getServiceUUID();
			Serial.print("Found ServiceUUID: ");
			Serial.println(devUUID.toString().c_str());
			Serial.println("");
		}
		else
		{
			return;
		}

		uint8_t *payLoad = advertisedDevice.getPayload();

		BLEUUID checkUrlUUID = (uint16_t)0xfeaa;

		if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
		{
			if (payLoad[11] == 0x10)
			{
				// this part for Eddystone URL beacon
			}
			else if (payLoad[11] == 0x20)
			{
				Serial.println("Found an EddystoneTLM beacon!");
				BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();

				// Why The F*** is a std::string used here. THE ADVERTISED DATA IS BINARY AND CONTAINS NULL VALUES
				std::string eddyContent = "01234567890123";

				for (int idx = 0; idx < 14; idx++)
				{
					eddyContent[idx] = payLoad[idx + 11];
				}

				foundEddyURL.setData(eddyContent);
				Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
				Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
				// Correct calculation of temperature from 8.8 fixed-point
				int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
				float calcTemp = temp / 256.0f;
				Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
				Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
				Serial.printf("Reported time since last reboot: %dms\n", foundEddyURL.getTime());
				Serial.println("\n");
			}
		}
	}
};

void setup()
{
	Serial.begin(115200);
	Serial.println("Scanning...");

	BLEDevice::init("");
	pBLEScan = BLEDevice::getScan(); //create new scan
	pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
	pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
	pBLEScan->setInterval(100);
	pBLEScan->setWindow(99); // less or equal setInterval value
}

void loop()
{
	// put your main code here, to run repeatedly:
	BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
	Serial.print("Devices found: ");
	Serial.println(foundDevices.getCount());
	Serial.println("Scan done!");
	pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
	delay(2000);
}

Debug Messages: Log output with both the incorrect calculated and correct calculated temperature.

Reported temperature from TLM class: 33309.00C
Reported temperature from data: 29.51C

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions