OPC(OLE for Process Control)定義:指為了給工業控制系統應用程序之間的通信建立一個接口標准,在工業控制設備與控制軟件之間建立統一的數據存取規范。它給工業控制領域提供了一種標准數據訪問機制,將硬件與應用軟件有效地分離開來,是一套與廠商無關的軟件數據交換標准接口和規程,主要解決過程控制系統與其數據源的數據交換問題,可以在各個應用之間提供透明的數據訪問。實際項目中“設備”就變成一個可以訪問的OPC Server和它的Tag位號值,更多的詳情請參考OPC基金會官網:http://opcfoundation.cn/。
上一小節我們首先通過一個簡單的json格式來完成數據到UI端的傳輸,UI端解析Json數據,並通過JQuery渲染到div上來完成數據的顯示,最后ajax輪詢實現了數據的實時刷新。本小節我們把Domo進一步迭代改進,首先規范數據傳輸的格式,然后,實現實時讀取模擬OPC Server的tag位號值。
1.1. 界面UI與Json數據結構
采用面向對象的模式來定義數據傳輸Json格式,“設備”對象包含多個“tag”屬性值。上一小節例子中,我們從后台獲取的數據格式是一個Json字符串,只定義了tank4C9的相關屬性。
tank4C9={ 'Status': random.randint(0,1), #設備運行狀態 'OverheadFlow':random.randint(1,10) ,#'頂流量', 'ButtomsFlow': random.randint(1,10), #'低流量' 'Power': random.randint(10000,100000), #功率 }
實際項目中的監控界面會涉及到多個設備和多個監控tag位號,為了便於數據的規范管理和更新,Json數據格式構造采用面向對象的模式進行構建如下:
tank4C9={ 'DeviceId': 1, 'DeviceName':'1#反應罐', 'Status': random.randint(0,1), #設備運行狀態 'OverheadFlow':random.randint(1,10) ,#'頂流量', 'ButtomsFlow': random.randint(1,10), #'低流量' 'Power': random.randint(10000,100000), #功率 }
Json代碼就構建了一個圖例反應罐主要監控數據,注意多出來的設備狀態點,也就是用來體現設備是運行狀態還是停機狀態。另外,為了體現這個設備來自那個一個OPC Server服務,更好地體現現場設備與采集器(OPC Server)的關系,再增加一層關於采集器的Json結構python代碼如下:
tank4C9={ 'DeviceId': 1, 'DeviceName':'1#反應罐', 'Status': random.randint(0,1), #設備運行狀態 'OverheadFlow':random.randint(1,10) ,#'頂流量', 'ButtomsFlow': random.randint(1,10), #'低流量' 'Power': random.randint(10000,100000), #功率 } Collector={ 'CollectorId': 1, 'CollectorName':'1#采集器', 'Status': 0, 'DeviceList':[tank4C9], }
從上述代碼的數據關系上,我們能看出來設備“1#反應罐”屬於“1#采集器”,數據采集器本身也有自己的設備運行狀態位號,來標識采集設備自身是否正常運行。
1.2. 重構Collector APP代碼
接下來我們重構Collector APP代碼,增加一個getCollectorData函數來返回連接器數據。
1.Collector APP views 增加函數getCollectorData代碼如下:
def getCollectorData(request): tank4C9={ 'DeviceId': 1, 'DeviceName':'1#反應罐', 'Status': random.randint(0,1), #設備運行狀態 'OverheadFlow':random.randint(1,10) ,#'頂流量', 'ButtomsFlow': random.randint(1,10), #'低流量' 'Power': random.randint(10000,100000), #功率 } Collector={ 'CollectorId': 1, 'CollectorName':'1#采集器', 'Status': 0, 'DeviceList':[tank4C9], } return HttpResponse( json.dumps(Collector));
2.修改項目urls文件urlpatterns ,發布getCollectorData path
from django.urls import path from Collector import views urlpatterns = [ # Uncomment the next line to enable the admin: #path('admin/', admin.site.urls) path('getTank4C9Data/', views.getTank4C9Data), path('getCollectorData/', views.getCollectorData), ]
項目調試狀態我們可以通過瀏覽器直接訪問url查看webAPI結果。http://127.0.0.1:8090/getCollectorData/
注意:Json數據格式的變化,圖中數據體現出了基於面向對象模式的層次結構“1#采集器”下面有一個包含的“設備對象列表”DeviceList屬性。
1.3. 修改UI代碼
現在修改tank4C9.html文件里面的getData異步獲取數據函數代碼修改為讀取上面getCollectorData函數如下:
<script> //JQuery 代碼入口 $(document).ready(function(){ setInterval("getData()",1000); }); function getData() { //模擬異步從后台獲得值 $.ajax({ url: "/getCollectorData/", success: function (result) { data = JSON.parse(result); tank4C9=data.DeviceList[0] $("#OverheadFlow").html(tank4C9.OverheadFlow); $("#ButtomsFlow").html(tank4C9.ButtomsFlow); $("#Power").html(tank4C9.Power); }}); } </script>
調試運行http://127.0.0.1:8090/tank4C9/ UI同樣的實時自動刷新后台數據的瀏覽效果。
重點:代碼重構的要點的功能不變的情況下,優化代碼結構。
代碼的結構優化,優先保證功能不變,盡量不要試圖在一次迭代中引入過多的變量,這樣只會導致編程工作雜亂無章的進行。Json格式代碼重構完成后,接下來我們把代碼調整成讀取OPC Server服務的Tag點。
1.4. 從OPC Server讀取Tag值
現在我們重構getCollectorData函數代碼,通過OPC服務讀取真正的設備值,當然dome的例子是讀取一個模擬OPC服務,實際項目中讀取設備發布的OPC服務即可,代碼如下:
<script> def getCollectorData(request): tank4C9={ 'DeviceId': 1, 'DeviceName':'1#反應罐', 'Status': 0, #設備運行狀態 'OverheadFlow':0 ,#'頂流量', 'ButtomsFlow': 0, #'低流量' 'Power': 0, #功率 } import OpenOPC opc = OpenOPC.client() opc.connect('Matrikon.OPC.Simulation') tank4C9['OverheadFlow']= opc['Random.Int1'] tank4C9['ButtomsFlow']= opc['Random.Int2'] tank4C9['Power']= opc['Random.Int4'] opc.close() Collector={ 'CollectorId': 1, 'CollectorName':'1#采集器', 'Status': 0, 'DeviceList':[tank4C9], } return HttpResponse( json.dumps(Collector));
現在重新調試運行並瀏覽監控界面http://127.0.0.1:8090/tank4C9/動態效果如下:
1.5. 小結
本小節我們演示了如何在功能不變的模式下重構代碼來實現功能的迭代和推進,過程中始終貫穿功能不變的前提下重構代碼的結構來滿足新迭代功能的要求,然后再改變代碼功能讀取OPC服務tag位號值。最終調整了Json的數據封裝格式和實時設備數據從設備OPC Server中獲取,也演示了從技術探索原型到生產原型的代碼迭代過程。下一節我們將把ajax輪詢演進到通過websocket來實現UI端的數據刷新,提高數據刷新的效率。