Decrypting messages for dummies

You can use a different port for each message type.

2 Likes

Would you be so kind and give me an example how to do this?

For an example using the port number, see step 3 and 5 of “Getting temperature, humidity and battery level” in Getting Badgerboard to work with TTN .

For LMiC, the port number is the first parameter in:

LMIC_setTxData2(1, buffer, sizeof(buffer), 0);

In the TTN Arduino library, it’s the last parameter in:

ttn.sendBytes(buffer, sizeof(buffer), 1);

A bit more details in Is there any documentation on payload functions?

And, of course, one can also define multiple applications for different payloads.

1 Like

Please help me with decoding data. I have this payload:

05 0A EF 22 28
where 050A is 2565 (this is temperature in celsius / 100)
where EF22 is 8944 (this is pressure in hPa, subtracted 900 and multiplied with 100)
where 28 is 40 (humidity in %)

This is decoder script but beggining is wrong.

function Decoder(bytes) {
  var temperature = bytes[0];
  var pressure = bytes[2];
  var humidity = bytes[4];

  dekodovana_teplota = temperature / 100;
  dekodovany_tlak = (pressure  / 100) + 900;
  
  return {
    teplota: dekodovana_teplota,
    tlak: dekodovany_tlak,
    vlhkost: humidity
  }
}

Im getting this but first two values are bad.

{
  "teplota": 0.34,
  "tlak": 900.34,
  "vlhkost": 40
}

Good values are:

{
  "teplota": 25.65,
  "tlak": 989.44,
  "vlhkost": 40
}

The first two values use two bytes each. The decoder won’t automatically add the other bytes for you. So, you’d need:

// LSB (least significant byte first):
var temperature = bytes[1]<<8 | bytes[0];
var pressure = bytes[3]<<8 | bytes[2];

Also, to support negative temperatures, you’ll want to read my notes about sign-extension above, and use:

// LSB (least significant byte first) and sign-extension to get 4 bytes 
// for proper decoding of negative values:
var temperature = bytes[1]<<24>>16 | bytes[0];
1 Like

var temperature = bytes[1]<<24>>16 | bytes[0];
var pressure = bytes[3]<<8 | bytes[2];
var humidity = bytes[4];

result is:

{
“teplota”: 25.65,
“tlak”: 989.4300000000001,
“vlhkost”: 40
}

but tlak is 989.44

That’s a rounding error when sending. Also, to limit the number of digits, you could fine tune using:

// Unary plus-operator to cast string result of toFixed to a number:
tlak: +dekodovany_tlak.toFixed(2),

Thank you. Works fine.

if you are an idiot like me and need to decode some text, paste this into your decoder payload function section.
this took me 2 hours to figure out. hope it saves you an hour and 55 minutes.

function Decoder(bytes, port) {
// Decode plain text; not recommended
var text = String.fromCharCode.apply(null, bytes);
return{
text: text,
}
}

2 Likes

If you want to save airtime you do not use text. Use binary data in stead…

hello, have you any example please of converting a text in bytes. I’m trying to do so with c++ on raspberry but fail!
The purpose is to send some informations of macaddress of conneted devices.
My string looks like: “54:65:00:AF:99 \n 78:87:09:AR:90 …” i get it in std::string format and i want to split it into bytes[]. thanks!

Hey Arjan

Just wanted to say thanks. You are one of the best communicators / educators I have seen on here. Thanks man.

John

6 Likes

Question from another dummy…

I have a BME680 sensor is working with my Pi-Zero and I can pull temp, pressure and voc data. The Pi-Supply Lora phat is connected and sending data. My Pi-Supply gateway works fine, I’m connected to TTN and passing decoded variables across to TagoIO which visualizes them. So all great… however i’m having trouble with decoding the data I’m sending to the TTN.

I’m using the “hello world” example script, supplied as part of the setup tutorial, as a template and have added the code to pull the data from the sensor. I’m converting that to HEX and the using the lora.send(temp). temp= the variable containing the hex of the temp integer. Packets are being received but my attempts to decode are failing. My assumption is that the data is being sent as ASCII text.

