asyncua模块实现OPC UA通讯

2024-08-21 03:36
文章标签 模块 实现 通讯 ua opc asyncua

本文主要是介绍asyncua模块实现OPC UA通讯,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

asyncua是OPCUA的python实现,使用起来非常方便,其github地址是https://github.com/FreeOpcUa/opcua-asyncio

UaExpert是OPC UA Client的GUI工具,当编写好server代码后并运行,我们可以使用UaExpert去和server进行通信。UaExpert使用教程参考:https://blog.csdn.net/watsoncheung/article/details/124268979

1. OPCUA的两种工作方式

客户端/服务器模式:在这种模式下,OPC UA 客户端向 OPC UA 服务器请求数据,服务器接收请求并向客户端发送数据。

发布/订阅模式:在这种模式下,OPC UA 服务器将数据“发布”到网络上,而客户端可以“订阅”特定的数据。当服务器更新数据时,客户端会收到更新的数据。

这两种模式可以根据应用场景的需要进行选择。例如,客户端/服务器模式适用于客户端需要向服务器请求单个数据项的情况,而发布/订阅模式则适用于客户端需要定期接收大量数据的情况。

OPC UA Server示例代码:

import logging
import asyncio
from asyncua import Serverlogging.basicConfig(level=logging.INFO)
_logger = logging.getLogger('asyncua')async def main():# 创建serverserver = Server()# 初始化serverawait server.init()# 设置server的endpoint地址server.set_endpoint('opc.tcp://192.168.5.86:4840/freeopcua/server/')# 设置server的名字server.set_server_name('MyOPCUAServer')# 设置自己的namespace,也可以不做uri = 'http://examples.freeopcua.github.io'idx = await server.register_namespace(uri)# 在上面的namespace下添加一个对象,名叫MyObjectmyobj = await server.nodes.objects.add_object(idx, 'MyObject')# 在MyObject下添加一个变量,名叫MyVariable,初始值是6.7myvar = await myobj.add_variable(idx, 'MyVariable', 6.7)# 设置改变量为可写await myvar.set_writable()_logger.info('Starting server!')# 让server一直运行async with server:while True:await asyncio.sleep(1)if __name__ == '__main__':asyncio.run(main())

OPC UA Client示例代码:

import asyncio
from asyncua import Clientasync def main():url = 'opc.tcp://192.168.5.86:4840/freeopcua/server/'async with Client(url=url) as client:uri = 'http://examples.freeopcua.github.io'idx = await client.get_namespace_index(uri)var = await client.nodes.root.get_child(['0:Objects', f'{idx}:MyObject', f'{idx}:MyVariable'])print('My Variable', var, await var.read_value())if __name__ == '__main__':asyncio.run(main())

在asyncua模块中添加OPC UA(OLE for Process Control Unified Architecture)的发布订阅模式,通常涉及几个关键步骤:

  1. 创建OPC UA客户端:
  • 使用asyncua.Client类创建一个OPC UA客户端实例,并指定OPC UA服务器的URL。
  1. 创建订阅处理器:
  • 定义一个类作为订阅处理器,该类将处理从OPC UA服务器接收到的数据变化通知。
  • 在类中实现datachange_notification方法,该方法将在数据变化时被调用。
  1. 创建订阅:
  • 使用客户端实例的create_subscription方法创建一个订阅。
  • 传递订阅的发布间隔(以毫秒为单位)和之前定义的订阅处理器实例作为参数。
  1. 订阅节点:
  • 获取要订阅的OPC UA节点的引用。
  • 使用订阅实例的subscribe_data_change方法订阅这些节点。
  1. 处理订阅:
  • 在主循环中,使用await asyncio.sleep(some_interval)来保持程序运行,并允许异步事件(如数据变化通知)被处理。
  1. 异常处理和关闭:
  • 确保在退出程序时妥善处理任何异常,并正确关闭客户端和订阅。

发布/订阅模式,Client订阅数据改变代码示例:

from asyncua import Client, ua, Node  
import asyncio  class SubscriptionHandler:  def datachange_notification(self, node: Node, val, data):  print(f"Node '{node.nodeid}' value changed to {val}")  async def main():  url = 'opc.tcp://[OPC_UA_SERVER_IP]:[PORT]'  async with Client(url=url) as client:  handler = SubscriptionHandler()  subscription = await client.create_subscription(500, handler)  # 500ms 发布间隔  # 假设我们要订阅的节点ID  node_to_subscribe = "ns=2;s=SomeNodeToSubscribe"  node = client.get_node(node_to_subscribe)  await subscription.subscribe_data_change([node])  # 保持程序运行以接收通知  while True:  await asyncio.sleep(1)  if __name__ == "__main__":  asyncio.run(main())

