Decoder function

i am converting float data to bytes using python struct library while sending data to TTN.

what decoder function do I need to use to get the data back ?

Hi, could you possibly elaborate on the question? Tell us which library exactly you are using (i know you say ‘python struct’, but there can be multiple variations…could you give a link to it on github?

The chances are - you will need to write a decoder yourself…
Show me how the data is converted (with an example of input in decimal <-python->output hex)…
Might have luck converting it…

Anyhow, if you are using lib i think you are, and it is converting a float into 2 bytes…try using this (assuming your data is only 2 bytes long):

function Decoder(bytes, port) {
var obj = new Object();
var float=(bytes[0] << 8 | bytes[1])/100;
return obj;
}

This will convert data like 011D to 285, and dividing by 100 will give 2.85…Thats how many manufacturers encode data for battery…
But anyhow, provide some details on encryption…

I am using lopy4 from pycom and below is the code I am using to pack the float values

buffersitemp = struct.pack(“f”,si.temperature())
buffersihum = struct.pack(“f”,si.humidity())

I am sending using

s.send(buffersitemp)
s.send(buffersihum)

for which I get the payload as below in TTN console

5A5A0642
D8202D42

As the value is actually transmitted as a float, you cannot use the above to decode it: the decoder is JavaScript and JavaScript’s bitwise operators work on 32 bits integers, not on floats.

See Decode float sent by Lopy as Node.

the link you gave worked. but I wanted to understand how this bytes to float works under the hood.

are there any links you can recommend for further reading.

I already linked to http://steve.hollasch.net/cgindex/coding/ieeefloat.html in the other topic.

I have temperature, humidity and pressure values coming into TTN (decoded using above code) how can I filter those to be published to separate mqtt topics ?

This is nicely documented: https://www.thethingsnetwork.org/docs/applications/mqtt/api.html#uplink-fields

Thanks for all the help.

I am able to subscribe to the uplink messages but the timestamp I see is for the eu region whereas my gateway is located in asia. How can I make sure I get the correct time ?

I doubt that. I’m quite sure you’ll get a value that ends with “Z”, indicating Zulu-time, a.k.a. UTC. So, any library that can handle ISO 8601 dates should understand that.

1 Like

two of the convert functions I use in the convert section of the ttn payloads

function Bytes2Float32(bytes) {
    var sign = (bytes & 0x80000000) ? -1 : 1;
    var exponent = ((bytes >> 23) & 0xFF) - 127;
    var significand = (bytes & ~(-1 << 23));
    if (exponent == 128) 
        return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);
    if (exponent == -127) {
        if (significand === 0)  return sign * 0.0 ;
        exponent = -126;
        significand /= (1 << 22);
    } else significand = (significand | (1 << 23)) / (1 << 23);
    return sign * significand * Math.pow(2, exponent);
}
function bytes2short(bytes){
  var sign = (bytes[1] & 0x80) ? -1 : 1 ;
  var short = (bytes[1] << 8) + bytes[0];
  if (sign < 0) {
    short = (short & ~(0xffff))
  }
  short *= sign;
  return short;
}
1 Like

When using TTN’s standard naming convention for the Decoder function, being:

function Decoder(bytes, port) {
    ...

…then bytes is an array of numbers, with each number being 0 to 255. So it seems the above needs to be invoked with something like:

// LSB 32 bits float
var float = Bytes2Float32(bytes[3]<<24 | bytes[2]<<16 | bytes[1]<<8 | bytes[0]);

Alternatively, change the function to read:

function Bytes2Float32(bytes) {
    // better rename this to a new local variable, e.g., bits:
    bytes = bytes[3]<<24 | bytes[2]<<16 | bytes[1]<<8 | bytes[0];
    var sign = (bytes & 0x80000000) ? -1 : 1;
    ....

…and invoke with:

// Take bytes 0 to 4 (not including)
var float = Bytes2Float32(bytes.slice(0, 4));

(When handling a lot of values, use the x+= addition assignment operator and the x++ postfixed increment operator to keep track of the bytes that have been handled.)

As an aside, bytes2short can be written as:

// LSB 16 bits signed number.
// 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 signedInteger = bytes[1]<<24>>16 | bytes[0];

Both functions are part of the Converter function and called like you described. In the decoder function I take a 4 byte slice of the bytes, and in the Converter I make a 4 byte float out of it.
your version of the bytes2short is a lot short. I wil try that one out.