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