2. OPC UA的一些基本概念

OPC UA地址空间中具有八种基本的节点类型,分别是数据节点、变量节点、对象节点、方法节点、引用节点、视图节点、变量类型和对象类型。每种节点对应的含义如图1所示。

数据类型节点(DataType)。数据类型节点描述了变量节点中变量的数据类型。在OPC UA信息模型在命名空间0中定义了多种内置的数据类型,包括整型、浮点型、字符串等多个类型,能对变量的数据进行准确的描述。也可以自定义数据类型,比如描述二维坐标的2DPoint,描述设备运行模式的MachieMode等类型,获得更符合数据本身的描述。

变量节点(Variable)。该节点是变量类型节点的实例,也是使用的最多的节点。客户端访问设备数据有3种方式。第一种是手动将设备多模态数据写入对应的变量节点,然后客户端读取对应节点内保存的数值。方式一缺点在于如果客户端要获取设备最新的值,需要一直手动去触发对设备数据源的读取请求。第二种方式通过给变量节点添加回调函数,在客户端发起读取请求后再由服务器向设备数据源发起读取请求,将取得的数据写入节点,再从节点读取数据发送到客户端中。方式二节省了无谓的读取消耗。第三种方式将客户端的读取请求直接重定向到设备的数据源中,即客户端直接从数据源获取数据,变量节点不存储数据。方式三缩减了数据先写入变量节点再进行读取的过程,但多个客户端连接访问同一数据时会增大服务器与设备之间的传输负载,而方式二中服务器可对时间戳进行判断后直接返回节点中保存的数据。在实际连接服务器与设备数据源的过程中,可以灵活结合方法二和方法三,方法一仅适用于极少数情况。

对象节点(Object)。将对象类型实例化即可得到对象节点,该节点是设备在数字空间的映射。所有对设备数据的访问都能在该模型中访问到对应的数据节点。所有对设备的控制都转换为方法节点的触发。设备产生的消息在节点对象中将触发对应的事件。

方法节点(Method)。方法节点是对设备控制方法在数字模型中的映射。方法节点可以通过服务器或客户端进行调用,然后将会对设备的控制器发送指令,使得设备执行对应的操作。常见的方法节点有,电机的正反转、点动、设备返回原点、伺服通断电等。

引用类型节点(ReferenceType)。引用类型描述了引用的语义,而引用用于定义引用两端的节点之间的关系。最常用的引用类型如层次结构引用节点(Organize),表示节点之间的层级关系,如同文件夹与文件夹内的文件;数据层级复杂的设备,需要通过多种引用类型对设备信息节点之间的关系进行描述。

视图节点(View)。视图节点可将地址空间中感兴趣的节点提取出来,作为一个子集,视图节点作为该子集的入口,方便客户端浏览。
变量类型节点(VariableType)。该节点提供了对变量节点的定义,是设备中各种数据的抽象。常用引用中的对象类型定义引用节点(HasTypeDefinition)连接数据类型节点,对数据类型进行描述。用属性引用节点(HasProperty)对数据的语义进行描述。也可以使用自定义的数据类型节点对变量的数据进行描述,具有灵活性。

对象类型节点(ObjectType)。提供对象的定义,即对象的抽象,与类相当,且子类可以继承父类的特征,方便模型的扩充。该节点包括对象的各种数据类型,数据的语义,以及控制方式。OPC UA命名空间0中规定了多个基础的对象类型节点。如使用最广的基础对象类型(BaseObjectType),所有对象类型节点都需要继承该节点再进行扩充。在对具体设备建模的过程中,应该将设备组成的各部分分解为不同的对象分别建模,再用引用节点将各部分按照实际设备中的关系相关联,从而得到完整设备的对象类型节点。

在这里插入图片描述

上述内容引用自专利《基于OPCUA协议的制造装备多模态数据智能解析方法》

OPC UA的建模实际上是节点与节点之间的引用,节点可以根据不同的用途归属于不同的节点类别。在OPC UA中,最重要的节点类别是对象、变量和方法。对象可以拥有变量和方法,而且可以触发事件。 (引用自专利《基于轨道交通的综合监控系统的事件存储方法及其设备》)

2.1 OPC UA的地址空间模型中,节点属性、变量和数据的区别

