OPC-UA 驱动
概述
基于 OPC Unified Architecture (IEC 62541) 的工业数据标准协议。
| 项目 | 值 |
|---|---|
opc_type | OPCUA |
| 实现类 | plantpulse.driver.protocol.opcua.OPCUA_34_Driver |
| 库 | Eclipse Milo (milo-sdk-client) |
| read | ✅ |
| write | ❌ (Phase 3 / 与 Sparkplug NCMD 一起) |
| 安全 | Username/Password, Anonymous |
与 Kepware、Matrikon、Prosys 等大多数 OPC-UA 服务器兼容。
OPC 注册表单
| 字段 | 含义 | 示例 |
|---|---|---|
opc_agent_ip | OPC-UA 服务器 IP | 192.168.0.40 |
opc_agent_port | OPC-UA 服务器 TCP 端口 | 49320 (Kepware 默认) |
timecycle | 轮询周期 (ms) | 1000 |
options.servername | endpoint 末尾的服务器名 | (Kepware 则留空) |
options.username | 认证用户 | kopens |
options.password | 认证密码 | *** |
options.discovery | 是否使用 discovery endpoint | false (为 true 时自动检索 endpoints) |
生成的 endpoint URL 格式:
opc.tcp://<opc_agent_ip>:<opc_agent_port>/<servername>
username 与 password 同时存在时使用 UsernameProvider,否则使用 AnonymousProvider。
标签 plc_address 格式
OPC-UA 标准 NodeId 表示法。例如:
| 表示 | 含义 |
|---|---|
ns=2;s=Simulator.Sine1 | namespace 2, string identifier Simulator.Sine1 |
ns=2;i=1234 | numeric identifier 1234 |
ns=3;g=09087e75-8e5e-499b-954f-f2a8624db28a | GUID identifier |
ns=2;b=Mb= | opaque (bytestring) identifier |
Kepware 通常为 ns=2;s=<Channel>.<Device>.<Tag> 格式。
data_type / format 映射
将 OPC-UA 变量节点的 Value 转换为 String 后返回。data_type 供后续环节
(PLCValueFomula、Sparkplug 发布等) 在类型转换时使用。
data_type | 行为 |
|---|---|
Float / Double | 数值原样 |
Int / Integer / Int32 / Short / Long | 数值原样 |
Boolean / Bool | true/false 字符串 |
String / Text | UTF-8 字符串 |
DateTime | ISO 字符串 |
format 在 OPC-UA 中通常不使用。如需后处理运算,请使用 fomula。
常见错误与解决
| 消息 / 现象 | 原因 | 解决 |
|---|---|---|
connection refused | 服务器未运行、端口被阻断 | 用 telnet <ip> <port> 确认通信 |
Bad_UserAccessDenied | username/password 错误、不允许匿名 | 在服务器侧注册用户或启用 anonymous |
Bad_SecurityChecksFailed | 安全策略不匹配 | 在服务器确认 None / Basic256Sha256 等策略。Phase 1 优先使用 MessageSecurityMode.None |
endpointUrl 不匹配 | 为 discovery=false 但服务器返回了其他主机名 | 保持为 discovery=true 或在 hosts 文件中做映射 |
| 值始终为 0 / null | NodeId 拼写错误、namespace 编号不一致 | 用 UA Expert 等客户端对同一 NodeId 进行 read 验证 |
curl 注册示例
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_UA_Kepware",
"opc_type": "OPCUA",
"opc_name": "Kepware",
"opc_agent_ip": "192.168.0.40",
"opc_agent_port": "49320",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": {
"username": "kopens",
"password": "***",
"discovery": "false"
},
"tag_list": [
{
"tag_id": "OPC_UA_Kepware_TAG_00001",
"tag_name": "Sine1",
"plc_address": "ns=2;s=Simulator.Sine1",
"data_type": "Float",
"description": "Sine wave"
},
{
"tag_id": "OPC_UA_Kepware_TAG_00002",
"tag_name": "Random1",
"plc_address": "ns=2;s=Simulator.Random1",
"data_type": "Integer"
}
]
}'
读取值:
curl -s http://<edge-host>/api/v1/tag/OPC_UA_Kepware_TAG_00001/value | jq
参考:Kepware 快速配置指南
- Kepware Server → Project → 添加通道 (例如
Simulator)。 - 添加设备 (例如
Simulator) → 模型 =16 Bit Device。 - 添加标签 →
Sine1,typeFloat,scan rate100ms等。 - 在
Project Properties → OPC UA → Server Endpoint中启用端口49320。 - 启用 Anonymous 或用户账户。
→ Edge 注册表单:
| 字段 | 值 |
|---|---|
| opc_agent_ip | Kepware 服务器 IP |
| opc_agent_port | 49320 |
| options.servername | (留空) |
| options.username/password | 上面创建的账户 |
| plc_address | ns=2;s=Simulator.Simulator.Sine1 |
示例集 (按数据类型)
OPC-UA 将变量节点的值(Variant)转换为 String 后返回。data_type 供后处理 (PLCValueFomula、Sparkplug DataTypeMapper) 在类型转换时使用。format 通常不使用。
Boolean
data_type | plc_address 示例 | 备注 |
|---|---|---|
Boolean | ns=2;s=Simulator.Boolean1 | Kepware Simulator 的 Boolean tag |
Boolean | ns=2;s=PLC.Status.Running | Kepware Channel.Device.Tag |
Boolean | ns=2;i=1003 | numeric NodeId |
16/32-bit 整数
data_type | plc_address 示例 | 备注 |
|---|---|---|
Integer | ns=2;s=Simulator.Random1 | Random integer 模拟 |
Integer | ns=2;s=Simulator.Counter1 | Counter |
Integer | ns=2;s=PLC.D100 | Kepware MELSEC 通道暴露 |
64-bit 整数
data_type | plc_address 示例 | 备注 |
|---|---|---|
Long | ns=2;s=Simulator.LongCounter | UInt64 / Int64 节点 |
Long | ns=2;s=PLC.Cycle.Total | 累计计数器 |
实数
data_type | plc_address 示例 | 备注 |
|---|---|---|
Float | ns=2;s=Simulator.Sine1 | sine wave 模拟 |
Float | ns=2;s=Simulator.Ramp1 | ramp wave |
Double | ns=2;s=PLC.Pressure | 精密测量值 |
字符串
data_type | plc_address 示例 | 备注 |
|---|---|---|
String | ns=2;s=Simulator.User1.Name | 字符串节点 |
String | ns=2;s=PLC.Recipe.Active | 配方名 |
按 NodeId 格式
| identifier 类型 | plc_address 示例 |
|---|---|
String (s=) | ns=2;s=Simulator.Sine1 |
Numeric (i=) | ns=2;i=1234 |
GUID (g=) | ns=3;g=09087e75-8e5e-499b-954f-f2a8624db28a |
Opaque (b=) | ns=2;b=Mb= |
Formula 应用
| 用途 | data_type | fomula | 备注 |
|---|---|---|---|
| 单位换算 | Float | ${VALUE}*0.001 | g → kg 等 |
| 零点校正 | Float | ${VALUE}-${TAG_ZERO} | 可引用其他 OPCUA 标签 |
| 类型转换 | Float | ${VALUE}*1.0 | Integer → Float 强制转换 |
| 多项式 | Float | ${VALUE}*${VALUE}*0.0001 | 非线性 |
curl 综合示例 (所有类型)
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_UA_FULL",
"opc_type": "OPCUA",
"opc_name": "Kepware Full",
"opc_agent_ip": "192.168.0.40",
"opc_agent_port": "49320",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "discovery": "false" },
"tag_list": [
{"tag_id":"OPC_UA_FULL_T01", "tag_name":"BoolTag", "plc_address":"ns=2;s=Simulator.Boolean1", "data_type":"Boolean"},
{"tag_id":"OPC_UA_FULL_T02", "tag_name":"IntTag", "plc_address":"ns=2;s=Simulator.Random1", "data_type":"Integer"},
{"tag_id":"OPC_UA_FULL_T03", "tag_name":"LongTag", "plc_address":"ns=2;s=Simulator.LongCounter", "data_type":"Long"},
{"tag_id":"OPC_UA_FULL_T04", "tag_name":"FloatTag", "plc_address":"ns=2;s=Simulator.Sine1", "data_type":"Float"},
{"tag_id":"OPC_UA_FULL_T05", "tag_name":"DoubleTag", "plc_address":"ns=2;s=PLC.Pressure", "data_type":"Double"},
{"tag_id":"OPC_UA_FULL_T06", "tag_name":"StringTag", "plc_address":"ns=2;s=Simulator.User1.Name", "data_type":"String"},
{"tag_id":"OPC_UA_FULL_T07", "tag_name":"NumIdTag", "plc_address":"ns=2;i=1234", "data_type":"Integer"},
{"tag_id":"OPC_UA_FULL_T08", "tag_name":"ScaledTag", "plc_address":"ns=2;s=Simulator.Sine1", "data_type":"Float", "fomula":"${VALUE}*100"}
]
}'