Proposal of April 30th, 2016. Thierry Schneider, Tetraedre Sarl
The maximum size of the LoRaWAN payload is 64 bytes. This limited size is the main reason to develop a flexible and compact data encoding.
Tetraedre is active in the Internet Of Things technology since many years and has developped efficient and versatile data encoding.
The goal is not to be the most size efficient but to find a good trade-off between size, versatility and portability.
The first byte of the payload is named header_main. This is the only fixed part of the payload. The description of this parameter is given below. The rest of the payload is a concatenation of data chunks. Chunks are either of type A, type B or type C. There might be any mix of chunks, in any order.
LoRaWAN Payload | |
First byte | rest of payload |
header_main | serie of chunks |
The two must significant bits of header_main are reserved and must be set to 0. Allowed values for header_main are thus 0 to 63.
Each chunk start with a header byte. This byte is used for data identification but also to know the size of the chunk.
Header value | Type / Description |
---|---|
0x00 | Reserved value. Means end of stream |
0x01 - 0x5F | Type A Chunk. Fixed size. 3 bytes |
0x60 - 0x7F | Type D Chunk. Fixed size. 2 bytes |
0x80 - 0xBF | Type B Chunk. Fixed size. 5 bytes |
0xC0 - 0xFE | Type C Chunk. Variable size |
0xFF | reserved value. Means end of stream |
The type A chunk is 3 bytes long. The first byte is the chunk header. The header is followed by 2 bytes
header | data byte8 |
data byte0 |
byte8 is MSB
The type B chunk is 5 bytes long. The first byte is the chunk header. The header is followed by 4 bytes
header | data byte24 |
data byte16 |
data byte8 |
data byte0 |
byte24 is MSB
When data are transmitted in floating point the IEEE754 format must be used
The type C chunk is a variable size block. The first byte is the chunk header. The header is followed the size parameter which indicates the size of the data field
header | size | data field length is "size" bytes |
The type D chunk is 2 bytes long. The first byte is the chunk header. The header is followed by 1 byte
header | data |
The content is defined with a combination of header_main and of header. The following table is a proposal of standard values.
header_main | header | Chunk | description | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 0x01 | A | Temperature. signed integer 16bits. 1 LSB = 0.01°C. 0: 0°C; 1: +0.01°C; 0xFFFF : -0.01°C | ||||||||||||||||||||||||
0 | 2 0x02 | A | Relative Humidity. unsigned integer 16bits. 1 LSB = 0.01°RH | ||||||||||||||||||||||||
0 | 3 0x03 | A | Oxygen concentration. 1 LSB = 0.001% | ||||||||||||||||||||||||
0 | 4 0x04 | A | CO2 concentration. 1 LSB = 0.001% | ||||||||||||||||||||||||
0 | 5 0x05 | A | Second temperature. signed integer 16bits. 1 LSB = 0.01°C. 0: 0°C; 1: +0.01°C; 0xFFFF : -0.01°C | ||||||||||||||||||||||||
0 | 6 0x06 | A | Pressure. unsigned integer 16bits. 1 LSB = 0.5mbar | ||||||||||||||||||||||||
0 | 7 0x07 | A | analog channel #0. 1 LSB = 1 uA | ||||||||||||||||||||||||
0 | 8 0x08 | A | analog channel #1. 1 LSB = 1 uA | ||||||||||||||||||||||||
0 | 9 0x09 | A | analog channel #2. 1 LSB = 1 uA | ||||||||||||||||||||||||
0 | 10 0x0A | A | analog channel #3. 1 LSB = 1 uA | ||||||||||||||||||||||||
0 | 11 0x0B | A | digital inputs state | ||||||||||||||||||||||||
0 | 12 0x0C | A | relative pulse counter 0 | ||||||||||||||||||||||||
0 | 13 0x0D | A | relative pulse counter 1 | ||||||||||||||||||||||||
0 | 14 0x0E | A | relative pulse counter 2 | ||||||||||||||||||||||||
0 | 15 0x0F | A | pH. unsigned integer, 16 bits. 1 LSB = 0.01 [pH] | ||||||||||||||||||||||||
0 | 16 0x10 | A | analog channel #0. 1 LSB = 1 mV | ||||||||||||||||||||||||
0 | 17 0x11 | A | analog channel #1. 1 LSB = 1 mV | ||||||||||||||||||||||||
0 | 18 0x12 | A | analog channel #2. 1 LSB = 1 mV | ||||||||||||||||||||||||
0 | 19 0x13 | A | analog channel #3. 1 LSB = 1 mV | ||||||||||||||||||||||||
0 | 20 0x14 | A | MES - Matieres en suspension. unsigned integer 16 bits. 1 LSB = 0.001 [g/L]. max 65.535 g/L | ||||||||||||||||||||||||
0 | 21 0x15 | A | NTU/FNU unsigned integer 16 bits. 1 LSB = 0.01 [NTU] . Max 655.35 NTU | ||||||||||||||||||||||||
0 | 22 0x16 | A | Oxygène dissous. unsigned integer 16 bits. 1 LSB = 0.01 [mg/L] . Max 655.35 mg/L | ||||||||||||||||||||||||
0 or 1 | 96 0x60 |
D | Battery voltageif (value>=81) Volt = 4.2 + (value-80) * 0.1 else Volt = 1.8 + value * 0.03 |
||||||||||||||||||||||||
1 | 97 0x61 |
D | M-BUS meter status byte | ||||||||||||||||||||||||
0 or 1 | 128 0x80 | B | timestamp of the measurement. unsigned integer 32 bits. UNIX timestamp | ||||||||||||||||||||||||
1 | 129 0x81 | B | Main energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 1.8.0) | ||||||||||||||||||||||||
1 | 130 0x82 | B | Serial number. unsigned integer 32bits. Serial number of the meter | ||||||||||||||||||||||||
1 | 131 0x83 | B | First tariff energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 1.8.1) | ||||||||||||||||||||||||
1 | 132 0x84 | B | Second tariff energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 1.8.2) | ||||||||||||||||||||||||
1 | 133 0x85 | B | Main energy index. IEEE754 floating point. Unit : m3 for water meter | ||||||||||||||||||||||||
1 | 134 0x86 | B | Main energy index. IEEE754 floating point. Unit : m3 for uncorrected gaz meters | ||||||||||||||||||||||||
1 | 135 0x87 | B | Flow temperature. IEEE754 floating point. Unit : °C | ||||||||||||||||||||||||
1 | 136 0x88 |
B | absolute pulse counter 0. unsigned integer 32bits | ||||||||||||||||||||||||
1 | 137 0x89 |
B | absolute pulse counter 1. unsigned integer 32bits | ||||||||||||||||||||||||
1 | 138 0x8A |
B | Power register. IEEE754 floating point. Unit W. | ||||||||||||||||||||||||
1 | 139 0x8B |
B | Volume index. IEEE754 floating point. Unit: m3 for heat meter | ||||||||||||||||||||||||
1 | 140 0x8C |
B | Return flow temperature. IEEE754 floating point. Unit: °C | ||||||||||||||||||||||||
1 | 141 0x8D |
B | Volume flow. IEEE754 floating point. Unit: m3/h | ||||||||||||||||||||||||
1 | 142 0x8E |
B | Production main energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 2.8.0) | ||||||||||||||||||||||||
1 | 143 0x8F |
B | Production first energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 2.8.1) | ||||||||||||||||||||||||
1 | 144 0x90 |
B | Production second energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 2.8.2) | ||||||||||||||||||||||||
1 | 150 0x96 |
B | Uncorrected volume index. IEEE754 floating point. Unit: m3 for electronic gas volume corrector EVC | ||||||||||||||||||||||||
1 | 151 0x97 |
B | Uncorrected spare volume index. IEEE754 floating point. Unit: m3 for electronic gas volume corrector EVC | ||||||||||||||||||||||||
1 | 152 0x98 |
B | Corrected volume index. IEEE754 floating point. Unit: m3 for electronic gas volume corrector EVC | ||||||||||||||||||||||||
1 | 153 0x99 |
B | Corrected spare volume index. IEEE754 floating point. Unit: m3 for electronic gas volume corrector EVC | ||||||||||||||||||||||||
1 | 154 0x9A |
B | Main energy index. IEEE754 floating point. Unit : kWh for heat meters | ||||||||||||||||||||||||
1 | 155 0x9B |
B | Mass. IEEE754 floating point. Unit : kg for heat meters | ||||||||||||||||||||||||
1 | 164 0xA4 |
B | Pressure. IEEE754 floating point. Unit : mbar | ||||||||||||||||||||||||
0 | 171 0xAB |
B | Fluorometer lamp 1. IEEE754 floating point. Unit: mV | ||||||||||||||||||||||||
0 | 172 0xAC |
B | Fluorometer lamp 2. IEEE754 floating point. Unit: mV | ||||||||||||||||||||||||
0 | 173 0xAD |
B | Fluorometer lamp 3. IEEE754 floating point. Unit: mV | ||||||||||||||||||||||||
0 | 174 0xAE |
B | Fluorometer lamp 4. IEEE754 floating point. Unit: mV | ||||||||||||||||||||||||
1 | 192 0xC0 | C | ZMD410 profil. First is timestamp (32bits unix) followed by either 1, 2 or 3 float16 values. The values definition and number are dependant of the ZMD410 configuration. Their encoding is float16 (see below). The first value represents to the first field of the profil, the second value (if any) represents the second field,... | ||||||||||||||||||||||||
1 | 200 0xC8 | C | M-BUS data chunk. | ||||||||||||||||||||||||
1 |
201 0xC9 |
C |
For water meter status information + Last read index + array of index differences (delta)
Status information: length: 8-bits format:
Last index is 32-bit IEEE754 floating point MBS first value followed by n 16-bit float16 "delta" (as described in the chapter "Type definition", section "float16 type" after the present table). Note that if the "delta" value is 0xFFFF, it means that its value is invalid. The first value is the most recent value. The second value is the second most recent value ... and so on. Note that if the most recent value (the index) is invalid (because we couldn't read the meter properly for example), it will be replaced by only 2 bytes 0xFFFF value. The valid index might (or not) be inserted later in the data or replaced by 0xFFFF. Once a valid index has been provided, only delta values are provided in the data. This means that if the float32 (IEEE754) value starts with 0xFFFF, it is an invalid delta (and the index might appear somewhere else )
See "Profile decoding" in the "Example" section after the present table. |
||||||||||||||||||||||||
1 |
202 0xCA |
C |
Format similar to header 201, except that this header is used gas meter |
||||||||||||||||||||||||
1 | 224 0xE0 | C | Index of the FastForward EnergyCam module. | ||||||||||||||||||||||||
1 | 229 0xE5 | C | SNR of the FastForward EnergyCam module. |
If you intend to use this specification or if you have comments, please inform me.
The goal of the float16 type is to encode small and large values using only 16-bit. Of course this is not as efficient as IEEE754 but it already gives interesting possibilites. Only positive values are accepted. Values in range 0 to 181930 are converted.
The two most significant bits define a decimal range (0.001, 0.2, 1, 5) (exponent), while the 14 less significant bits defines the value (mantisse). Use the following code to decode the values:
left = (value >> 14) & 0x03;
value0 = value & 0x3FFF;
result = (float32) value0;
switch(left)
{
case 0:
result = result * 0.001;
break;
case 1:
result = result * 0.02;
result = result + 16.38;
break;
case 3:
result = result * 5;
result = result + 16725;
break;
case 2:
default:
result = result + 344;
break;
}
Example index without delta:
01 80 5b 6d 63 b0 82 00 12 d6 87 ca 0b 00 43 2a 00 00 ff ff ff ff ff ff
01 main header
80 timestamp
5b 6d 63 b0 UNIX timestamp = 2018-08-10 12:06:40 GMT+2
82 serial number
00 12 d6 87 hexa =1234567 decimal
ca header = uncorrected gas meter
0b size = 11. Unit: bytes
00 conf = 0000 0000 = acq interval of 3600 seconds (1 hour) & no battery error & 0 = no other type of error
43 2a 00 00 index IEE754 Floating point MSB first = 170 decimal. Unit: m3
ff ff delta 1
ff ff delta 2
ff ff delta 3
Example with delta:
01 80 5b 6d 68 68 82 00 12 d6 87 ca 0b 00 43 34 00 00 02 58 01 2c 00 64
01 main header
80 timestamp
5b 6d 68 68 2018-08-10 12:26:48 GMT+2
82
00 12 d6 87 hexa =1234567 decimal
ca header
0b size = 11
00 conf = 0000 0000 = acq interval of 3600 seconds (1 hour) & no battery error & 0 = no other type of error
43 34 00 00 = index IEE754 Floating point MSB first = 180 decimal. Unit: m3
02 58 delta 1 hex value = 0000 0010 0101 1000 binary
left = (value >> 14) & 0x03;
this means: (0000 0010 0101 1000 >> 14) == 00
then apply the "and" mask
00
&11
---------------
result: 00
value0 = value & 0x3FFF;
0000 0010 0101 1000
& 0011 1111 1111 1111
result: 0000 0010 0101 1000
result = 0b0000001001011000 = 0x258 =0d600
result = (float32) value0;
result = (float32) 0d600;
result = 600.00
switch (left)
case 0
result = result / 100.0;
=> result = 600.00/100.00 == 6.00
Delta 1 = 6.00 m3
As last index = 180 m3
The previous index can be calculated as last index – delta 1 = 180 – 6 = 174 m3and it was the index reas 1 hour ago as conf == 00