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 端的数据刷新, 提高数据刷新的效率.
来源: https://www.cnblogs.com/haozi0804/p/12696459.html