Python实现OPC UA

FreeOpcUa,是使用Python开发基于OPC统一架构的优选第三方库,项目链接:https://github.com/FreeOpcUa/python-opcua

创建一个OPC服务器的步骤非常简单:

from opcua import Server

server = Server()    # 实例化一个UA服务器
server.set_endpoint("opc.tcp://0.0.0.0:48400/freeopcua/server/")    # 设定服务器URI
server.start()    # 启动UA服务器

测试所创建的UA服务器,建议可以使用UaExpert,它可以实现UA客户端的功能,下载链接:https://www.unified-automation.com

软件打开后,右键“Servers”,添加新连接
image
2.在“Custom Discovery”下双击,并填入上面代码中设定的服务器URI
image
上步添加完URI后,会扫描到Python中创建的UA服务器,选择“Anonymous”,建立连接
image
3.连接成功后在主页面能够看到OPC UA规范定义的标准地址空间结构
image
对于如何通过FreeOpcUa,创建自己的地址空间,项目源代码Examples文件夹下的server-example.py文件进行了举例。这里要介绍的是如何通过XML文件来编辑地址空间。
在XML文件中创建节点和分配引用,是非常非常棒的一种方法。

编写XML文件,首先添加命名空间,主要包括节点类、数据类型以及W3C标准。

<?xml version="1.0" encoding="UTF-8" ?>
<UANodeSet xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
           xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</UANodeSet>

  1. 创建对象节点
<UAObject NodeId="" BrowseName="" ParentNodeId="">
    <Description></Description>
    <DisplayName></DisplayName>
    <References>
        <Reference ReferenceType="" IsForward=""></Reference>
    </References>
</UAObject>

  1. 填写正确的NodeId,用于明确标识节点

  2. 填写BrowseName,作为浏览地址空间时的非本地化名称

  3. 填写ParentNodeId,在实例化时非常关键,与ModelParent相关,如果不对实例声明进行明确指定,会导致无法实例化

  4. 分配引用,需要注意每种引用可以使用的次数(在节点类学习心得中进行了总结中)

  5. 创建变量节点

<UAVariable NodeId="" BrowseName="" DataType="" ParentNodeId="" AccessLevel="" UserAccessLevel="">
    <Description></Description>
    <DisplayName></DisplayName>
    <References>
        <Reference ReferenceType="" IsForward=""></Reference>
    </References>
    <Value></Value>
</UAVariable>

AccessLevel,设定访问方式,可读可写或其他
Value,定义节点Value属性

一个简单的例子

from opcua import Server

server = Server()
server.set_endpoint("opc.tcp://0.0.0.0:48400/freeopcua/server/")    # 设定服务器URI
server.import_xml("custom_nodes.xml")    # 导入XML文件
server.start()

image

<?xml version="1.0" encoding="UTF-8" ?>
<UANodeSet xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
			xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd"
			xmlns:xsd="http://www.w3.org/2001/XMLSchema"
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <UAObject NodeId="i=30001" BrowseName="MyXMLFolder">
        <Description>A custom folder.</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=61</Reference>
            <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
        </References>
    </UAObject>

    <UAObject NodeId="i=30002" BrowseName="MyXMLObject">
        <Description>A custom object node.</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=58</Reference>
            <Reference ReferenceType="Organizes" IsForward="false">i=30001</Reference>
        </References>
    </UAObject>

    <UAVariable NodeId="i=30004" BrowseName="MyXMLVariable" DataType="String">
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
            <Reference ReferenceType="Organizes" IsForward="false">i=30002</Reference>
        </References>
        <Value><uax:String>StringValue</uax:String></Value>
    </UAVariable>

    <UAVariable NodeId="i=30005" BrowseName="MyXMLProperty" DataType="UInt32">
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
            <Reference ReferenceType="HasProperty" IsForward="false">i=30002</Reference>
        </References>
        <Value><uax:UInt32>76</uax:UInt32></Value>
    </UAVariable>
