Skip to main content

Environment Sensor (LoRaWAN)

Lobaro LoRaWAN Environment Sensor

Target Measurement and Purpose

High-precision measurement of temperature, humidity, and pressure using the Bosch BME680 environmental sensor.

Configuration

For configuration of the LoRaWAN parameters, refer to the LoRaWAN configuration article.

NameDescriptionExample value
MeasureCronCron expression defining when a measurement is taken.0 0/15 * * * * for every 15 minutes

See also our Introduction to CRON expressions.

Firmware update notifications are described on the Firmware & Updates page.

Payload

Example payloads for each port:

Status Message (Port 1)

Payload: no example available yet.

Decoded:

{
"temp": 20.4,
"vBat": 3.0,
"version": "v0.0.1"
}

Data Message (Port 2)

Structure:

NamePosLenTypeDescription
timestamp05uint40Time of measurement, see timestamps in our LoRaWAN devices.
error flag51byte1: error, 0: success
humidity62uint16 BEHumidity in 1/10 % rH
temperature82int16 BETemperature in 1/10 °C
pressure102uint16 BEPressure in 10 Pa

Example payload: 00386d440700015400f527d1

Decoded:

{
"error": false,
"humidity": 34,
"pressure": 1019.3,
"temperature": 24.5,
"time": 946684935000
}

Parser

JavaScript Parser

Environment Sensor payload parser
function readVersion(bytes, i) {
if (bytes.length < 3) {
return null;
}
return "v" + bytes[i] + "." + bytes[i + 1] + "." + bytes[i + 2];
}

function signed(val, bits) {
if ((val & 1 << (bits - 1)) > 0) { // value is negative (16bit 2's complement)
var mask = Math.pow(2, bits) - 1;
val = (~val & mask) + 1; // invert all bits & add 1 => now positive value
val = val * -1;
}
return val;
}

function uint40_BE(bytes, idx) {
bytes = bytes.slice(idx || 0);
return bytes[0] << 32 |
bytes[1] << 24 | bytes[2] << 16 | bytes[3] << 8 | bytes[4] << 0;
}

function uint16_BE(bytes, idx) {
bytes = bytes.slice(idx || 0);
return bytes[0] << 8 | bytes[1] << 0;
}

function int40_BE(bytes, idx) {
return signed(uint40_BE(bytes, idx), 40);
}

function int16_BE(bytes, idx) {
return signed(uint16_BE(bytes, idx), 16);
}

function ParseStatusMessage(data) {
var decoded = {};
decoded.version = readVersion(data, 0);
decoded.vBat = uint16_BE(data, 5) / 1000.0;
decoded.temp = int16_BE(data, 3) / 10.0; // byte 8-9 (originally in 10th degree C)
decoded.msg = "Firmware Version: " + decoded.FirmwareVersion + " Battery: " + decoded.Vbat + "V Temperature: " + decoded.Temp + "°C";
return decoded;
}

function ParseDataMessage(data) {
return {
"time": int40_BE(data, 0) * 1000,
"error": !!data[5],
"humidity": uint16_BE(data, 6) / 10.0,
"temperature": int16_BE(data, 8) / 10.0,
"pressure": uint16_BE(data, 10) / 10
};
}

// Decoder function for TTN
function Decoder(bytes, port) {
// Decode an incoming message to an object of fields.
var decoded;

switch (port) {
case 1:
decoded = ParseStatusMessage(bytes);
break;
case 2:
decoded = ParseDataMessage(bytes);
break;
default:
decoded = {};
}

return decoded;
}

// Wrapper for Lobaro Platform
function Parse(input) {
// Decode an incoming message to an object of fields.
var b = bytes(atob(input.data));
var decoded = Decoder(b, input.fPort);

if (input.fPort == 2) {
Device.setProperty("status.firmware", decoded.FirmwareVersion);
Device.setProperty("status.voltage", decoded.Vbat);
Device.setProperty("status.temperature", decoded.Temp);
}

return decoded;
}

// Wrapper for Loraserver / ChirpStack
function Decode(fPort, bytes) {
return Decoder(bytes, fPort);
}

/*
// Wrapper for Digimondo niota.io
module.exports = function (payload, meta) {
const port = meta.lora.fport;
const buf = Buffer.from(payload, 'hex');

return Decoder(buf, port);
};
*/