LoRaWAN serialization/deserialization library for The Things Network
This fully unit-tested library allows you to encode your data on the Arduino side and decode it on the TTN side. It provides both a C-based encoder and a JavaScript-based decoder.
Since version 2.2.0 there is also an encoder for the TTN side.
In short
Encoding on Arduino, decoding in TTN
Arduino side:
LoraMessage message; message .addUnixtime(1467632413) .addLatLng(-33.905052, 151.26641); delete message;
TTN side:
// include src/decoder.jsvar json = ;// json == {time: unixtime, coords: [latitude, longitude]}
Encoding in TTN
TTN side:
// include src/encoder.jsvar bytes = ;// bytes is of type Buffer
With the convenience class
// include src/encoder.js// include src/LoraMessage.jsvar bytes = encoder ;// bytes = <Buffer 1d 4b 7a 57 64 a6 fa fd 6a 24 04 09 d0>
and then decoding as usual:
var result = decoder;// result =// { time: 1467632413,// coords: [ -33.905052, 151.26641 ],// heaters:// { a: true,// b: true,// c: false,// d: true,// e: false,// f: false,// g: false,// h: false } }
General Usage
Unix time (4 bytes)
Serializes/deserializes a unix time (seconds)
byte buffer[4];LoraEncoderencoder.writeUnixtime(1467632413);// buffer == {0x1d, 0x4b, 0x7a, 0x57}
and then in the TTN frontend, use the following method:
// 1467632413
GPS coordinates (8 bytes)
Serializes/deserializes coordinates (latitude/longitude) with a precision of 6 decimals.
byte buffer[8];LoraEncoderencoder.writeLatLng(-33.905052, 151.26641);// buffer == {0x64, 0xa6, 0xfa, 0xfd, 0x6a, 0x24, 0x04, 0x09}
and then in the TTN frontend, use the following method:
// [-33.905052, 151.26641]
Unsigned 8bit Integer (1 byte)
Serializes/deserializes an unsigned 8bit integer.
byte buffer[1];LoraEncoderuint8_t i = 10;encoder.writeUint8(i);// buffer == {0x0A}
and then in the TTN frontend, use the following method:
// 10
Unsigned 16bit Integer (2 bytes)
Serializes/deserializes an unsigned 16bit integer.
byte buffer[2];LoraEncoderuint16_t i = 23453;encoder.writeUint16(i);// buffer == {0x9d, 0x5b}
and then in the TTN frontend, use the following method:
// 23453
Temperature (2 bytes)
Serializes/deserializes a temperature reading between -327.68 and +327.67 (inclusive) with a precision of 2 decimals.
byte buffer[2];LoraEncoderencoder.writeTemperature(-123.45);// buffer == {0xcf, 0xc7}
and then in the TTN frontend, use the following method:
// -123.45
Humidity (2 bytes)
Serializes/deserializes a humidity reading between 0 and 100 (inclusive) with a precision of 2 decimals.
byte buffer[2];LoraEncoderencoder.writeHumidity(99.99);// buffer == {0x0f, 0x27}
and then in the TTN frontend, use the following method:
// 99.99
Bitmap (1 byte)
Serializes/deserializes a bitmap containing between 0 and 8 different flags.
byte buffer[1];LoraEncoderencoder.writeBitmap(true, false, false, false, false, false, false, false);// buffer == {0x80}
and then in the TTN frontend, use the following method:
// { a: true, b: false, c: false, d: false, e: false, f: false, g: false, h: false }
Composition
On the Arduino side
The decoder allows you to write more than one value to a byte array:
byte buffer[19];LoraEncoder encoder.writeUnixtime(1467632413);encoder.writeLatLng(-33.905052, 151.26641);encoder.writeUint8(10);encoder.writeUint16(23453);encoder.writeTemperature(80.12);encoder.writeHumidity(99.99);encoder.writeBitmap(true, false, false, false, false, false, false, false);/* buffer == { 0x1d, 0x4b, 0x7a, 0x57, // Unixtime 0x64, 0xa6, 0xfa, 0xfd, 0x6a, 0x24, 0x04, 0x09, // latitude,longitude 0x0A, // Uint8 0x9d, 0x5b, // Uint16 0x1f, 0x4c, // temperature 0x0f, 0x27, // humidity 0x80 // bitmap}*/
LoraMessage
Convenience class There is a convenience class that represents a LoraMessage that you can add readings to:
LoraMessage message; message .addUnixtime(1467632413) .addLatLng(-33.905052, 151.26641) .addUint8(10) .addUint16(23453) .addTemperature(80.12) .addHumidity(99.99) .addBitmap(false, false, false, false, false, false, true, false); /*getBytes() == { 0x1d, 0x4b, 0x7a, 0x57, // Unixtime 0x64, 0xa6, 0xfa, 0xfd, 0x6a, 0x24, 0x04, 0x09, // latitude,longitude 0x0A, // Uint8 0x9d, 0x5b, // Uint16 0x1f, 0x4c, // temperature 0x0f, 0x27, // humidity 0xfd // Bitmap}andgetLength() == 20*/
decode
method
Composition in the TTN decoder frontend with the The decode
method allows you to specify a mask for the incoming byte buffer (that was generated by this library) and apply decoding functions accordingly.
Example
Paste everything from src/decoder.js
into the decoder method and use like this:
{ // code from src/decoder.js here return ;}
This maps the incoming byte buffer of 12 bytes to a sequence of one latLng
(8 bytes) and one unixtime
(4 bytes) sequence and maps the first one to a key coords
and the second to a key time
.
You can use: 64 A6 FA FD 6A 24 04 09 1D 4B 7A 57
for testing, and it will result in:
Example decoder in the TTN console
Set up your decoder in the console:
Example converter in the TTN console
The decode method already does most of the necessary transformations, so in most cases you can just pass the data through:
Development
- Install the dependencies via
yarn
- Run the unit tests (C) via
yarn run test:c
- Run the unit tests (JavaScript) via
yarn test
- Check the coverage (JavaScript) via
yarn coverage
(seecoverage/lcov-report
)
The CI will kick off once you create a pull request automatically.