Payload Format
Codec
A complete LoRaWAN payload codec with examples can be found in the TBD section. See also Decoder example for reference.
Overview
The payload of up and downlink messages consists of an arbitrary number of data structs (DS) of different types and lengths.
DS 1 | DS 2 | ... | DS n |
---|---|---|---|
Each data struct is a combination of a header and the actual data payload:
L | T | payload |
---|---|---|
The header consists of two fields:
Field | Description |
---|---|
L | Length of data struct, 1 byte, not including the length byte itself |
T | Data struct type, 1 byte |
Data Encoding
Signed integers use two’s complement for encoding.
Important
Unless otherwise noted, payloads will use little endian data encoding.
Uplinks
There are three distinct uplink payloads:
- Button Press
- Regular Status Message
- Firmware Hash
Important
All uplinks are sento to LoRaWAN port 15.
Button Press
On every button press a message is sent to the network. The button press message is either sent confirmed or unconfirmed depending on current settings. The message consists of two data sections: Button state and Used charge
Button State
The message reports to different button state bit fields. The first field represents the activating button(s), which is the button that has been registered first. Only one bit will be set if ambiguous button press is off. If it is set to on one or more bits might be set, indicating, that more than one button has been pressed at the same time. Only activated buttons will be reported.
After the button debounce time has passed, a second reading of all active buttons will is taken and reported int the bit field second reading.
Byte | Size | Description | Format |
---|---|---|---|
0 | 1 | Message length (0x04) | uint8 |
1 | 1 | Message type (0x01) | uint8 |
2 | 1 | Bit mask representing active buttons: Bit 0..3: Bit mask for first button press (N E S W) Bit 4..7: Bit mask for all buttons pressed (N E S W) |
Bitfield |
3-4 | 2 | Counter since last reset (little endian) | uint16 |
For all bit fields, buttons are encoded as in
Bit (within bit field) | Button |
---|---|
0 | North (N), top |
1 | East (E), right |
2 | South (S), bottom |
3 | West (W), left |
Used Charge
Rough approximation of used charge in uAh since last reset.
Byte | Size | Description | Format |
---|---|---|---|
0 | 1 | Message length (0x05) | uint8 |
1 | 1 | Message type (0x02) | uint8 |
2-5 | 4 | Used charge in uAh (little endian) | uint32 |
Example
Payload 04:01:51:A5:00:05:02:20:12:00:00 is reporting
Field | Value |
---|---|
First Button | N (0b0001) |
All Buttons | NS (0b0101) |
Button Count | 165 |
Used Charge | 4640 uAh |
First button that has been pressed is 'N' (top). Upon sending 'N' and 'S' buttons have been pressed. Total button count since reset is 165. Used charge since reset is 4640 uAh.
Status Message
The device sends a regular status messages at a configurable interval. The status message is always unconfirmed, regardless of the settings.
The Status message can be used to detect low batteries. An miro Click will stop working at 1.8V. 2.0V is therefore a good value to use for critical battery alerts. It may be useful to already create an alert at around 2.4V, in order to know when the device slowly reaches low battery levels.
The status message consists of the following data structs. Please note, depending on the LoRaWAN region, not all data structs may be present.
Used Charge
See data section used charge above.
Battery Voltage and Temperature
Report current battery voltage and MCU temperature.
Byte | Size | Description | Format |
---|---|---|---|
0 | 1 | Message length (0x03) | uint8 |
1 | 1 | Message type (0x03) | uint8 |
2 | 1 | Current battery Voltage in 10 mV with an offset of 170. To calculate volts: (x + 170)/100 | uint8 |
3 | 1 | Current MCU temperature in °C | uint8 |
Current Configuration
Report current configuration.
Byte | Size | Description | Format |
---|---|---|---|
0 | 1 | Message length (0x05) | uint8 |
1 | 1 | Message type (0x04) | uint8 |
2 | 1 | Bit mask representing active buttons: Bit 4..7: RFU Bit 0..3: Button N E S W |
Bitfield |
3 | 1 | Flags, bitwise or combination: Bit 7 = Confirmed uplinks (0 = off, 1 = on) Bit 6 = Buzzer (0 = off, 1 = on) Bit 5 = Dury Cycle (0 = off, 1 = on) Bit 4 = Amigious button press (0 = off, 1 = on) Bit 3 = Join strategy (0 = fast DR, 1 = slow DR) Bits 0-2: RFU |
Bitfield |
4-5 | 2 | Status interval in minutes | uint16 |
Example
Payload 05:02:10:00:00:00:03:03:AA:28:05:04:0F:F8:A0:05 is reporting the following values
Parameter | Value |
---|---|
Used Charge | 16 uAh |
Battery Voltage | 3.4 V |
Internal Temperature | 40° C |
Button Configuration | 0x0F -> All buttons enabled |
Configuration Flags | 0b11111100 -> Everything enabled |
Status Message Intervall | 1440 minutes (1 day) |
Firmware Hash
The firmware hash message is sent once after successfully joining the network. The hash value can be used to identify the current firmware version of the device
Byte | Size | Description | Format |
---|---|---|---|
0 | 1 | Message length (0x05) | uint8 |
1 | 1 | Message type (0x05) | uint8 |
2-5 | 4 | Firmware hash | uint32 |
Example
Payload 05:05:23:52:D6:59 is reporting git hash value 59d65223
Downlinks
Downlink messages are used to change the configuration of the device. They use the same general payload format as uplinks.
Important
All downlinks must be sent on the LoRaWAN port 3!
Device Configuration
The device configuration message type is used to set general device configuration.
Message type T = 0x80 and length L = 0x06.
Byte | Size | Description | Format |
---|---|---|---|
0 | 1 | Message lenght (0x06) | uint8 |
1 | 1 | Message type (0x81) | uint8 |
2 | 1 | Button configuration mask: Bit 4..7: RFU Bit 0..3: Button N E S W |
Bitfield |
3 | 1 | Flags, combination of: Bit 7 = Confirmed uplinks (0 = off, 1 = on) Bit 6 = Buzzer (0 = off, 1 = on) Bit 5 = Duty Cycle (0 = off, 1 = on) Bit 4 = Ambiguous button press (0 = off, 1 = on) Bit 3 = Join strategy (0 = fast DR, 1 = slow DR) Bit 2 = Force join (0 = off, 1 = on) Bits 0-1: RFU |
Bitfield |
4-5 | 2 | Status interval in minutes | uint16 |
6 | 1 | Button debounce time in milliseconds | uint8 |
Example
Payload 06:81:0F:F8:A0:05:1E will set the following config on the device
Parameter | Value |
---|---|
Flags | Duty Cycle: On Buzzer: On Confirmed uplinks: On Join Strategy: slowest DR Ambigious First Press: On |
Status interval | 1440 minutes (1 day, 0x05A0) |
Button Debounce Time | 30 ms |
Decoder example
function decodeMiroClick(fPort, bytes) {
// Decode an uplink message from a buffer
// (array) of bytes to an object of fields.
var decoded = {};
function map(button) {
r = "";
if (button & 1) r += "N";
if (button & 2) r += "E";
if (button & 4) r += "S";
if (button & 8) r += "W";
return r;
}
if (fPort == 15) {
n = bytes.length;
idx = 0;
while (n > idx) {
s = bytes[idx++];
decoded.type = bytes[idx];
if (bytes[idx] == 1) {
decoded.buttons_first = map(bytes[idx + 1] & 0xF);
decoded.buttons = map((bytes[idx + 1] >> 4) & 0xF);
decoded.count = bytes[idx + 2] + (bytes[idx + 3] << 8);
} else if (bytes[idx] == 2) {
decoded.uah = bytes[idx + 1] + (bytes[idx + 2] << 8) + (bytes[idx + 3] << 16) + (bytes[idx + 4] << 24);
} else if (bytes[idx] == 3) {
decoded.iTemp = bytes[idx + 2];
decoded.vBatt = (bytes[idx + 1] + 170) / 100.0;
} else if (bytes[idx] == 4) {
decoded.buttonCfg = map(bytes[idx + 1] & 0xF);
decoded.flags = bytes[idx + 2].toString(16);
decoded.statusCycle = bytes[idx + 3] + (bytes[idx + 4] << 8);
} else if (bytes[idx] == 5) {
decoded.firmwareHash = (bytes[idx + 1] + (bytes[idx + 2] << 8) + (bytes[idx + 3] << 16) + (bytes[idx +4] << 24)).toString(16);
}
idx += s;
}
}
return decoded;
}