I have a question in with Pi Supply as to how the RAK811 library is encoding the data using the send command and also how do I decode it in the TTN?

If I use the raw rak811 send command i get…
rak811 -v send --port 1 FF TTN sees 46 46 in the payload
rak811 -v send --port 1 255 TTN sees 32 35 35 in the payload
rak811 -v send --port 1 01 TTN sees 30 31 in the payload
rak811 -v send --port 1 --binary 011001 TTN sees - 01 10 01 in the payload

I’m struggling to work out what the code is doing so I can clean it up. Based on the other post I’m assuming this is being seen as ASCII. How do I need to format my data?

I’d like to send the my temperature integer as HEX. So I was assuming that I would take 25.3456, shorten it to 2 decimal places *100 and send as 2 bits, 09c4. I’ve read about how to be ever more efficient but for now I’d be happy to have this work. Any pointers?

Python code from a coder of 3 months experience…

#!/usr/bin/env python3
from rak811 import Mode, Rak811
import time
import board
from busio import I2C
import adafruit_bme680

i2c = I2C(board.SCL, board.SDA)
bme680 = adafruit_bme680.Adafruit_BME680_I2C(i2c, debug=False)

bme680.sea_level_pressure = 1013.25

while True:
 
    print("\nTemperature: %0.1f C" % bme680.temperature)
    print("Gas: %d ohm" % bme680.gas)
    print("Humididty: %0.1f %%" % bme680.humidity)
    print("Pressure: %0.3f hPa" % bme680.altitude)

    temp = (bme680.temperature)
    temp = temp*100
    temp = round(temp, 0)
    tempH = hex(int(temp)).lstrip("0x")
    print(tempH)

    gas = (bme680.gas)
    gasH = hex(int(gas)).lstrip("0x")
    print(gasH)

    lora = Rak811()
    lora.hard_reset()
    lora.mode = Mode.LoRaWan
    lora.band = 'EU868'
    lora.set_config(dev_eui='3939353461xxxxxx',
    app_eui='70B3D57ED00xxxxx',
    app_key='D4CDC8FCB4C407093796E4298Axxxxxx')
    lora.join_otaa()
    lora.dr = 5
lora.send(tempH)
    time.sleep(1)

    rak811 -v send --port 1 --binary (tempH)
    lora.close()

    time.sleep(60)

TTN Java decoder I’ve been messing about with this…I have no Java knowledge/skills etc

function Decoder(bytes, port) {
  var gas = (bytes[1] << 23 ) | bytes[0];
  var temp = (bytes[0] << 0) | bytes[0];
  return {
    gas: gas,
    temp: temp
  }
}

Indeed, you’re sending text. That text happens to be the hexadecimal or even binary representation of the bytes you actually want to send, but: it’s still text. (“Hello world” examples are evil for LoRaWAN.)

Not really. You’ll want to send binary data; bits or bytes. Those don’t care about a human readable representation, such as hexadecimal.

So, the question for the other readers is: how to send bytes using Python?

Aside: JavaScript is not (at all) the same as Java. But if you would have been sending bytes, then your decoder would almost be fine, though you’ll want to check on shifting bytes, so: 8 bits at a time: var gas = bytes[1]<<8 | bytes[0]. And on not using the index [0] multiple times, and support negative temperatures, like explained above too: var temp = (bytes[2]<<24>>16 | bytes[3]) / 100 makes more sense, depending on the Python code you’ll end up with. Also, please see How do I format my forum post? [HowTo].

1 Like

Arjan,

I used your post Jan 7 '17 for reference. I know this post is old, but perhaps you can help me out?
I am struggling with decoding bytes from a Lora-Sensor.
I coded the sensor-controller (Arduino MKR WAN) as follows.
The data comes off a very sensitive inclinometer, so I want to keep accuracy up to 10-e6
co->rRoll and co->rPitch are double

