LoRaWAN設備與物聯網平臺的通信數據格式為透傳/自定義,因此需要使用消息解析腳本,解析上下行數據。本文以LoRaWAN溫濕度傳感器為例,介紹LoRaWAN設備消息解析腳本的編輯和調試方法。
步驟一:編輯腳本
- 在物聯網平臺控制臺,創建連網方式為LoRaWAN的產品。
- 為該產品定義物模型。功能定義具體方法,請參見單個添加物模型。
本示例中,定義了以下屬性、事件和服務:
表 1. 屬性 標識符 數據類型 取值范圍 讀寫類型 Temperature int32 -40~55 讀寫 Humidity int32 1~100 讀寫 表 2. 服務 標識符 調用方式 輸入參數 SetTempHumiThreshold 異步 四個輸入參數,數據類型均為int32: - 溫度過高告警閾值(標識符:MaxTemp)
- 溫度過低告警閾值(標識符:MinTemp)
- 濕度過高告警閾值(標識符:MaxHumi)
- 濕度過低告警閾值(標識符:MinHumi)
表 3. 事件 標識符 事件類型 輸入參數 TempError 告警 溫度Temperature HumiError 告警 濕度Humidity - 編寫腳本。
在物聯網平臺控制臺,產品詳情頁面的消息解析頁簽下,選擇腳本語言,編寫腳本。
支持的腳本語言 設備自定義數據格式轉Alink JSON格式數據的函數(上行通信) Alink JSON格式數據轉為設備自定義數據格式的函數(下行通信) JavaScript(ECMAScript 5) rawDataToProtocol protocolToRawData Python 2.7 raw_data_to_protocol protocol_to_raw_data PHP 7.2 rawDataToProtocol protocolToRawData 本文示例的語言為JavaScript(ECMAScript 5)。
腳本中,解析下行數據的函數protocolToRawData中,需設定輸出結果的起始三個字節,用于指定下行端口號和下行消息類型。否則,系統會丟掉下行幀。 設備實際接收的數據中不會包含這三個字節。
表 4. 下行數據解析輸出結果起始三字節 LoRa Downlink 字節數 說明 DFlag 1 固定為0x5D。 FPort 1 下行端口號。 DHDR 1 可選: - 0:表示 “Unconfirmed Data Down”數據幀。
- 1:表示 “Confirmed Data Down”數據幀。
例如,
0x5D 0x0A 0x00
表示下行幀端口號為10,數據幀為“Unconfirmed Data Down”。完整的示例腳本Demo,請參見本文附錄:示例腳本。
步驟二: 在線測試腳本
在數據解析編輯器中,使用模擬數據測試腳本。
- 設備上報數據模擬解析 。
在模擬輸入框中,選擇模擬類型為設備上報數據,輸入模擬數據000102,單擊運行。
運行結果為:
{ "method": "thing.event.property.post", "id": "12345", "params": { "Temperature": 1, "Humidity": 2 }, "version": "1.1" }
- 設備接收數據模擬解析 。
選擇模擬類型為設備接收數據,輸入以下JSON格式的下行模擬數據,單擊運行。
{ "method": "thing.service.SetTempHumiThreshold", "id": "12345", "version": "1.1", "params": { "MaxTemp": 50, "MinTemp": 8, "MaxHumi": 90, "MinHumi": 10 } }
運行結果為:
0x5d0a000332085a0a
步驟三:提交腳本
確認腳本可以正確解析數據后,單擊提交,將該腳本提交到物聯網平臺系統,以供數據上下行時,物聯網平臺調用該腳本解析數據。
說明 僅提交后的腳本才能被物聯網平臺調用;草稿狀態的腳本不能被調用。
步驟四:使用真實設備調試
腳本提交后,正式使用之前,請使用真實設備進行測試。LoRaWAN節點設備如何發送和接收數據,請參見模組廠商的相關手冊。
- 測試LoRaWAN設備上報溫濕度屬性。
- 使用設備端發送數據,例如000102。
- 在該設備的設備詳情頁 頁簽下,查看設備上報的屬性數據。
- 測試LoRaWAN設備上報事件。
- 使用設備端發送事件數據,如,溫度告警數據0102,或濕度告警數據0202。
- 在該設備的設備詳情頁 頁簽下,查看設備上報的事件數據。
- 測試調用LoRaWAN設備服務。
- 在物聯網平臺控制臺,選擇 。
- 選擇要調試的產品和設備,并選擇調試真實設備,功能選擇為溫度濕度閾值(SetTempHumiThreshold),輸入以下數據后,單擊發送指令。
{ "MaxTemp": 50, "MinTemp": 8, "MaxHumi": 90, "MinHumi": 10 }
- 檢查設備端是否接收到服務調用命令。
- 在該設備的設備詳情頁 頁簽下,查看設備服務調用數據。
附錄:示例腳本
根據以上產品和其功能定義,編輯的示例腳本如下:
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';
/*
* 示例數據:
* 傳入參數:
* 000102 // 共3個字節
* 輸出結果:
* {"method":"thing.event.property.post", "id":"12345", "params":{"Temperature":1,"Humidity":2}, "version":"1.1"}
* 傳入參數:
* 0102 // 共2個字節
* 輸出結果:
* {"method":"thing.event.TempError.post","id":"12345","params":{"Temperature":2},"version":"1.1"}
* 傳入參數:
* 0202 // 共2個字節
* 輸出結果:
* {"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;
}
/*
* 示例數據:
* 傳入參數:
* {"method":"thing.service.SetTempHumiThreshold", "id":"12345", "version":"1.1", "params":{"MaxTemp":50, "MinTemp":8, "MaxHumi":90, "MinHumi":10}}
* 輸出結果:
* 0x5d0a000332085a0a
*/
function protocolToRawData(json)
{
var id = json['id'];
var method = json['method'];
var version = json['version'];
var payloadArray = [];
// 追加下行幀頭部。
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;
}
/**
* 將設備自定義Topic數據轉換為JSON格式數據,設備上報數據到物聯網平臺時調用。
* 入參:topic,字符串,設備上報消息的Topic。
* 入參:rawData,byte[]數組,不能為空。
* 出參:jsonObj,對象,不能為空。
*/
function transformPayload(topic, rawData) {
var jsonObj = {}
return jsonObj;
}
// 以下是部分輔助函數。
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);
}