不久前億佰特小編發(fā)布在《串口服務(wù)器接入阿里云物模型》一文中通過(guò)編寫(xiě)TPC-7062(MCGS腳本)的腳本程序解析Alink JSON數(shù)據(jù),從而實(shí)現(xiàn)阿里云物模型采集控制RTU設(shè)備。
本文將介紹另一種方式實(shí)現(xiàn)阿里云物模型控制RTU設(shè)備,之前是通過(guò)設(shè)備進(jìn)行數(shù)據(jù)解析,因此開(kāi)發(fā)者既需要了解MCGS腳本程序還需要了解Modbus協(xié)議導(dǎo)致使用門(mén)檻較高,而本文使用方法無(wú)需使用設(shè)備解析Alink JSON數(shù)據(jù),因此不需要編寫(xiě)MCGS腳本從而降低是使用門(mén)檻。
小編將通過(guò)物模型查詢(xún)RTU設(shè)備的保持寄存器(0x0000)的值講解如何實(shí)現(xiàn)該功能。
串口服務(wù)器一臺(tái)用于連接MQTT服務(wù)器,本例程的從機(jī)將通過(guò)Modbus Slave仿真實(shí)現(xiàn)(方便觀察數(shù)據(jù)變化);
可上網(wǎng)路由器一臺(tái);
網(wǎng)線兩根,一根連接串口服務(wù)器與路由器,一根連接電腦與路由器;
電腦一臺(tái),用于配置串口服務(wù)器以及調(diào)試云平臺(tái);
MQTTX調(diào)試工具(https://mqttx.app/zh),用于接入前數(shù)據(jù)幀分析;
Modbus Slave仿真工具(https://www.modbustools.com/),用于Modbus RTU從機(jī)仿真;
億佰特網(wǎng)絡(luò)配置工具(http://hivx.cn/product/1465.html,相關(guān)下載),用于配置串口服務(wù)器,可以不適應(yīng)軟件通過(guò)網(wǎng)頁(yè)配置,由于設(shè)備采用DHCP獲取本機(jī)IP,因此采用上位機(jī)配置更為方便;
第一次使用阿里云的數(shù)據(jù)解析功能,并且這是筆者第一次使用JavaScript(ECMAScript 5)編寫(xiě)腳本,因此接下的云平臺(tái)配置都將參考阿里云幫助中性的最佳實(shí)例下的“設(shè)備通過(guò)DTU接入物聯(lián)網(wǎng)平臺(tái)”進(jìn)行開(kāi)發(fā),建議開(kāi)發(fā)者仔細(xì)閱讀阿里云手冊(cè)可以發(fā)現(xiàn)不一樣的世界,活學(xué)活用里面案例能對(duì)初學(xué)者有很好的引導(dǎo)和啟發(fā)。
1.產(chǎn)品創(chuàng)建
這次創(chuàng)建的產(chǎn)品和以往的不同不能無(wú)腦點(diǎn)擊下一步,需要調(diào)整數(shù)據(jù)收發(fā)協(xié)議為“透?jìng)?/span>/自定義”,如下圖:
其余參數(shù)保持默認(rèn)。
2.設(shè)備創(chuàng)建
在產(chǎn)品詳情下的功能定義目錄下點(diǎn)擊“編輯草稿”,選擇添加自定義功能;
一共需要添加兩個(gè)自定義功能,一個(gè)用于保存寄存器值(左圖),一個(gè)用于物模型發(fā)起讀取指令;
這里需要分析下Modbus響應(yīng)數(shù)據(jù)幀,0103020064320C,可以看到響應(yīng)幀只有地址用于標(biāo)記,未標(biāo)記寄存器地址,因此只有在平臺(tái)對(duì)收發(fā)數(shù)據(jù)進(jìn)行標(biāo)記,本例程重點(diǎn)介紹連接使用不需要考慮標(biāo)記,保留接口待后續(xù)使用。因此在定義功能時(shí)使用枚舉變量。
復(fù)制參考實(shí)例的腳本,并調(diào)整部分配置,如下:
var ALINK_ID = "12345";
var ALINK_VERSION = "1.1";
var ALINK_PROP_POST_METHOD = 'thing.event.property.post';
var ALINK_PROP_SET_METHOD = 'thing.service.property.set';
/*此函數(shù)將設(shè)備上報(bào)數(shù)據(jù)轉(zhuǎn)換為Alink JSON物模型數(shù)據(jù)。*/
function rawDataToProtocol(bytes) {
? ?/*將設(shè)備上報(bào)的原始數(shù)據(jù)轉(zhuǎn)換為數(shù)組。其中bytes對(duì)象中存儲(chǔ)著設(shè)備上報(bào)原始數(shù)據(jù)。*/
? ?var uint8Array = new Uint8Array(bytes.length);
? ?for (var i = 0; i < bytes.length; i++) {
? ? ? ?uint8Array[i] = bytes[i] & 0xff;
? ?}
? ?var params = {}; ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 定義屬性存放對(duì)象。
? ?var jsonMap = {}; ? ? ? ? ? ? ? ? ? ? ? ? ? // 定義模擬Alink數(shù)據(jù)報(bào)對(duì)象。
? ?/*填寫(xiě)Alink數(shù)據(jù)報(bào)協(xié)議頭部分。*/
? ?jsonMap['version'] = ALINK_VERSION; ? ? ? ? // Alink 協(xié)議版本號(hào)。
? ?jsonMap['id'] = ALINK_ID; ? ? ? ? ? ? ? ? ? // 消息ID。
? ?jsonMap['method'] = ALINK_PROP_POST_METHOD; // 設(shè)備上行數(shù)據(jù)方法:設(shè)備屬性上報(bào)。
/*填寫(xiě)Alink數(shù)據(jù)報(bào)屬性部分。*/
//0103020064320c
? ?params['register'] = uint8Array[3]*265+ uint8Array[4]; ? ? ? ? ? ?// 將收到的第一和第二字節(jié)轉(zhuǎn)換為十進(jìn)制數(shù)存儲(chǔ)。
? ?jsonMap['params'] = params; ? ? ? ? ? ? ? ? // 將參數(shù)打包到數(shù)據(jù)幀中。
? ?return jsonMap; ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 返回結(jié)果會(huì)發(fā)送給物聯(lián)網(wǎng)平臺(tái)。
}
//以下是部分輔助函數(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);
}
/*此函數(shù)實(shí)現(xiàn)由物聯(lián)網(wǎng)平臺(tái)下發(fā)數(shù)據(jù)轉(zhuǎn)換為設(shè)備能識(shí)別的16進(jìn)制數(shù)。*/
function protocolToRawData(json)
{
? ?var method = json['method'];
? ?var id = json['id'];
? ?var version = json['version'];
? ?var payloadArray = [];
? ?if (method == ALINK_PROP_SET_METHOD) ? ?// 接收來(lái)自物聯(lián)網(wǎng)平臺(tái)的“設(shè)置設(shè)備屬性”的命令。
? ?{
? ? ? ?var send_params = json['params'];
? ? ? ?var prop_cur = send_params['READ_R']; ? // 將設(shè)置的具體值抽取出來(lái)。
? ? ? ?//按照自定義協(xié)議格式拼接rawdata。
//0103000000018833
? ? ? ?payloadArray = payloadArray.concat(buffer_uint8(0x01));
payloadArray = payloadArray.concat(buffer_uint8(0x03));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x01));
payloadArray = payloadArray.concat(buffer_uint8(0x88));//校驗(yàn)錯(cuò)誤,但保留錯(cuò)誤,引導(dǎo)學(xué)習(xí)如何分析問(wèn)題,見(jiàn)“從機(jī)仿真”,正確校驗(yàn)0x840A
payloadArray = payloadArray.concat(buffer_uint8(0x33));//
? ?}
? ?return payloadArray; ? ?// 返回時(shí),將數(shù)據(jù)發(fā)送至設(shè)備端。
}
function transformPayload(topic, rawData) {
? ?var jsonObj = {};
? ?return jsonObj;
}
將上述腳本粘貼到“產(chǎn)品詳情”下的“數(shù)據(jù)解析”,如圖所示:
腳本語(yǔ)言測(cè)試與提交
測(cè)試數(shù)據(jù)上報(bào)功能,如下圖所示:
測(cè)試數(shù)據(jù)下發(fā)功能,如下圖所示:
測(cè)試完成點(diǎn)擊“提交”,自此云平臺(tái)腳本與產(chǎn)品配置完成。
使用MQTT X軟件連接MQTT服務(wù)器進(jìn)行測(cè)試,配置如下:
查詢(xún)“訂閱”“發(fā)布”的地址,如下圖所示:
平臺(tái)發(fā)送讀取請(qǐng)求,如下圖所示:
MQTT X發(fā)送響應(yīng)幀,如下圖所示:
通過(guò)調(diào)試軟件可以更加直觀的對(duì)數(shù)據(jù)幀進(jìn)行分析,若發(fā)現(xiàn)數(shù)據(jù)幀錯(cuò)誤可以更加方便定位問(wèn)題,這里是沒(méi)有錯(cuò)誤的可進(jìn)入下一步串口服務(wù)器演示。
串口服務(wù)器參數(shù)配置,如下圖所示:
從機(jī)仿真
Modbus Slave并非免費(fèi)軟件,可免費(fèi)試用30天,若有長(zhǎng)時(shí)間使用需求請(qǐng)購(gòu)買(mǎi)正版授權(quán)。
點(diǎn)擊“Connection”配置連接參數(shù),選擇“Serial Port”,并配置正確端口與匹配的波特率參數(shù),如下圖所示:
配置仿真軟件的保持寄存器值,如下圖所示:
物模型發(fā)送查詢(xún)指令,仿真從機(jī)收到云平臺(tái)下發(fā)指令,仿真設(shè)備未響應(yīng),檢查發(fā)現(xiàn)之前使用的校驗(yàn)工具沒(méi)有配置正確導(dǎo)致校驗(yàn)錯(cuò)誤。
修改腳本中關(guān)于校驗(yàn)的兩位,注意需要先調(diào)試才能提交生效。
修改后再次發(fā)送,如下圖所示:
效果演示,如下圖所示: