Quick Start Guide
Prerequisites
To get startet you need:
- Access to a LoRaWAN® network server (LNS), such as Loriot
- A LoRaWAN® gateway which is online, in range and using the same frequency plan as the miro Cargo. The frequency plan of your miro Cargo depends on the region it was commissioned for (EU868, US915, AU915 or AS923). Of course, the gateway also has to be registered with your LNS.
Registration
Acquire the LoRaWAN® keys of the miro Cargo (DevEUI, AppEUI and AppKey). If you did not receive the keys from Miromico AG directly, you should be able to retrieve them from our database. The process of how to download your specific device keys is described on our DevEUI management docs page. You will need the DevEUI of at least one device of your shipment to access the keys. The DevEUI of a miro Cargo is printed on the bottom of the device.
Register the miro Cargo on your LoRaWAN® network server using the following settings:
- LoRaWAN® version: 1.0.3
- Device type: Class A
- Frequency plan / region: EU868, US915, AU915 or AS923
- DevEUI, AppEUI and AppKey: Use the keys you acquired in the previous step
Setup
Before the first use, the battery pull-tab inside the miro Cargo needs to be removed. Open the housing of the miro Cargo by removing the 4 screws on top (yellow boxes in the picture below) with a standard Phillips screwdriver.
Remove the lid and remove the battery pull-tab from the battery compartment.
Once the pull tab is removed, the miro Cargo boots which is indicated by 3 short beeps and the LED being g reen for 10 seconds.
After boot, the miro Cargo tries to join to a LoRaWAN® network using its keys. If it joins successfully,
it makes one long beep and the LED is white for 1 second. This only works if the miro Cargo was registered on a
LoRaWAN® network server before (see section <
Ensure the miro Cargo joined before closing the housing again. Tighten the screws firmly to ensure the best possible sealing.
Messages
Once the miro Cargo joined successfully, check the LoRaWAN® messages which were received by the chosen LoRaWAN® network server. After joining, the miro Cargo first sends a welcome message on port 100. Afterwards, it sends a git hash message on port 212.
If you shake the miro Cargo slightly, it will start the acquisition of a GPS fix. Once a GPS fix is acquired, the miro Cargo sends a location message on port 103. If the payload of the location message is zero, no GPS fix could be acquired. This happens mostly because the miro Cargo has no clear view of the sky, for example, if it is inside a building. In this case, place the miro Cargo somewhere outside the building and shake it again slightly.
The GPS reception of the miro Cargo is best if the miro Cargo label is facing the sky as in the picture below.
Refer to payload section for more details.
Decoding your first location message
Once a non-zero location message is received on port 103, you can decode the payload of message by opening this
online JavaScript interpreter and copying the
javascript-decoder-snippet below into the script.js
window.
Replace payload_base64
or payload_hex
at the end of the snippet by the actual payload of the location message you
received. Ensure to use double quotes around the encoded payload. The decoded location message will be printed in
the console
window.
{
"gps_date": 110123,
"gps_time": 145627,
"gps_latitude": 47.38537,
"gps_longitude": 8.53793,
"gps_altitude": 578.9,
"unixtime_ms": 1673445387000
}
Example
Example output if payload_base64
is AAGuKwACONsASE3pAA0HIQAA4iI=
:
You can enter the latitude and longitude of the decoded payload in the search bar of Google Maps or OpenStreetMap to see the location of the miro Cargo.
Ideally, this process is automated such that the location messages are decoded automatically and the location of the miro Cargo is displayed on a map.
JavaScript Decoder snippet
The following code snippet decodes a miro Cargo location message. The payload format of a location message is described here.
function base64ToHex(str) {
var raw = atob(str);
let result = '';
for (let i = 0; i < raw.length; i++) {
var hex = raw.charCodeAt(i).toString(16);
result += (hex.length === 2 ? hex : '0' + hex);
}
return result;
}
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
function getTimestamp(ddmmyy, hhmmss) {
day = parseInt(ddmmyy / 10000, 10);
month = parseInt(ddmmyy / 100 - day * 100, 10);
year = parseInt(ddmmyy - month * 100 - day * 10000 + 2000, 10);
hour = parseInt(hhmmss / 10000, 10);
minute = parseInt(hhmmss / 100 - hour * 100, 10);
second = parseInt(hhmmss - minute * 100 - hour * 10000, 10);
date = new Date(year, month - 1, day, hour, minute, second)
return date.valueOf();
}
function Decode(bytes) {
// Decode an uplink message from a buffer
// (array) of bytes to an object of fields.
var decoded = {};
// location message
// returns date and time as DDMMYY and HHMMSS
// returns latitude, longitude and altitude as float
// input example: 0002717900024c6e00396fc4fff44f9500001d7e
var dat = (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]) >>> 0;
var tim = (bytes[4] << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7]) >>> 0;
var lat = (bytes[8] << 24 | bytes[9] << 16 | bytes[10] << 8 | bytes[11]) >>> 0;
var lon = (bytes[12] << 24 | bytes[13] << 16 | bytes[14] << 8 | bytes[15]) >>> 0;
var alt = (bytes[16] << 24 | bytes[17] << 16 | bytes[18] << 8 | bytes[19]) >>> 0;
// conversion to signed integer (2's complement)
if (lat > 0x7FFFFFFF) {
lat = -(0xFFFFFFFF - lat + 1);
}
if (lon > 0x7FFFFFFF) {
lon = -(0xFFFFFFFF - lon + 1);
}
if (alt > 0x7FFFFFFF) {
alt = -(0xFFFFFFFF - alt + 1);
}
if ((lat != 0) && (lon != 0)) {
var ts = getTimestamp(dat, tim);
decoded = {
gps_date: dat,
gps_time: tim,
gps_latitude: (lat / 100000.0),
gps_longitude: (lon / 100000.0),
gps_altitude: (alt / 100.0),
unixtime_ms: ts,
};
}
return decoded;
}
var payload_base64 = "AAGuKwACONsASE3pAA0HIQAA4iI="
var payload_hex = base64ToHex(payload_base64);
var bytes = hexToBytes(payload_hex);
var decoded = Decode(bytes);
console.log();
console.log(JSON.stringify(decoded, null, 2));