Parse LoRaWAN device messages
LoRaWAN devices communicate with IoT Platform using a pass-through or custom data format. This communication method requires a data parsing script to parse uplink and downlink data. This topic uses a LoRaWAN temperature and humidity sensor as an example to demonstrate how to edit and test a data parsing script.
Step 1: Edit the script
- In the IoT Platform console, create a product. Set the connection method to LoRaWAN.
- Define a Thing Specification Language (TSL) model for the product. For more information about how to define features, see Add a TSL model for a single product.
In this example, the following properties, events, and services are defined:
Table 1. Properties Identifier Data type Value range Read/Write type Temperature int32 -40 to 55 Read/Write Humidity int32 1 to 100 Read/Write Table 2. Services Identifier Invocation method Input parameters SetTempHumiThreshold Asynchronous Four input parameters. All are int32 data type: - High temperature alert threshold (Identifier: MaxTemp)
- Low temperature alert threshold (Identifier: MinTemp)
- High humidity alert threshold (Identifier: MaxHumi)
- Low humidity alert threshold (Identifier: MinHumi)
Table 3. Events Identifier Event type Input parameters TempError Alert Temperature HumiError Alert Humidity - Write the script.
In the IoT Platform console, go to the product details page. On the Message Parsing tab, you can select a scripting language and write the script.
Supported scripting languages Function to transform custom device data to Alink JSON format (uplink communication) Function to transform Alink JSON format to custom device data format (downlink communication) JavaScript (ECMAScript 5) rawDataToProtocol protocolToRawData Python 2.7 raw_data_to_protocol protocol_to_raw_data PHP 7.2 rawDataToProtocol protocolToRawData This example uses JavaScript (ECMAScript 5).
In the script, the protocolToRawData function parses downlink data. The first three bytes of the output must be set to specify the downlink port number and the downlink message type. If these bytes are not set, the system discards the downlink frame. The device does not receive these three bytes.
Table 4. First three bytes of the downlink data parsing output LoRa Downlink Bytes Description DFlag 1 Fixed value of 0x5D. FPort 1 The downlink port number. DHDR 1 Optional: - 0: Unconfirmed Data Down frame.
- 1: Confirmed Data Down frame.
For example,
0x5D 0x0A 0x00indicates that the downlink port is 10 and the data frame is Unconfirmed Data Down.For the complete sample script, see Appendix: Sample script in this topic.
Step 2: Test the script online
In the data parsing editor, you can use simulated data to test the script.
- Simulate parsing of data reported by a device.
In the Input Simulation box, set the simulation type to Device-reported Data. Enter the simulated data 000102 and click Run.
The result is:
{ "method": "thing.event.property.post", "id": "12345", "params": { "Temperature": 1, "Humidity": 2 }, "version": "1.1" } - Simulate parsing of data received by a device.
Set the simulation type to Device-received Data. Enter the following downlink simulated data in JSON format and click Run.
{ "method": "thing.service.SetTempHumiThreshold", "id": "12345", "version": "1.1", "params": { "MaxTemp": 50, "MinTemp": 8, "MaxHumi": 90, "MinHumi": 10 } }The result is:
0x5d0a000332085a0a
Step 3: Submit the script
After you confirm that the script can parse data correctly, click Submit to submit the script to the IoT Platform system. IoT Platform then calls the script to parse uplink and downlink data.
Step 4: Test with a real device
After you submit the script, test it with a real device before you use it in a production environment. For information about how LoRaWAN nodes send and receive data, see the manual from your module manufacturer.
- Test property reporting for the LoRaWAN device.
- Use the device to send data, such as 000102.
- On the Device Details page for the device, navigate to the tab to view the reported property data.
- Test event reporting for the LoRaWAN device.
- Use the device to send event data, such as temperature alert data 0102 or humidity alert data 0202.
- On the Device Details page for the device, navigate to the tab to view the reported event data.
- Test service invocation for the LoRaWAN device.
- In the IoT Platform console, choose .
- Select the product and device that you want to test. Select Debug Real Device. For Function, select Temperature and Humidity Threshold (SetTempHumiThreshold). Enter the following data and click Send Command.
{ "MaxTemp": 50, "MinTemp": 8, "MaxHumi": 90, "MinHumi": 10 } - Check if the device received the service invocation command.
- On the Device Details page for the device, navigate to the tab to view the service invocation data.
Appendix: Sample script
The following sample script is created based on the product and its feature definitions:
var ALINK_ID = "12345";
var ALINK_VERSION = "1.1";
var ALINK_PROP_POST_METHOD = 'thing.event.property.post';
var ALINK_EVENT_TEMPERR_METHOD = 'thing.event.TempError.post';
var ALINK_EVENT_HUMIERR_METHOD = 'thing.event.HumiError.post';
var ALINK_PROP_SET_METHOD = 'thing.service.property.set';
var ALINK_SERVICE_THSET_METHOD = 'thing.service.SetTempHumiThreshold';
/*
* Sample data:
* Input parameter:
* 000102 // 3 bytes
* Output result:
* {"method":"thing.event.property.post", "id":"12345", "params":{"Temperature":1,"Humidity":2}, "version":"1.1"}
* Input parameter:
* 0102 // 2 bytes
* Output result:
* {"method":"thing.event.TempError.post","id":"12345","params":{"Temperature":2},"version":"1.1"}
* Input parameter:
* 0202 // 2 bytes
* Output result:
* {"method":"thing.event.HumiError.post","id":"12345","params":{"Humidity":2},"version":"1.1"}
*/
function rawDataToProtocol(bytes)
{
var uint8Array = new Uint8Array(bytes.length);
for (var i = 0; i < bytes.length; i++)
{
uint8Array[i] = bytes[i] & 0xff;
}
var params = {};
var jsonMap = {};
var dataView = new DataView(uint8Array.buffer, 0);
var cmd = uint8Array[0]; // command
if (cmd === 0x00)
{
params['Temperature'] = dataView.getInt8(1);
params['Humidity'] = dataView.getInt8(2);
jsonMap['method'] = ALINK_PROP_POST_METHOD;
}
else if (cmd == 0x01)
{
params['Temperature'] = dataView.getInt8(1);
jsonMap['method'] = ALINK_EVENT_TEMPERR_METHOD;
}
else if (cmd == 0x02)
{
params['Humidity'] = dataView.getInt8(1);
jsonMap['method'] = ALINK_EVENT_HUMIERR_METHOD;
}
else
{
return null;
}
jsonMap['version'] = ALINK_VERSION;
jsonMap['id'] = ALINK_ID;
jsonMap['params'] = params;
return jsonMap;
}
/*
* Sample data:
* Input parameter:
* {"method":"thing.service.SetTempHumiThreshold", "id":"12345", "version":"1.1", "params":{"MaxTemp":50, "MinTemp":8, "MaxHumi":90, "MinHumi":10}}
* Output result:
* 0x5d0a000332085a0a
*/
function protocolToRawData(json)
{
var id = json['id'];
var method = json['method'];
var version = json['version'];
var payloadArray = [];
// Append the downlink frame header.
payloadArray = payloadArray.concat(0x5d);
payloadArray = payloadArray.concat(0x0a);
payloadArray = payloadArray.concat(0x00);
if (method == ALINK_SERVICE_THSET_METHOD)
{
var params = json['params'];
var maxtemp = params['MaxTemp'];
var mintemp = params['MinTemp'];
var maxhumi = params['MaxHumi'];
var minhumi = params['MinHumi'];
payloadArray = payloadArray.concat(0x03);
if (maxtemp !== null)
{
payloadArray = payloadArray.concat(maxtemp);
}
if (mintemp !== null)
{
payloadArray = payloadArray.concat(mintemp);
}
if (maxhumi !== null)
{
payloadArray = payloadArray.concat(maxhumi);
}
if (minhumi !== null)
{
payloadArray = payloadArray.concat(minhumi);
}
}
return payloadArray;
}
/**
* Transforms custom topic data from a device into JSON format. This function is called when a device reports data to IoT Platform.
* Input parameter: topic, a string that specifies the topic of the message reported by the device.
* Input parameter: rawData, a byte[] array. Cannot be empty.
* Output parameter: jsonObj, an object. Cannot be empty.
*/
function transformPayload(topic, rawData) {
var jsonObj = {}
return jsonObj;
}
// The following are helper functions.
function buffer_uint8(value)
{
var uint8Array = new Uint8Array(1);
var dv = new DataView(uint8Array.buffer, 0);
dv.setUint8(0, value);
return [].slice.call(uint8Array);
}
function buffer_int16(value)
{
var uint8Array = new Uint8Array(2);
var dv = new DataView(uint8Array.buffer, 0);
dv.setInt16(0, value);
return [].slice.call(uint8Array);
}
function buffer_int32(value)
{
var uint8Array = new Uint8Array(4);
var dv = new DataView(uint8Array.buffer, 0);
dv.setInt32(0, value);
return [].slice.call(uint8Array);
}
function buffer_float32(value)
{
var uint8Array = new Uint8Array(4);
var dv = new DataView(uint8Array.buffer, 0);
dv.setFloat32(0, value);
return [].slice.call(uint8Array);
}References
- To learn basic information such as the message parsing flow, see What is message parsing?.
- For information about parsing messages from custom topics, see Submit a message parsing script.
- For information about calling an API to send messages to a device, see APIs for TSL models and APIs for message communication.
- For information about how to troubleshoot data parsing issues, see Troubleshooting.