python工業互聯網監控項目實戰2—OPC
OPC(OLE for Process Control)定義:指為了給工業控制系統應用程式之間的通訊建立一個介面標準,在工業控制設備與控制軟體之間建立統一的數據存取規範。它給工業控制領域提供了一種標準數據訪問機制,將硬體與應用軟體有效地分離開來,是一套與廠商無關的軟體數據交換標準介面和規程,主要解決過程式控制制系統與其數據源的數據交換問題,可以在各個應用之間提供透明的數據訪問。實際項目中「設備」就變成一個可以訪問的OPC Server和它的Tag位號值,更多的詳情請參考OPC基金會官網://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結果。//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>
調試運行//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));
現在重新調試運行並瀏覽監控介面//127.0.0.1:8090/tank4C9/動態效果如下:
1.5. 小結
本小節我們演示了如何在功能不變的模式下重構程式碼來實現功能的迭代和推進,過程中始終貫穿功能不變的前提下重構程式碼的結構來滿足新迭代功能的要求,然後再改變程式碼功能讀取OPC服務tag位號值。最終調整了Json的數據封裝格式和實時設備數據從設備OPC Server中獲取,也演示了從技術探索原型到生產原型的程式碼迭代過程。下一節我們將把ajax輪詢演進到通過websocket來實現UI端的數據刷新,提高數據刷新的效率。