</UANodeSet>

  • 在上例中,首先添加了一个类型为文件夹的对象节点MyXMLFolder,通过HasTypeDefinition设定其类型为FolderType,用于组织地址空间中的节点,并使用Organizes引用将它组织到Root下的Objects节点下
  • 然后在文件夹节点下添加了一个名为MyXMLObject的对象节点,通过HasTypeDefinition引用设定其类型为BaseObjectType,并使用Organizes引用将它组织到MyXMLFolder节点下
  • 在MyXMLObject对象节点下创建一个变量MyXMLVariable,数据类型设定为字符串型,节点类型为BaseVariableType,设定Value属性来赋予初始值“StringValue”
  • 在MyXMLObject对象节点下添加一个特性MyXMLProperty,需要使用HasProperty引用,节点类型设定为PropertyType,数据类型为32位的UInt,并赋予初始值76

image

一个复杂的例子
创建一个自定义的对象类型节点,然后通过实例化该类型节点得到一个复杂的对象节点。

image

from opcua import Server

server = Server()
server.set_endpoint("opc.tcp://0.0.0.0:48400/freeopcua/server/")    # 设定服务器URI
uri = 'http://examples.freeopcua.github.io'
idx = server.register_namespace(uri)    # 注册地址空间

server.import_xml("test.xml")    # 导入自定义的节点类型

my_sensor_type = server.get_root_node().get_child([
    "0:Types", "0:ObjectTypes", "0:BaseObjectType", "0:TemperatureSensorType"]).nodeid
my_sensor = server.nodes.objects.add_object(idx, "TemperatureSensor", my_sensor_type)

server.start()

在XML文件中创建自定义的类型定义节点MyTemperatureSensorType
image

编程实例化该节点,得到地址空间结构如图:
image

<?xml version="1.0" encoding="UTF-8" ?>
<UANodeSet xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
           xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <UAObjectType NodeId="i=30000" BrowseName="TemperatureSensorType">
        <DisplayName>MyTemperatureSensorType</DisplayName>
        <Description>温度传感器类型</Description>
        <References>
            <Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>    <!-- BaseObjectType -->
        </References>
    </UAObjectType>

    <UAObject NodeId="i=30001" BrowseName="Configuration">
        <Description>配置</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=58</Reference>    <!-- BaseObjectType -->
            <Reference ReferenceType="HasModellingRule">i=78</Reference>    <!-- ModellingRule_Mandatory -->
            <Reference ReferenceType="HasComponent" IsForward="false">i=30000</Reference>
        </References>
    </UAObject>

    <UAVariable NodeId="i=30002" BrowseName="EngineeringUnit" ParentNodeId="i=30001" DataType="String">
        <DisplayName>EngineeringUnit</DisplayName>
        <Description>温度工程单位</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>    <!-- BaseDataVariableType -->
            <Reference ReferenceType="HasModellingRule">i=78</Reference>    <!-- ModellingRule_Mandatory -->
            <Reference ReferenceType="Organizes" IsForward="false">i=30001</Reference>
        </References>
        <Value><uax:String></uax:String></Value>
    </UAVariable>

    <UAObject NodeId="i=30003" BrowseName="Measurement">
        <Description>温度测试</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=58</Reference>    <!-- BaseObjectType -->
            <Reference ReferenceType="HasModellingRule">i=78</Reference>    <!-- ModellingRule_Mandatory -->
            <Reference ReferenceType="HasComponent" IsForward="false">i=30000</Reference>
        </References>
    </UAObject>

    <UAVariable NodeId="i=30004" BrowseName="Temperature" ParentNodeId="i=30003" DataType="Float">
        <DisplayName>Temperature</DisplayName>
        <Description>温度</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=63</Reference>    <!-- BaseDataVariableType -->
            <Reference ReferenceType="HasModellingRule">i=78</Reference>    <!-- ModellingRule_Mandatory -->
            <Reference ReferenceType="Organizes" IsForward="false">i=30003</Reference>
        </References>
        <Value><uax:Float>0.0</uax:Float></Value>
    </UAVariable>

    <UAVariable NodeId="i=30005" BrowseName="EngineeringUnit" ParentNodeId="i=30004" DataType="String">
        <DisplayName>EngineeringUnit</DisplayName>
        <Description>温度工程单位</Description>
        <References>
            <Reference ReferenceType="HasTypeDefinition">i=68</Reference>    <!-- PropertyType -->
            <Reference ReferenceType="HasModellingRule">i=78</Reference>    <!-- ModellingRule_Mandatory -->
            <Reference ReferenceType="HasProperty" IsForward="false">i=30004</Reference>
        </References>
        <Value><uax:String></uax:String></Value>
    </UAVariable>