在OPC UA(OLE for Process Control Unified Architecture)的地址空间模型中,节点属性、变量和数据各自扮演着不同的角色,它们共同构成了OPC UA信息模型的基础。以下是关于这三者区别的详细解释:

  1. 节点属性(Attributes):
  • 定义:属性用于描述节点的基本信息和特性。它们提供了关于节点类型、名称、描述、访问级别等的元数据。
  • 特点:
    • 是节点的基本组成部分之一,每个节点都可以有多个属性。
    • 属性的值可以是各种数据类型,如字符串、整数、浮点数等。
    • 属性是静态的,即它们的值在节点创建时确定,并且通常不会在节点的生命周期内改变。
  • 作用:属性帮助客户端理解和使用节点,提供了关于节点功能和行为的上下文信息。
  1. 变量(Variables):
  • 定义:变量节点代表地址空间中的一个值,这个值可以被客户端读取、写入和订阅变化。
  • 特点:
    • 变量节点具有数据类型和值,数据类型定义了值的类型和格式。
    • 变量的值可以是简单的(如单个数值),也可以是复杂的(如结构体或数组)。
    • 变量的值在节点生命周期内是可以变化的,客户端可以实时获取这些变化。
  • 作用:变量用于表示工业自动化系统中的实时数据,如传感器读数、设备状态等。通过读取和写入变量值,客户端可以与服务器进行交互,实现数据的监控和控制。
  1. 数据(Data):
  • 定义:在OPC UA中,“数据”通常指的是存储在变量节点中的值。这些数据可以是任何类型的信息,包括实时测量值、配置参数、事件通知等。
  • 特点:
    • 数据是动态的,可以随着工业自动化系统的运行而实时变化。
    • 数据的类型和格式由变量节点的数据类型决定。
    • 数据可以被客户端读取、写入和订阅变化,以实现数据的实时处理和响应。
  • 作用:数据是工业自动化系统的核心组成部分,它反映了系统的实时状态和运行情况。通过处理和分析这些数据,可以实现系统的监控、控制、优化和决策等功能。

总结

  • 节点属性提供了关于节点的静态信息,用于描述节点的特性和行为。
  • 变量是地址空间中的动态元素,用于表示实时数据,并允许客户端与服务器进行交互。
  • 数据是存储在变量节点中的值,反映了工业自动化系统的实时状态和运行情况。

这三者共同构成了OPC UA地址空间模型的基础,为工业自动化系统中的通信和数据处理提供了强大的支持。

2.2 opcua节点类型枚举

opcua预定义的8种节点类型:
ObjectNode
ObjectTypeNode
VariableNode
VariableTypeNode
MethodNode
ReferenceTypeNode
DataTypeNode
ViewNode

2.3 opcua数据类型枚举

1. Null = 0
2. Boolean = 1
3. SByte = 2
4. Byte = 3
5. Int16 = 4
6. UInt16 = 5
7. Int32 = 6
8. UInt32 = 7
9. Int64 = 8
10. UInt64 = 9
11. Float = 10
12. Double = 11
13. String = 12
14. DateTime = 13
15. Guid = 14
16. ByteString = 15
17. XmlElement = 16
18. NodeId = 17
19. ExpandedNodeId = 18
20. StatusCode = 19
21. QualifiedName = 20
22. LocalizedText = 21
23. ExtensionObject = 222
4. DataValue = 23
25. Variant = 24
26. DiagnosticInfo = 25
#实例
1. ua.VariantType.Boolean
2. ua.VariantType.String
3. ua.VariantType.Int16
4. ua.VariantType.Int32
5. ua.VariantType.UInt32
6. ua.VariantType.Float
7. ua.VariantType.Byte

2.4 opcua节点规则

NodeId节点规则:ns=<命名空间索引>;<标识符类型>=<标识符>
命名空间索引:
ns表示命名空间索引,一般为2;通常,Namespace 0用于标准节点,Namespace 1用于服务器特定的节点 
标识符类型枚举:
i-数值
s-字符串
g-全局唯一标识符 (GUID) 
b-不透明值(ByteString 中的命名空间特定格式)

2.5 OPC UA的事件

OPC UA中的事件通常是通过订阅(Subscription)和监视项(MonitoredItem)来处理的,而不是通过直接的Event类。
以下是一个简化的步骤,展示了如何在OPC UA客户端中设置订阅和监视项以接收服务器上的事件。

  1. 连接到OPC UA服务器。
  2. 创建一个订阅(Subscription)。
  3. 在订阅中创建一个或多个监视项(MonitoredItem),指定要监视的节点(通常是事件源节点)。
  4. 等待并处理从服务器发送的事件通知。

2.6 OPC UA的监控项、订阅和通知

学习链接:https://www.cnblogs.com/jiyuqi/p/9639034.html

学习资料:https://github.com/FreeOpcUa/opcua-asyncio
OPCUA的Client监控Server的界面:https://github.com/FreeOpcUa/opcua-client-gui

这篇关于asyncua模块实现OPC UA通讯的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092009

相关文章

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J