Decode float sent by Lopy as Node

Hello everyone!

I am sending my data from my lopy to my gateway using struct.pack(‘d’,data) to make them bytes.
Now, how can i decode them from Hexadecimal back to float? I found some functions in javascript but none of them is working.

i am using the struct.pack(‘f’,data) method to send data collected by tmp36 sensor. So the last payload i send was “00 82 d2 41” which sould represent 26.3135 as decoded by https://gregstoll.dyndns.org/~gregstoll/floattohex/.
I search to find any javascript method which implement this decode but i found nothing.

Thanks in advance!

Unfortunately Otto, the JavaScript ES5 parser that TTN uses, does not support Typed Arrays, which would have made life easy.

Two options:

  • Don’t send a float, but multiply by, say, 100 and send an integer. Then after decoding, divide by 100 to get the original value. You’ll find many examples here on the forum.

  • Use the following, based on a Stack Overflow post by Ilya Bursov, but for this example with the byte order reversed:

function Decoder(bytes, port) {

  // Based on https://stackoverflow.com/a/37471538 by Ilya Bursov
  function bytesToFloat(bytes) {
    // JavaScript bitwise operators yield a 32 bits integer, not a float.
    // Assume LSB (least significant byte first).
    var bits = bytes[3]<<24 | bytes[2]<<16 | bytes[1]<<8 | bytes[0];
    var sign = (bits>>>31 === 0) ? 1.0 : -1.0;
    var e = bits>>>23 & 0xff;
    var m = (e === 0) ? (bits & 0x7fffff)<<1 : (bits & 0x7fffff) | 0x800000;
    var f = sign * m * Math.pow(2, e - 150);
    return f;
  }  

  // Test with 0082d241 for 26.3134765625
  return {
    // Take bytes 0 to 4 (not including), and convert to float:
    temp: bytesToFloat(bytes.slice(0, 4))
  };
}

The above function will get you 26.3134765625. To limit the number of decimals, use, e.g.:

// Unary plus-operator to cast string result of toFixed to a number:
temp: +bytesToFloat(bytes.slice(0, 4)).toFixed(3)

Of course, the toFixed could also be added to bytesToFloat instead:

// Convert to a string with 3 decimals, and then apply the unary plus-operator
// to cast the string result of toFixed to a proper number:
return +f.toFixed(3);

When handling multiple values, one can use the x+= addition assignment operator and the x++ postfixed increment operator to keep track of the bytes that have been handled:

var b = 0;
var float1 = bytesToFloat(bytes.slice(b, b+=4));
var float2 = bytesToFloat(bytes.slice(b, b+=4));
var byte1 = bytes[b++];
// Assume LSB (MSB seems more common?)
var unsigned16bits = bytes[b++] | bytes[b++]<<8;
// Sign-extend to 32 bits to support negative values, by shifting 24 bits
// (too far) to the left, followed by a sign-propagating right shift:
var signed16bits = bytes[b++] | bytes[b++]<<24>>16;
var signed32bits = bytes[b++] | bytes[b++]<<8 | bytes[b++]<<16 | bytes[b++]<<24;
var float3 = bytesToFloat(bytes.slice(b, b+=4));

Finally, beware:

6 Likes

Thank you very much! It works!

As an aside: note that you are not sending hexadecimal. That’s just a representation of the binary data you’re sending. You could also print the very same data as 4 decimal values, a single Base64 value, 32 ones or zeroes, and so on, and so on.

…and beware: the code might be a bit too simple; most other examples take more edge cases into account, such as NaN and infinity.

Also, the “bias” value of 150 in Math.pow(2, e - 150) seems to work for your example but I don’t know why. (The documented bias for 32 bits single-precision IEEE-754 floating point is 127. So I assume there’s some optimization going on in the first lines of code that apparently make the value for e and m not be the “exponent” and “mantissa” as used in other definitions, which apparently needs the bias in the above code to be 23 larger. Maybe the mantissa is 223 too large?)

Another aside: the “bias” value, which is documented to be 127 for 32 bits single-precision IEEE-754 floating point, has been replaced by 150 in m * Math.pow(2, e - 150). This is effectively m × 2-23 × 2e-127 a.k.a. (m / 223) × 2e-127, and is a nice optimization to get the 24th implicit leading bit in the “mantissa”.

worked flawless for extract the values from Eastron ESDM 230 Lorawan current meter. (yes, not the best but finally got it works) Thanks

Hello, I need to create the upload command line to obtain:
Voltage
accumulated power KWH
If someone knows how to do it, let them contribute.

How to make it report every 1min with the information I have collected I have not succeeded.
Thanks

Please dont - not on TTN - given other posts on the Eastron thread where you have double posted. I believe their payload is inefficient and too long (per other thread) and even if you force device to stay on SF7 (close to GW?) then TTN FUP is 30s per day - ~<every 3 mins payload dependent - will leave you to do your own calculations based on your payload…

And given that this thread is specifically about decoding floats, closing - you can carry on with the other thread as this one hasn’t got started.