-
• #2
I think what you're doing is right (you can also use DataView - which could be a little easier).
The issue is with the EspruinoHub's decoding. It's doing something pretty simple right now - 8 bit is interpreted as-is, and 16 bit is the temperature x100. I'm not sure if it's spec compliant but it is what the nRF Connect app seems to do.
https://github.com/espruino/EspruinoHub/blob/master/lib/attributes.js#L32
I'm not 100% sure the docs you found are for the UUID 0x1809 that's being used though. They seem to be for 0x2A1C. Having said that there don't appear to be any docs for the 0x1809 UUID when used in advertising (in fact it's almost certainly non-standard).
... so I'd be tempted to add a decoder in EspruinoHub for the
0x2A1C
UUID, and handle that correctly? Either that, or you could add to the 0x1809 decoder so that it interprets 4 bytes of data as a float? -
• #3
I'm not 100% sure the docs you found are for the UUID 0x1809 that's being used though
GATT docs list that as:
Health Thermometer org.bluetooth.service.health_thermometer 0x1809
It matches your example in docs. From what I can tell
0x2A1C
is a code for "temperature measurement", while0x1809
is the code for the "health thermometer" service as a whole. Not sure if the NRF library we're using even has a notion of those formats, or is it up for us to provide an implementation.The issue is with the EspruinoHub's decoding. It's doing something pretty simple right now - 8 bit is interpreted as-is, and 16 bit is the temperature x100
Hmm... it seems that you're bitshifting the second value (
(((a[1]<<8)+a[0])/100)
), which makes it hard for me to reverse it.How would you encode a 16 bit float to this that would work on puck (i'm assuming its BE)?
function encodeFloat(num) { const dec = Math.round(n); const fractional = Math.round(n % 1 * 100); return [ dec, fractional >> 8 ]; // ??? }
-
• #4
The bit shift is just a way to turn the two 8 bit values into one 8 bit one.
You're doing basically the right thing but
n % 1 * 100
looks a bit weird to me... Something like this should work:function encodeFloat(num) { var d = Math.round(n*100); return [ d&255, d >> 8 ]; }
The
&255
isn't required (it cuts of the top 8 bits) as we're writing an 8 bit array anyway, but it makes it easier to debug.The other option you have is
DataView
:var d = new DataView(new ArrayBuffer(2)); d.setInt16(0,num*100,true) return new Uint8Array(d.buffer);
-
• #5
Thanks mate! Works like a charm.
I'll update the docs, maybe it'll be useful for others as well. -
• #6
Thanks!
Hey there!
I'm using
NRF.setAdvertising()
to advertise temperature readings from Puck.js.The examples in docs sadly only mention byte arrays, integers and string fragments as supported data:
What I'm trying to do is advertise the floating point temperature without rounding. Puck currently reports temperature with
0.25
accuracy, but I'm struggling with how to encode it in a way, that would make EspruinoHub understand it.The official BLE GATT spec for thermometer actually supports extra flags in the first byte and temp. reading (default is Celsius) as a Float32.
The node on puck doesn't sadly provide
Buffer
so I tried encoding withTypedArrays
like so:The resulting array is something like:
[0, 0, 0, 236, 65]
for temperature of around 21 deg, or[0, 0, 236, 65]
if you don't include the "flags" byte and just have BE 32-bit float.However, when I receive it in EspruinoHUB, the debug shows me:
It seems to struggle to decode those Float32 byte arrays.
When I sent something like
[236, 65]
(without the GATT flags and trimmed to just 2 bytes) then it shows me:I have no idea how it got
168.75
from those bytes.Any idea what EspruinoHub/Noble/bleno expect as a format for floats?
Have anyone succeeded in encoding floats for BLE Adv. ?