Decrypting messages for dummies

Without seeing your code, my guess would be that you’re still sending text, as a null-terminated string. The maximum length of such string is always 1 less than its total length, as it always needs a place to store the 0x00 character.

If you look at the manual for slice, you’ll see it needs a start index and an end index. In the examples x is the start index. In my example:

var i = uint16(bytes.slice(0, 2));  // use bytes 0 and 1
var c = latLng(bytes.slice(2, 10)); // use bytes 2 thru 9

You could rewrite that to:

var x = 0;
var i = uint16(bytes.slice(x, x + 2));
x = x + 2;
var c = latLng(bytes.slice(x, x + 8));
x = x + 8;
...

And as x = x + 2 can be written as x += 2, you can combine this to:

var x = 0;
var i = uint16(bytes.slice(x, x += 2));
var c = latLng(bytes.slice(x, x += 8));

Here is the Arduino code:
byte mydata[3];
uint16_t k;

// Prepare upstream data transmission at the next possible time.
Serial.print("\nReady to send string mydata “);
Serial.print(k);
Serial.println(” in DEC is: ");
LoraEncoder encoder(mydata);
encoder.writeUint16(k); //
LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
Serial.println(F(“Packet queued”));

Is it correct?

1 Like

There’s your surprise…

This will fill 2 bytes:

encoder.writeUint16(k);

So, declaring memory space for just 2 bytes is good enough (you’re not sending a null-terminated string here, but just plain bytes that you encode yourself):

byte mydata[2]; // size is 2
...
LMIC_setTxData2(1, mydata, sizeof(mydata), 0);

Holy shit! - true! But for what purpose is -1 in this sketch https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-abp/ttn-abp.ino (line 142)?

Well, that example does send a null-terminated string:

static uint8_t mydata[] = "Hello, world!";

Here, the text is 13 characters long, but the size of mydata will be 14, to add an 0x00 at the end. So, to only send the text without the trailing 0x00 character, sizeof(mydata) - 1 is needed.

The example would better use strlen((char *)mydata) to get the size up to the first 0x00 character. Or better yet: not send strings at all :slight_smile:

At the end of this topics i would like to thank you to @arjanvanb for the useful advices and i would like to make short digest to be useful for the someone else also.
Here is the highlights:

  • documentation on “Payload functions” is here Is there any documentation on payload functions?
  • before you send the data from the node you should pack it in packet as small as possible due to stay within fair policy BW use; so the best way is to code it and not to use for example ASCII text;
  • one nice tools to code/decode on Arduino/TTN is https://github.com/thesolarnomad/lora-serialization
  • to code use code for Arduino and if you use “Convenience class LoraMessage” do not forget “LoraMessage message” at the beggining of the loop, otherwise your payload will grow every time as it will pass the loop ;-);
  • to decode message on TTN go to console/payload functions and in window of decoder copy src/decoder.js and at the end add for example “return decode(bytes, [uint16, temperature, humidity, uint16], [‘voltage’, ‘temperature’, ‘humidity’, ‘pressure’]);”

I hope this will make a day to someone else :slight_smile:

6 Likes

When everything work fine comes another question: how can i decrypt messages from two different nodes where one sending for example temperature and the other sending temperature and voltage?

You might be able to determine the difference by the size of what is received.

Alternatively what we did once when we had all kinds of different nodes, we added a leading byte describing what data was following. I.e. 0x00 for temp 2 bytes (total of 3 bytes), 0x01 for temp 2 bytes plus voltage 1 byte. Etc.

1 Like

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