long l_rRoll = (long)(((double)co->rRoll) * 10e6 ); //mRad
long l_tRoll = (long)(((double)co->tRoll) * 10e6 ); //mRad

char msg[7] = {0,1,2,3,4,5,6};
//Placeholder
msg[0]=0;
//Roll
msg[1] = (byte) (l_rRoll >> (0*8));
msg[2] = (byte) (l_rRoll >> (1*8));
msg[3] = (byte) (l_rRoll >> (2*8));  
//Pitch
msg[4] = (byte) (l_rPitch >> (2*8));                     
msg[5] = (byte) (l_rPitch >> (1*8));
msg[6] = (byte) (l_rPitch >> (0*8));

In the decoder I have the following (I multiply by 1000 to get to rad from mRad):

decoded.rRoll = ( bytes[3]<<16 | bytes[2]<<8 | bytes[1] ) / 10e6 * 1000.0;
decoded.rPitch =( bytes[6]<<16 | bytes[5]<<8 | bytes[4] ) / 10e6 * 1000.0;

The value for Roll is positive (+5.901337) and returns properly: “rRoll”: 5.9013
The value for Pitch is negative (-0.702381) but does return properly: “rPitch”: 5.8674
What am I doing wrong?

The 32 should read 24. As JavaScript bitwise operators are always 32 bits, shifting 32 bits effectively shifts nothing at all. (And <<40 would be the same as <<8.) Also, when using <<24 you only need to right-shift 8 bits. So: bytes[4]<<24>>8.

Aside, why are you sending l_rRoll as LSB, and l_rPitch as MSB? While you’re using the proper decoding, it’s quite confusing, I’d say.

Oh, you edited that, I think? The above applies to the previous version. :slight_smile:

Thx very much i will try this.
Yes it was a test, that’s why they were opposite

I used this for Pitch, which is currently neg:

decoded.tPitch = ( bytes[13]<<24>>16 | bytes[14]<<8 | bytes[15]) / 10e6 * 1000.0;

it yields: “tPitch”: -0.0189, which should be -0.607729
When I use this (from your earlier post upstream):

decoded.tPitch = ( (bytes[13] & 0x80 ? 0xFFFF<<24 : 0) | bytes[13]<<16 | bytes[14]<<8 | bytes[15]) / 10e8 * 1000.0;

it obtains the correct result: “tPitch”: -0.612914

(I changed the divisor/muliplier from 10e6 to 10e8 in order to increase the decimals, that’s why it’s different between the 2 versions above)

This basically is <<8 (but with sign-extension to support negative values). When combining 3 bytes into 32 bits, you need <<24>>8. Like for the 3 bytes XXYYZZ:

XX<<24>>8 = 00XX0000 or ffXX0000 (for negative values)
YY<<8     =     YY00        YY00
ZZ        =       ZZ          ZZ
            --------    --------
            00XXYYZZ    ffXXYYZZ

By the way:

While it will indeed return the correct value, using 0xFFFF<<24 is confusing, I feel. I wrote:

This is the same as:

var celciusInt = (bytes[0] & 0x80 ? 0xFFFF0000 : 0) | bytes[0]<<8 | bytes[1];

Above, handling 2 bytes from the payload, one needs to determine the value for the leftmost 2 bytes to get 32 bits. But in your case, when handling 3 bytes from the payload, you only need 1 extra byte to get 32 bits. Now, in JavaScript’s 32 bits processing for bitwise operators, your 0xFFFF<<24 indeed yields the 32 bits FF000000, not the 40 bits FFFF000000. But you can achieve the same with 0xFF<<24.

To be sure you understand bit shifting, see many more examples in Laird RS1xx - probably a question on bit shifting and Payload Format / Decode for TM-901 / N1C2 sensor from KCS TraceME.

(Aside: please see How do I format my forum post? [HowTo] about formatting code blocks, to avoid surprises with unwanted formatting, like happened in your first post before I edited that.)