</UANodeSet>

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 答:下面是一个使用Python实现opc ua的示例代码:from opcua import Client# 创建一个客户端 client = Client("opc.tcp://localhost:4840/")# 连接到客户端 client.connect()# 获取一个变量 node = client.get_node("ns=2;s=MyVariable")# 读取变量的值 value = node.get_value()# 设置变量的值 node.set_value(1.0)# 关闭连接 client.disconnect() ### 回答2: 要使用Python实现OPC UA的代码,首先需要安装opcua库。可以通过以下命令使用pip安装: ``` pip install opcua ``` 接下来,我们可以使用以下的示例代码来连接到OPC UA服务器,并获取一个节点的数据: ```python from opcua import Client # OPC UA服务器的地址 url = "opc.tcp://localhost:4840" # 创建一个OPC UA客户端 client = Client(url) # 连接到OPC UA服务器 client.connect() # 获取根节点对象 root = client.get_root_node() # 获取名为"Objects"的子节点 objects_node = root.get_child(["0:Objects"]) # 获取名为"Server"的子节点 server_node = objects_node.get_child(["0:Server"]) # 获取名为"ServerStatus"的子节点 server_status_node = server_node.get_child(["0:ServerStatus"]) # 获取"CurrentTime"属性的值 current_time = server_status_node.get_value() print("Current Time: ", current_time) # 断开与OPC UA服务器的连接 client.disconnect() ``` 以上代码连接到指定的OPC UA服务器,获取了Server对象的ServerStatus的CurrentTime属性的值,并打印出来。你可以根据实际情况修改代码中的URL和节点路径来适配你的OPC UA服务器和节点。 ### 回答3: 这里提供一个简单的示例代码,使用Python实现opc ua的功能: ``` from opcua import ua, Server # 创建OPC UA服务器 server = Server() server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") # 添加命名空间 uri = "MyNamespace" idx = server.register_namespace(uri) # 创建一个对象节点,用于存储数据 data_obj = server.get_objects_node().add_object(idx, "MyDataObject") # 添加一个变量节点,用于存储整数值 var_node = data_obj.add_variable(idx, "MyVariable", 0) var_node.set_writable() # 设置变量可写 # 启动服务器 server.start() # 循环更新变量值 count = 0 while True: count += 1 var_node.set_value(count) # 更新变量值 print("Updated variable value to:", count) ``` 这段代码首先创建了一个OPC UA服务器,并为其指定了一个端点。然后,创建了一个命名空间和一个用于存储数据的对象节点,以及一个用于存储整数值的变量节点,并设置了变量可写。最后,通过循环更新变量的值,并通过打印语句显示变量的最新值。 要运行此代码,需要先安装`opcua`库,可以使用以下命令进行安装: ``` pip install opcua ``` 运行代码后,服务器将在`opc.tcp://0.0.0.0:4840/freeopcua/server/`端点上运行,可以使用OPC UA客户端连接到该服务器,并读取或写入变量的值。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值