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: