本文主要讲述如何使用asyncua去实现OPCUA Server和Client。asyncua是OPCUA的python实现,使用起来非常方便,其github地址是https://github.com/FreeOpcUa/opcua-asyncio
一 安装asyncua
Python版本要求3.7+
在win下使用pip即可安装,
pip install asyncua
如果在linux下,使用pip3去安装,
pip3 install asyncua
二 Server
Server代码如下,
import logging
import asyncio
import signal
import sys
from asyncua import ua, Server
# Ctrl+C的处理函数
def signal_handler(sig, frame):
print("Receive Ctrl+C.")
sys.exit(0)
logging.basicConfig(level=logging.INFO)
_logger = logging.getLogger('asyncua')
async def main():
# 创建server
server = Server()
# 初始化server
await server.init()
# 设置server的endpoint地址
server.set_endpoint('opc.tcp://127.0.0.1:4840/freeopcua/server/')
# 设置server的名字
server.set_server_name('MyOPCUAServer')
# 设置自己的namespace,也可以不做
uri = 'http://examples.freeopcua.github.io'
idx = await server.register_namespace(uri)
# 在上面的namespace下添加一个对象,名叫MyObject
myobj = await server.nodes.objects.add_object(idx, 'MyObject')
# 在MyObject下添加一个变量,名叫MyVariable,初始值是6.7
myvar = 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__':
signal.signal(signal.SIGINT, signal_handler)
asyncio.run(main())
上述代码主要做以下几件事
- 创建server并初始化
- 添加自己的namespace
- 在自己的namespace下添加一个对象,并在该对象下添加一个变量
- loop循环运行server
运行上述代码,
python server.py
然后使用UaExpert进行连接,打开后可以在Local下看到Server和endpoint
连接这个endpoint,可以在地址空间里看到添加的对象和变量
对于地址空间,可以在UaExpert里观察到,如下,
可以看到server里有3个地址空间,index分别是0,1,2
三 Client
代码如下,
import asyncio
import sys
import logging
from asyncua import Client
async def main():
url = 'opc.tcp://localhost: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())
所做的事情就是从sever端按照Objects->MyObject->MyVariable来读取变量值,client.nodes.root.get_child()函数里接收了一个list参数,里面填入路径节点的Browse Name
运行之,
python client.py
打印如下,
打印了MyVariable的NodeId和值,且与UaExpert里观察到的一样,
四 总结
本文主要讲述如何使用asyncua来实现简单的Server和Client,并让他们通信。asyncua使用了异步io,写的时候经常需要加上async和await,习惯就好。对于快速原型验证,asyncua是个非常不错的选择,不需要编译。