LoRaWAN Connection
Info | ||
---|---|---|
| ||
Some of the features listed here (LoRaWAN 1.1, Remote Configuration, ...) are only implemented for recent versions of our firmware. For the Lobaro Sensor this starts with v0.2.1, for the Keller Sensor it starts with v0.3.0. If possible, you should update your devices to our most recent firmware. |
The connection to the LoRaWAN network is defined by multiple configuration parameters. This need to be set according to your LoRaWAN network and the way your device is supposed to be attached to it, or the device will not be able to send any data.
For a detailed introduction into how this values need to be configured, please refer to the chapter LoRaWAN configuration in our LoRaWAN background article.
Name | Description | Type | Values |
---|---|---|---|
OTAA | Activation: OTAA or ABP | bool | true = use OTAA, false = use ABP |
DevEUI | DevEUI used to identify the Device | byte[8] | e.g. 0123456789abcdef |
JoinEUI | Used for OTAA (called AppEUI in v1.0) | byte[8] | e.g. 0123456789abcdef |
AppKey | Key used for OTAA (v1.0 and v1.1) | byte[16] | |
NwkKey | Key used for OTAA (v1.1 only) | byte[16] | |
SF | Initial / maximum Spreading Factor | int | 7 - 12 |
ADR | Use Adaptive Data Rate | bool | true = use ADR, false = don't |
TimeSync | Days after which to sync time | int | days, 0 =don't sync time |
RndDelay | Random delay before sending | int | max seconds |
RemoteConf | Support Remote Configuration | bool | true =allow, false =deactivate |
LostReboot | Days without downlink before reboot | int | days, 0 =don't reboot |
Configuration
Configuration values defining the behaviour of the device. The Min and Max values will be preconfigured when receiving the device. In case of using "Restore Default" they will be reset to standard values and have to be set again using the values printed on the sensor or given separately.
name | description | example value |
---|---|---|
sendCron | Cron expression defining when to read and send | 0 0/15 * * * * for every 15 minutes |
rangeMin | min range in mh2o | in most cases 0 |
rangeMax | max range in mh2o | in most cases 15 |
outputMin | min digital output value of the sensor | in most cases 819 |
outputMax | max digital output value of the sensor | in most cases 11664 |
See also our Introduction to Cron expressions.
Payload Format
Data Message
Port: 1, Payload: 8 Bytes
Temperature is transmitted in 1/100°C, battery voltage in Millivolt and pressure in Bar.
PRESSURE | Temperature | Battery Voltage | |||||
---|---|---|---|---|---|---|---|
float32 | float32 | float32 | float32 | int16 | int16 | int16 | int16 |
Byte 0 | Byte 1 | Byte 2 | Byte 3 | LSB | MSB | LSB | MSB |
Status message
Port: 64, Payload: 13 Bytes
The Status Message communicates information about the device itself (starting with firmware 0.3.0). It contains information like the internal temperature of the device and the reason for the latest reboot.
For instructions how to parse the status message, please take a look at the reference parser implementation.
Payload Parser
Element-IoT: https://github.com/ZennerIoT/element-parsers/blob/master/lib/lobaro_pressure26d.ex
The Things Network
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
/** Helper* functionsTTN-compatible useddata bydecoder thisfor parser */ function signed(val, bits) { if ((val & 1 << (bits-1)) > 0) { // value is negative (16bit 2's complement) val = (~val & ((1 << bits) - 1)) + 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 uint32_BE(bytes, idx) { bytes = bytes.slice(idx || 0); return bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3] << 0; } function uint16_BE(bytes, idx) { bytes = bytes.slice(idx || 0); return bytes[0] << 8 | bytes[1] << 0; } function uint32_LE(bytes, idx) { bytes = bytes.slice(idx || 0); return bytes[0] << 0 | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; } function uint16_LE(bytes, idx) { bytes = bytes.slice(idx || 0); return bytes[0] << 0 | bytes[1] << 8; } function int40_BE(bytes, idx) { return signed(uint40_BE(bytes, idx), 40); } function int32_BE(bytes, idx) { return signed(uint32_BE(bytes, idx), 32); } function int16_BE(bytes, idx) { return signed(uint16_BE(bytes, idx), 16); } function int32_LE(bytes, idx) { return signed(uint32_LE(bytes, idx), 32); } function int16_LE(bytes, idx) { return signed(uint16_LE(bytes, idx), 16); } function float32(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 readVersion(bytes, i) { if (bytes.length < 3) { return null; } return "v" + bytes[i] + "." + bytes[i + 1] + "." + bytes[i + 2]; } /* Port 1: Data */ function Decoder_Data(bytes) { return { pressure: float32(int32_LE(bytes, 0)), temp: int16_LE(bytes,4) / 100, voltage: int16_LE(bytes,6) / 1000, } } /** * Decode status/error codes from GPS-Tracker to human readable tags. */ function decode_status_code(code) { switch (code) { case 0: return "OK"; case 101: return "PROBE_ERROR"; default: return "UNKNOWN"; } } /** * Decode reboot reason explaining last reboot of device. */ function decode_reboot_reason(code) { // STM reboot code from our HAL: switch (code) { case 1: return "LOW_POWER_RESET"; case 2: return "WINDOW_WATCHDOG_RESET"; case 3: return "INDEPENDENT_WATCHDOG_RESET"; case 4: return "SOFTWARE_RESET"; case 5: return "POWER_ON_RESET"; case 6: return "EXTERNAL_RESET_PIN_RESET"; case 7: return "OBL_RESET"; default: return "UNKNOWN"; } } /* Port 64: Status */ function Decoder_Status(bytes) { var firmware = String.fromCharCode.apply(null, bytes.slice(0, 3)); var version = readVersion(bytes, 3); var status_code = bytes[6]; var status_text = decode_status_code(status_code); var reboot_code = bytes[7]; var reboot_reason = decode_reboot_reason(reboot_code); var final_code = bytes[8]; var vcc = (int16_BE(bytes, 9) / 1000) || 0.0; var temp = (int16_BE(bytes, 11) / 10) || -0x8000; var app_data = bytes.slice(13); return { "firmware": firmware, "version": version, "status_code": status_code, "status_text": status_text, "reboot_code": reboot_code, "reboot_reason": reboot_reason, "final_code": final_code, "temperature": temp, "voltage": vcc, "app_data": app_data }; } // TTN compatible decoder function: function Decoder(bytes, port) { // Decode an uplink message from a buffer // (array) of bytes to an object of fields switch (port) { case 1: // date message: return Decoder_Data(bytes); case 64: // lobaro unified status telegram return Decoder_Status(bytes); case 128: case 129: case 130: case 131: // remote config responses return {}; default: // unsupported port: return null; } } function UpdateDevice(decoded) { if (!Device || !Device.setProperty) { // not in Lobaro Platform parser return; } var keys = ["firmware", "version", "status_code", "status_text", "reboot_code", "reboot_reason",the Lobaro LoRaWAN Humidity Sensor. * * For the current version of this and other data formats check out: * https://github.com/lobaro/ttn-data-formats/ * * For more information go to: * https://www.lobaro.com/ * * * MIT License * * Copyright (c) 2020 Lobaro * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // number parsing functions, minified: function signed(n,t){var i=Math.pow(2,t-1);return n<i?n:n-2*i}function uint_BE(n,t,i){if(i=i||0,n.length<t+i)return 0;for(var u=0,E=0;E<t;E++)u=256*u+n[E+(i||0)];return u}function int_BE(n,t,i){return signed(uint_BE(n,t,i),8*t)}function uint_LE(n,t,i){if(i=i||0,n.length<t+i)return 0;for(var u=0,E=t;E--;)u=256*u+n[E+i];return u}function int_LE(n,t,i){return signed(uint_LE(n,t,i),8*t)}function uint8(n,t){return n[t||0]}function int8(n,t){return signed(n[t||0],8)}function uint16_BE(n,t){return uint_BE(n,2,t)}function uint24_BE(n,t){return uint_BE(n,3,t)}function uint32_BE(n,t){return uint_BE(n,4,t)}function uint40_BE(n,t){return uint_BE(n,5,t)}function uint48_BE(n,t){return uint_BE(n,6,t)}function int16_BE(n,t){return int_BE(n,2,t)}function int24_BE(n,t){return int_BE(n,3,t)}function int32_BE(n,t){return int_BE(n,4,t)}function int40_BE(n,t){return int_BE(n,5,t)}function int48_BE(n,t){return int_BE(n,6,t)}function uint16_LE(n,t){return uint_LE(n,2,t)}function uint24_LE(n,t){return uint_LE(n,3,t)}function uint32_LE(n,t){return uint_LE(n,4,t)}function uint40_LE(n,t){return uint_LE(n,5,t)}function uint48_LE(n,t){return uint_LE(n,6,t)}function int16_LE(n,t){return int_LE(n,2,t)}function int24_LE(n,t){return int_LE(n,3,t)}function int32_LE(n,t){return int_LE(n,4,t)}function int40_LE(n,t){return int_LE(n,5,t)}function int48_LE(n,t){return int_LE(n,6,t)}function float32FromInt(n){var t=2147483648&n?-1:1,i=(n>>23&255)-127,u=8388607&n;if(128===i)return t*(u?Number.NaN:Number.POSITIVE_INFINITY);if(-127===i){if(0===u)return 0*t;i=-126,u/=1<<22}else u=(u|1<<23)/(1<<23);return t*u*Math.pow(2,i)}function float32_BE(n,t){return float32FromInt(int32_BE(n,t))}function float32_LE(n,t){return float32FromInt(int32_LE(n,t))} // status message decoding: var REBOOT_REASON={1:"LOW_POWER_RESET",2:"WINDOW_WATCHDOG_RESET",3:"INDEPENDENT_WATCHDOG_RESET",4:"SOFTWARE_RESET",5:"POWER_ON_RESET",6:"EXTERNAL_RESET_PIN_RESET",7:"OBL_RESET"}, FINAL_WORDS={0:"NONE",1:"RESET",2:"ASSERT",3:"STACK_OVERFLOW",4:"HARD_FAULT",16:"INVALID_CONFIG",17:"REMOTE_RESET",18:"NETWORK_LOST",19:"NETWORK_FAIL"}, STATUS_CODE={0:"OK",101:"PROBE_ERROR"}; function status_decode(e,t,_){return e[t]?e[t]:_||"UNKNOWN"}function status_version(e,t){return(e=e.slice(t||0)).length<3?null:"v"+e[0]+"."+e[1]+"."+e[2]}function status_Decoder(e){return{firmware:String.fromCharCode.apply(null,e.slice(0,3)),version:status_version(e,3),status_code:e[6],status_text:status_decode(STATUS_CODE,e[6]),reboot_code:e[7],reboot_reason:status_decode(REBOOT_REASON,e[7]),final_code:e[8],final_words:status_decode(FINAL_WORDS,e[8]),voltage:int16_BE(e,9)/1e3||0,temperature:int16_BE(e,11)/10||-32768,app_data:e.slice(13)}}function status_update_device(e){if(Device&&Device.setProperty){for(var t=["firmware","version","status_code","status_text","reboot_code","reboot_reason","final_code","final_words","app_data","temperature","voltage"],_=0;_<t.length;_++){var a=t[_];e[a]&&Device.setProperty(a,e[a])}e.latitude&&e.longitude&&Device.setLocation(e.latitude,e.longitude)}}function Parse(e){var t=bytes(atob(e.data)),_=Decoder(t,e.fPort);return status_update_device(_),_} /* Port 1: Data */ function data_Decoder(bytes) { return { pressure: float32_LE(bytes, 0), temp: int16_LE(bytes,4) / 100, voltage: int16_LE(bytes,6) / 1000, } } // TTN compatible decoder function: function Decoder(bytes, port) { // Decode an uplink message from a buffer // (array) of bytes to an object of fields switch (port) { case 1: // date message: "final_code", "final_words", "app_data", "temperature", "voltage"]; return data_Decoder(bytes); for (var i=0; i< keys.length; i++) { case 64: // varlobaro keyunified = keys[i];status telegram if (decoded[key]) { return status_Decoder(bytes); Device.setProperty(key, decoded[key]); case 128: case } 129: case } } // Wrapper for Lobaro Platform (not used in TTN) function Parse(input) { 130: case 131: // Decoderemote anconfig incomingresponses message to an object of fields. var b = bytes(atob(input.data))return {}; // use TTN decoderdefault: var decoded = Decoder(b, input.fPort); // unsupported Updateport: values in device properties UpdateDevice(decoded); return decoded;null; } } |
Device & Probe Dimensions
CE Declaration of Conformity
CE Declaration of Conformity (pdf).