Loriot
Qubitro and Loriot integration.
Loriot offers distributed LoRaWAN® infrastructure and an easy-to-use software platform. This guide will help you integrate the Loriot LoRaWAN server with Qubitro.

Getting started

You can easily integrate your Loriot devices with Qubitro in several steps. All you have to do is follow our guide steps.

Creating a Project

First, if you don't have any current project, you need to create a new one to get the Target URL and Custom "Authorization" header value. These two credentials are essential for our integration steps.
You can get your credentials under the Settings tab if you have a project already going on.
After logging in to our portal, click on the new project from the top left.

Getting Credentials

When you choose devices, make sure that you select Loriot.
Then there will be quick details about the integration process. After clicking continue, you will get credentials for your integration. You can easily copy it right away or find it under the credentials tab from the left bar any time you need it.
Now switch to the Loriot application page to paste these values into the corresponding fields.

Add Integration on Loriot

Jump to the application you want to sync with Qubitro and click Output on the left menu.
Click Add new output and choose HTTP Push. You can also edit existing output if you already created one.
Paste credentials into the corresponding fields.

Observe Devices and Customize Device Data

Refresh the device list and make sure all devices are synchronized.
If you want to make changes to your device information, click on settings and quickly customize your device photo, name, brand, etc. So you can keep your projects more organized.

Payload Formatters

Payload formatters allow you to process data going to and from end devices.
For Qubitro to be able to decode the sensor data coming from Loriot, you need to create an uplink payload formatter.
The example uplink payload formatter is shown below.
As seen below, the returned value must be a JSON object with the 'data' key and the function name must be 'decodeUplink' with a single parameter.
1
function decodeUplink(input) {
2
return {
3
data: {
4
temperature: input.bytes[0],
5
humidity: input.bytes[1]
6
},
7
warnings: [],
8
errors: []
9
};
10
}
Copied!

Creating Payload Formatter

To create a payload formatter for Uplink messages, you can click on any device and the Formatter tab.
As seen in the second screenshot below, the returned value must be a JSON object with the 'data' key and the function name must be 'decodeUplink' with a single parameter.
A complete and complex formatter example.
1
function decodeUplink(input)
2
{
3
// Decode an uplink message from a buffer
4
// (array) of bytes to an object of fields.
5
var decoded = {};
6
7
if (input.bytes == null)
8
return null;
9
10
if (input.port === 1)
11
{
12
if (input.bytes.length != 11)
13
return null;
14
15
decoded.type = "position";
16
17
decoded.latitudeDeg = input.bytes[0] + input.bytes[1] * 256 + input.bytes[2] * 65536 + input.bytes[3] * 16777216;
18
if (decoded.latitudeDeg >= 0x80000000) // 2^31
19
decoded.latitudeDeg -= 0x100000000; // 2^32
20
decoded.latitudeDeg /= 1e7;
21
22
decoded.longitudeDeg = input.bytes[4] + input.bytes[5] * 256 + input.bytes[6] * 65536 + input.bytes[7] * 16777216;
23
if (decoded.longitudeDeg >= 0x80000000) // 2^31
24
decoded.longitudeDeg -= 0x100000000; // 2^32
25
decoded.longitudeDeg /= 1e7;
26
27
decoded.inTrip = ((input.bytes[8] & 0x1) !== 0) ? true : false;
28
decoded.fixFailed = ((input.bytes[8] & 0x2) !== 0) ? true : false;
29
decoded.headingDeg = (input.bytes[8] >> 2) * 5.625;
30
31
decoded.speedKmph = input.bytes[9];
32
decoded.batV = input.bytes[10] * 0.025;
33
34
decoded.manDown = null;
35
36
// Clean up the floats for display
37
decoded.latitudeDeg = parseFloat(decoded.latitudeDeg.toFixed(7));
38
decoded.longitudeDeg = parseFloat(decoded.longitudeDeg.toFixed(7));
39
decoded.batV = parseFloat(decoded.batV.toFixed(3));
40
decoded.position = {
41
"value":1,
42
"context":{"lat":decoded.latitudeDeg, "lng":decoded.longitudeDeg}
43
};
44
}
45
else if (input.port === 4)
46
{
47
if ((input.bytes.length < 9) || (input.bytes.length > 11))
48
return null;
49
50
decoded.type = "position";
51
52
decoded.latitudeDeg = input.bytes[0] + input.bytes[1] * 256 + input.bytes[2] * 65536;
53
if (decoded.latitudeDeg >= 0x800000) // 2^23
54
decoded.latitudeDeg -= 0x1000000; // 2^24
55
decoded.latitudeDeg *= 256e-7;
56
57
decoded.longitudeDeg = input.bytes[3] + input.bytes[4] * 256 + input.bytes[5] * 65536;
58
if (decoded.longitudeDeg >= 0x800000) // 2^23
59
decoded.longitudeDeg -= 0x1000000; // 2^24
60
decoded.longitudeDeg *= 256e-7;
61
62
decoded.headingDeg = (input.bytes[6] & 0x7) * 45;
63
decoded.speedKmph = (input.bytes[6] >> 3) * 5;
64
65
decoded.batV = input.bytes[7] * 0.025;
66
67
decoded.inTrip = ((input.bytes[8] & 0x1) !== 0) ? true : false;
68
decoded.fixFailed = ((input.bytes[8] & 0x2) !== 0) ? true : false;
69
decoded.manDown = ((input.bytes[8] & 0x4) !== 0) ? true : false;
70
71
// Clean up the floats for display
72
decoded.latitudeDeg = parseFloat(decoded.latitudeDeg.toFixed(7));
73
decoded.longitudeDeg = parseFloat(decoded.longitudeDeg.toFixed(7));
74
decoded.batV = parseFloat(decoded.batV.toFixed(3));
75
decoded.position = {
76
"value":1,
77
"context":{"lat":decoded.latitudeDeg, "lng":decoded.longitudeDeg}
78
};
79
}
80
else if (input.port === 2)
81
{
82
if (input.bytes.length != 3)
83
return null;
84
85
decoded.type = "downlink ack";
86
87
decoded.sequence = (input.bytes[0] & 0x7F);
88
decoded.accepted = ((input.bytes[0] & 0x80) !== 0) ? true : false;
89
decoded.fwMaj = input.bytes[1];
90
decoded.fwMin = input.bytes[2];
91
}
92
else if (input.port === 3)
93
{
94
if (input.bytes.length != 11)
95
return null;
96
97
decoded.type = "stats";
98
99
decoded.initialBatV = (((input.bytes[0] & 0xF) !== 0) ? (4.0 + (input.bytes[0] & 0xF) * 0.100) : null);
100
decoded.txCount = 32 * ((input.bytes[0] >> 4) + (input.bytes[1] & 0x7F) * 16);
101
decoded.tripCount = 32 * ((input.bytes[1] >> 7) + (input.bytes[2] & 0xFF) * 2
102
+ (input.bytes[3] & 0x0F) * 512);
103
decoded.gpsSuccesses = 32 * ((input.bytes[3] >> 4) + (input.bytes[4] & 0x3F) * 16);
104
decoded.gpsFails = 32 * ((input.bytes[4] >> 6) + (input.bytes[5] & 0x3F) * 4);
105
decoded.aveGpsFixS = 1 * ((input.bytes[5] >> 6) + (input.bytes[6] & 0x7F) * 4);
106
decoded.aveGpsFailS = 1 * ((input.bytes[6] >> 7) + (input.bytes[7] & 0xFF) * 2);
107
decoded.aveGpsFreshenS = 1 * ((input.bytes[7] >> 8) + (input.bytes[8] & 0xFF) * 1);
108
decoded.wakeupsPerTrip = 1 * ((input.bytes[8] >> 8) + (input.bytes[9] & 0x7F) * 1);
109
decoded.uptimeWeeks = 1 * ((input.bytes[9] >> 7) + (input.bytes[10] & 0xFF) * 2);
110
}
111
112
return { data: decoded };
113
}
Copied!

Validate Payload Formatter

Working with Data

Once the payload formatter is set up correctly, it is possible to utilize all Qubitro features, including visualizing data and building custom applications with Qubitro APIs.

Visualizing Data

You can easily visualize your data with our widgets from the Monitoring section on the left side of our portal or under the analytics tab in your project.
Multiple charts are also can be added under a specific device. Also, you can quickly filter your data by clicking the calendar under Data or Analytics.

Support and Feedback

If you have further questions or suggestions, feel free to join
👇
-> Qubitro Community Forum -> Community Discord via this invitation link.