3、工业通信协议(下):OPC UA 协议基础、地址空间模型、安全机制、实战:使用 opcua-asyncio 库连接PLC并读写变量
3.1 OPC UA 到底是什么?
说实话,很多刚入行的朋友会把 OPC UA 和 OPC DA 搞混。我刚开始接触时也犯过这个错。
OPC UA 的全称是“统一架构”(Unified Architecture)。它跟老一代的 OPC DA 最大的区别是什么?
跨平台。 老 OPC 依赖 Windows 的 COM/DCOM 技术,换个 Linux 环境就抓瞎了。OPC UA 从底层就重新设计了,不依赖任何操作系统。
我在一个项目中遇到过,客户现场既有 Windows 上位机,又有 Linux 的边缘网关。如果用老 OPC,两边通信得折腾死。换成 OPC UA 后,一个库搞定所有平台。
- 面向服务架构(SOA),不是简单的数据搬运
- 内置安全机制,不是裸奔的 TCP
- 自带地址空间,能描述数据的“含义”
3.2 地址空间模型——OPC UA 的灵魂
你想想看,传统工业通信里,我们读一个寄存器地址 40001,你知道它代表什么吗?不知道。你只能靠文档去查。
OPC UA 的地址空间模型,说白了就是给每个数据点都配了“身份证”。
它用 节点(Node) 和 引用(Reference) 来组织信息。每个节点都有属性,比如:
- NodeId:唯一标识,类似身份证号
- BrowseName:人类可读的名字
- Value:实际的数据值
- DataType:数据类型(Int32、Float、String 等)
节点之间通过引用连接,形成一张巨大的信息网。你可以从“设备”节点,找到它的“温度传感器”,再找到“当前温度值”。
3.3 安全机制——别让你的数据裸奔
工业网络一旦被攻击,后果很严重。我见过一个工厂,因为 OPC 服务暴露在公网上,被勒索软件加密了所有 PLC 程序……
OPC UA 的安全机制分三层:
| 安全层 | 作用 | 我的建议 |
|---|---|---|
| 传输层安全 | 加密通信通道,防止窃听 | 生产环境必须开启 |
| 应用层安全 | 用户认证、权限控制 | 至少用用户名+密码 |
| 消息层安全 | 签名和加密单个消息 | 高安全场景推荐 |
嗯,这里要注意:很多人在测试时为了方便,把安全模式设为 None。但上线前一定要改回来。我曾经吃过这个亏,测试环境跑得好好的,一上生产就被安全审计卡住了。
3.4 实战:用 opcua-asyncio 连接 PLC
理论说完了,咱们直接上手。我用的是 Python 的 opcua-asyncio 库,异步非阻塞,适合做高并发的工业网关。
3.4.1 安装库
pip install opcua-asyncio
就这么简单。没有复杂的依赖,跨平台兼容。
3.4.2 连接 PLC 并读取变量
假设你的 PLC 上有一个变量叫 ns=2;s=Temperature,我们把它读出来:
import asyncio
from opcua import Client
async def read_plc():
# 创建客户端
client = Client("opc.tcp://192.168.1.100:4840")
try:
# 连接
await client.connect()
print("连接成功!")
# 获取节点
node = client.get_node("ns=2;s=Temperature")
# 读取值
value = await node.read_value()
print(f"当前温度: {value} °C")
except Exception as e:
print(f"连接失败: {e}")
finally:
await client.disconnect()
asyncio.run(read_plc())
你看,核心代码就几行。但实际项目中,我建议加上重连机制。工业网络不稳定,断线重连是基本功。
3.4.3 写入变量
写入和读取类似,只是把 read_value 换成 write_value:
# 写入设定值
setpoint_node = client.get_node("ns=2;s=Setpoint")
await setpoint_node.write_value(100.0) # 写入浮点数
print("写入成功!")
3.4.4 订阅变量变化
轮询读取效率低,工业场景更推荐订阅模式:
class MySubHandler:
def datachange_notification(self, node, val, data):
print(f"节点 {node} 的值变为: {val}")
async def subscribe():
client = Client("opc.tcp://192.168.1.100:4840")
await client.connect()
handler = MySubHandler()
node = client.get_node("ns=2;s=Temperature")
# 创建订阅,采样间隔100ms
sub = await client.create_subscription(100, handler)
await sub.subscribe_data_change(node)
# 保持运行
await asyncio.sleep(3600)
await sub.delete()
await client.disconnect()
为什么用订阅?说白了,就是让 PLC 主动推数据给你,而不是你每秒去问一次。这样网络压力小,实时性还高。
3.5 常见问题与排错
实战中你可能会遇到这些问题:
- 连接超时:检查 IP 和端口,确认防火墙没拦截 4840 端口
- 证书错误:生产环境用正式证书,测试环境可以暂时禁用安全验证
- 节点不存在:用 UA Expert 工具浏览一下地址空间,确认 NodeId 写对了
好了,这一章的内容就到这里。OPC UA 其实还有很多高级特性,比如历史数据访问、报警与事件、方法调用等。但掌握了地址空间模型、安全机制和基本的读写操作,你已经能应对 80% 的工业自动化场景了。
下一章,我们会聊一聊 MQTT 在工业物联网中的应用。到时候见。