目 錄 1. 概述... 2 2. 平臺演示... 2 3. 控制端與iNeuKernel的交互協議... 3 4. 設備驅動實現控制業務... 4 5. 應用效果... 9 5.1 CS客戶端... 9 5.2 BS瀏覽器... 9 5.3 Linux環境測試... 10 5.4 視頻應用效果.. ...
目 錄
1. 概述... 2
2. 平臺演示... 2
3. 控制端與iNeuKernel的交互協議... 3
4. 設備驅動實現控制業務... 4
5. 應用效果... 9
5.1 CS客戶端... 9
5.2 BS瀏覽器... 9
5.3 Linux環境測試... 10
5.4 視頻應用效果... 10
>>iNeuKernel v2.3版本下載:https://pan.baidu.com/s/1nxpnC7FazBBVyK9zUFgjyg
1. 概述
2019年6月,iNeuOS發佈第一個版本以來,實際合作的客戶和在談合作的客戶,對於雲端控制或雲端修改參數的需求比較多,基本上是共識。將來5G的發展和應用,雲端控制將是一個常態,在iNeuOS的規劃中已經作為一項重要工作。之所以沒有早期開發雲端控制部分,是因為我們所在的工業領域(煤炭、鋼鐵、化工、電力等)是重工業,與互聯網傳輸數據都有嚴格的限制,更不可能讓雲端控制,另外涉及到安全問題。
大部分雲端控制的需求涉及行業一般為環保、農業、電工裝備等,業務需求一般是遠程修改參數和控制一些開關狀態,但是這些操作不會帶來致命事故,更多的是從遠程運維角度考慮的需求。
現在iNeuKernel(設備容器)物聯網核心組件,已經具備了遠程式控制制服務功能,支持終端設備或軟體以Socket或WebSocket通道協議,通過標準的文本協議與硬體或感測進行交互,實現遠程修改參數和控制的目的。後續會把這項功能集成到iNeuView(Web組態)視圖建模,可以通過組態頁面操作實現遠程式控制制。
參見以前的文章:
《4種通訊模式機制》
2. 平臺演示
線上演示:http://demo.ineuos.net (註:伺服器比較慢,請耐心等待。自已註冊用戶,體驗系統功能)
視頻演示:http://www.ineuos.net/video/iNeuOS%20and%20app.mp4
驅動開發:http://www.ineuos.net/index.php/products/ineukernel-15.html (v2.1版本)
手機APP:http://demo.ineuos.net/app/ineuos_app.apk
3. 控制端與iNeuKernel的交互協議
控制端可以理解為iNeuView組態,控制操作通過交互協議與後臺的iNeuKernel進行交互,進一步與設備驅動交互,對設備進行控制操作,當然其他終端的操作鏈路也是這樣的。示意,如下圖:
交互協議充分考慮了系統命令和設備命令兩種情況,一個是對後臺服務進行遠程式控制制,一個是對設備進行控制,綜合完成遠程運維業務需求。示意,如下圖:
4. 設備驅動實現控制業務
以Modbus RTU通訊協議為例,實現遠程式控制制業務需求。IRunDevice介面有一個RunServiceConnector函數介面接收控制端發來的交互信息,交互信息是一個DevicePacket協議包。
註:具體代碼事例,可以加物聯網&大數據技術群:54256083,找群主。
(1)DevicePacket設備協議包轉換成JSON格式
"DevicePacket": { "OperationCode": "20200206202127025", "DeviceId": "92b2306385f749d494a9b24f469cac87", "DeviceName": "Modbus", "Desc": "", "DeviceFrames": [ { "TagId": "79be2b1e790f4c06873a8446bca755ea", "TagName": "tag1", "DataType": "int", "Value": "true", "FrameId": "20200206202127032", "OperationType": "setack", "Code": "200", "Desc": "淇敼鎴愬姛", "Time": "2020-02-06T20:21:27.0322772+08:00" } ] }
(2)RunServiceConnector函數介面接收設備協議包
/// <summary> /// 與服務(Service)交互使用的介面,與service.OnServiceConnector配合使用。 /// </summary> /// <param name="fromService"></param> /// <param name="toDevice"></param> /// <param name="asyncService"></param> /// <returns></returns> public override IServiceConnectorCallbackResult RunServiceConnector(IFromService fromService, IServiceToDevice toDevice, AsyncServiceConnectorCallback asyncService) { if(!(toDevice.Object is DevicePacket)) { OnDeviceRuningLog("RunServiceConnector 接收到的為非 DevicePacket 對象"); return null; } //設置優先調用此設備驅動 this.DevicePriority = DevicePriority.Priority; //接收過來的設備協議包 this._devicePacket = (DevicePacket)toDevice.Object; //非同步返回操作結果,把操作最終的結果反饋給代理服務,最終通知操作端 this._asyncServiceConnectorCallback = asyncService; //設置為當前為接收狀態 this._sendCommandState = SendCommandState.Received; OnDeviceRuningLog("已經接收到命令交換信息,正在準備下發命令......"); return new ServiceConnectorCallbackResult(true, null); }
(3)GetConstantCommand()函數介面獲得下發控制命令
if (_sendCommandState == SendCommandState.Received) //發送命令 { #region 構建發送命令 if (_devicePacket != null) { #region _sendCommandState = SendCommandState.ReadySending; foreach (DeviceFrame df in _devicePacket.DeviceFrames) { ITag tag = tags.Where(t => t.TagId == df.TagId && t.TagName == df.TagName).FirstOrDefault(); if (tag != null) { IModbusMessage requestMsg = null; byte[] reqeustBytes = null; switch (tag.Function) { case 0x01: //線圈,bool值 reqeustBytes = _modbusRtuMaster.BuildWriteSingleCoilCommand(byte.Parse(tag.SlaveId), ushort.Parse(tag.Address), bool.Parse(df.Value), out requestMsg); break; case 0x03: //保持寄存器,數值 reqeustBytes = _modbusRtuMaster.BuildWriteSingleRegisterCommand(byte.Parse(tag.SlaveId), ushort.Parse(tag.Address), ushort.Parse(df.Value), out requestMsg); break; default: OnDeviceRuningLog("沒有找到可寫入命令的標簽配置"); break; } if (reqeustBytes != null) { requestList.Add(new RequestInfo(reqeustBytes, new SendObject(requestMsg, tag))); } } } _sendCommandState = SendCommandState.Sending; #endregion } else { _sendCommandState = SendCommandState.None; } #endregion }
(4)Communicate接收控制命令返回結果
byte[] revData = info.Data; IModbusMessage requestMessage = _sendObject.ModbusMessage; ITag tag = _sendObject.Tag; //用於驗證修改值返回數據 bool modiftyData = false; //是否修改返回數據 bool validate = true; //驗證是否通過 if(requestMessage.FunctionCode == Modbus.Modbus.WriteSingleCoil) { modiftyData = true; try { _modbusRtuMaster.ValidateWriteSingleCoilResponse(revData, requestMessage); } catch(Exception ex) { validate = false; OnDeviceRuningLog(ex.Message); } } else if(requestMessage.FunctionCode==Modbus.Modbus.WriteSingleRegister) { modiftyData = true; try { _modbusRtuMaster.ValidateWriteSingleRegisterResponse(revData, requestMessage); } catch (Exception ex) { validate = false; OnDeviceRuningLog(ex.Message); } } if(modiftyData) { if (_devicePacket != null) { DeviceFrame df = _devicePacket.DeviceFrames.Where(t => t.TagId == tag.TagId).FirstOrDefault(); if (df != null) { if (validate) //正常 { df.OperationType = "setack"; df.Code = "200"; df.Desc = "修改成功"; _modifyConfirm.Add(df.TagId, true); } else { df.OperationType = "setack"; df.Code = "-1"; df.Desc = "修改失敗"; } OnDeviceRuningLog(String.Format("{0},{1}!!!", tag.TagName, df.Desc)); if (_asyncServiceConnectorCallback != null) { _asyncServiceConnectorCallback.Invoke(_devicePacket); } } else { OnDeviceRuningLog("獲得修改設備幀數據為空"); } bool modifyComplete = true; foreach(DeviceFrame d in _devicePacket.DeviceFrames) { modifyComplete=_modifyConfirm.ContainsKey(d.TagId); if(!modifyComplete) { break; } } if(modifyComplete) { _devicePacket = null; _asyncServiceConnectorCallback = null; _modifyConfirm.Clear(); _sendCommandState = SendCommandState.Complete; OnDeviceRuningLog("修改參數已全部完成!!!"); } } }
5. 應用效果
5.1 CS客戶端
5.2 BS瀏覽器
5.3 Linux環境測試
5.4 視頻應用效果
文章:
《.NET Core開發的iNeuOS工業互聯網平臺,發佈 iNeuDA 數據分析展示組件,快捷開發圖形報表和數據大屏》
《[視頻演示].NET Core開發的iNeuOS物聯網平臺,實現從設備&PLC、雲平臺、移動APP數據鏈路閉環 》
《.NET Core開發的iNeuOS物聯網平臺部署樹霉派(raspbian),從網關到雲端整體解決方案》
《.NET Core開發的iNeuOS物聯網平臺部署在Ubuntu操作系統,無縫跨平臺》
《iNeuOS 物聯網雲操作系統2.0發佈,集成設備容器、視圖建模、機器學習三大模塊 》
物聯網&大數據技術 QQ群:54256083
物聯網&大數據合作 QQ群:727664080
聯繫QQ:504547114
合作微信:wxzz0151