OPC UA 服务器
Darra PLC 内置完整的 OPC UA (Unified Architecture) 服务器, 包含 15 个功能模块, 符合 OPC UA Part 1-14 规范。
架构概览
15 功能模块
| 模块 | 功能 | OPC UA Part |
|---|---|---|
| 节点管理 | 地址空间构建与维护 | Part 3 |
| 会话管理 | 客户端连接/认证/超时 | Part 4 |
| 订阅服务 | MonitoredItem 数据变化通知 | Part 4 |
| 安全模块 | 证书验证/加密/签名 | Part 2, 6 |
| 历史数据 | 历史值读取/趋势查询 | Part 11 |
| 方法调用 | 远程方法执行 (PLC 控制) | Part 3 |
| 报警与条件 | 报警事件发布/确认/过滤 | Part 9 |
| 发现服务 | 服务器注册/端点枚举 | Part 12 |
| 视图管理 | 节点过滤视图 | Part 3 |
| 数据类型 | 自定义结构体/枚举 | Part 3, 5 |
| 引用管理 | 节点间关系维护 | Part 3 |
| 事件过滤 | WhereClause 事件筛选 | Part 4 |
| 权限控制 | 节点级读写权限 | Part 3 |
| 诊断信息 | 服务器状态/统计 | Part 5 |
| 命名空间 | 多命名空间管理 | Part 3 |
安全策略
| 安全策略 | 加密 | 签名 | 说明 |
|---|---|---|---|
| None | 无 | 无 | 仅用于调试, 不建议生产使用 |
| Basic256Sha256 | AES-256 | SHA-256 | 推荐, 符合当前安全标准 |
| Aes128_Sha256_RsaOaep | AES-128 | SHA-256 | 兼容性好 |
| Aes256_Sha256_RsaPss | AES-256 | SHA-256 + PSS | 最高安全级别 |
生产环境必须配置 X.509 证书:
- 服务器证书: 用于客户端验证服务器身份
- 信任列表: 仅允许受信任的客户端证书连接
- 证书存放于
%ProgramData%\Darra\PLC\Certificates\
地址空间
PLC 数据自动映射为 OPC UA 节点:
Objects/
├── Server/ 服务器诊断节点
├── Darra/
│ ├── PLC/
│ │ ├── Variables/ PLC 变量 (M区)
│ │ │ ├── MW0 ns=2;s=MW0
│ │ │ ├── MD100 ns=2;s=MD100
│ │ │ └── ...
│ │ ├── IO/ IO 点位
│ │ │ ├── DI/ 数字输入
│ │ │ ├── DO/ 数字输出
│ │ │ ├── AI/ 模拟输入
│ │ │ └── AO/ 模拟输出
│ │ ├── Programs/ PLC 程序状态
│ │ └── Alarms/ 报警事件源
│ └── Robot/
│ ├── Joint[0..5]/ 关节状态
│ ├── TCP/ 工具中心点位姿
│ └── State/ 运动状态
订阅与监控
客户端可订阅变量变化, 支持多种触发条件:
| 参数 | 说明 | 默认值 |
|---|---|---|
| 发布间隔 | 服务器推送周期 | 1000ms |
| 采样间隔 | 变量检查周期 | 250ms |
| 队列大小 | 每个 MonitoredItem 缓冲 | 10 |
| 死区 | 模拟量变化阈值 | 0.0 (无死区) |
| 过滤器 | 数据变化 / 事件过滤 | DataChange |
方法节点
OPC UA 方法节点允许远程调用 PLC 功能:
| 方法 | 参数 | 说明 |
|---|---|---|
| StartProgram | programName | 启动 PLC 程序 |
| StopProgram | - | 停止运行 |
| ResetAlarms | - | 清除所有报警 |
| WriteVariable | name, value | 写入 PLC 变量 |
| JogRobot | axis, direction, speed | 机器人点动 |
配置示例
在 IDE 中配置 OPC UA 服务器:
{
"opcua": {
"enabled": true,
"port": 4840,
"serverName": "Darra PLC OPC UA Server",
"securityPolicy": "Basic256Sha256",
"maxSessions": 50,
"maxSubscriptions": 200,
"publishInterval": 1000,
"certificatePath": "Certificates/server.pfx",
"trustedPath": "Certificates/Trusted/",
"historyEnabled": true,
"historyMaxDays": 30
}
}
可使用 UaExpert (Unified Automation) 或 Prosys OPC UA Browser 连接测试 OPC UA 服务器。默认端点: opc.tcp://localhost:4840
OPC UA Client
Darra 既支持作为 Server (上述), 也支持作为 Client 连接其他 OPC UA 设备:
var client = OpcUaClientFactory.Create("opc.tcp://siemens-gateway:4840");
await client.ConnectAsync();
// 浏览节点
var nodes = await client.BrowseAsync("ns=2;s=Devices");
// 读取节点
var value = await client.ReadAsync("ns=2;s=Temperature");
// 订阅变化
await client.SubscribeAsync("ns=2;s=Pressure", TimeSpan.FromSeconds(1),
(id, val) => Console.WriteLine($"{id} = {val}"));
// 调用方法
var result = await client.CallMethodAsync(
objectNode: "ns=2;s=Device.Motor",
methodNode: "ns=2;s=Device.Motor.Start",
args: new object[] { 1500.0 });
Client 与 Server 可共存, 典型场景: PLC 作为 Client 聚合多个老设备的 OPC UA Server, 再作为 Server 统一对外暴露。
身份认证
OPC UA 支持三种用户身份:
| 身份类型 | 实现 | 适用场景 |
|---|---|---|
| 匿名 | 无 | 仅内网调试 |
| 用户名/密码 | 明文或加密传输 | 中等安全性 |
| X.509 证书 | 证书+私钥 | 企业级, 最高安全 |
多个身份可同时启用, 客户端在连接时选择。Server 侧配置:
{
"userIdentities": {
"anonymous": { "enabled": true },
"userPassword": {
"enabled": true,
"users": [
{ "name": "readonly", "hash": "...", "role": "Observer" },
{ "name": "operator", "hash": "...", "role": "Supervisor" },
{ "name": "engineer", "hash": "...", "role": "Engineer" }
]
},
"certificate": {
"enabled": true,
"trustList": "Certificates/Trusted/"
}
}
}
角色与权限
角色控制节点级访问权限:
| 角色 | 读 | 写 | 订阅 | 方法调用 | 历史 |
|---|---|---|---|---|---|
| Anonymous | Yes | No | Yes | No | No |
| Observer | Yes | No | Yes | No | Yes |
| Operator | Yes | 部分 | Yes | Yes | Yes |
| Supervisor | Yes | Yes | Yes | Yes | Yes |
| Engineer | Yes | Yes | Yes | Yes | Yes + 配置修改 |
单节点级权限可覆盖默认角色规则 (节点属性 AccessRestrictions)。
命名空间
OPC UA 用命名空间索引 + 标识符唯一定位节点:
| 索引 | URI | 用途 |
|---|---|---|
| 0 | http://opcfoundation.org/UA/ | OPC 基金会标准 |
| 1 | urn:DarraPLC | 本服务器 URI |
| 2 | urn:DarraPLC:UserNamespace | 用户自定义节点 |
| 3 | http://darra.com/robot | Robot 命名空间 |
节点 ID 格式:
ns=2;s=MW100— 字符串标识ns=2;i=1234— 数字标识ns=2;g=xxxxxxxx-xxxx-...— GUIDns=2;b=...— 字节串 (Base64)
订阅与发布
订阅是 OPC UA 的推送机制, 核心参数:
| 参数 | 说明 |
|---|---|
| Publishing Interval | 服务器发往客户端的最大间隔 |
| Sampling Interval | 服务器采样变量的间隔 |
| Queue Size | 每个 MonitoredItem 的缓存深度 |
| Discard Oldest | 队列满时丢旧 or 丢新 |
| Max KeepAlive Count | 无数据时最多 N 次发 KeepAlive |
| Max Lifetime Count | 无通讯时的生存周期 |
Deadband (死区) 用于减少无效通知:
- Absolute: 数值变化 > 阈值才通知
- Percent: 变化比例 > 百分比才通知
事件与报警
Alarms & Conditions (CiA 方法) 定义了标准报警模型:
Event (基础事件)
├─ Condition (可确认条件)
│ ├─ DialogCondition
│ ├─ AlarmCondition
│ │ ├─ LimitAlarm (上下限)
│ │ │ ├─ ExclusiveLimitAlarm
│ │ │ └─ NonExclusiveLimitAlarm
│ │ ├─ OffNormalAlarm
│ │ └─ ...
Darra 的 AlarmManager 自动把 PLC 报警映射为 OPC UA 报警事件, 支持:
- 触发 / 激活
- Acknowledge (操作员确认)
- Confirm (维护员确认)
- Suppress / Shelve (抑制)
历史数据
两种历史数据来源:
- 内置历史: 使用 SQLite 本地缓存, 存一段时间 (默认 30 天)
- 外挂数据库: 历史查询转发到 SQL / InfluxDB
查询接口:
var history = await client.HistoryReadRawAsync(
nodeId: "ns=2;s=MD100",
startTime: DateTime.UtcNow.AddHours(-1),
endTime: DateTime.UtcNow,
numValuesPerNode: 1000);
方法节点实现
PLC 侧可声明 OPC UA 方法节点, 绑定到 FB:
项目树 → 通讯 → OPC UA → 方法 → 新建
配置:
- 方法名 + 输入参数 (类型 + 名称) + 输出参数
- 绑定的 FB: 方法被调用时, 写入输入到 FB 的 VAR_INPUT, 调用 FB, 读出 VAR_OUTPUT
这样外部系统可以远程触发 PLC 逻辑, 不需要写入变量 + 等结果的间接方式。
性能调优
| 场景 | 建议 |
|---|---|
| 100 客户端 + 1000 变量 | Publishing Interval ≥ 500 ms, Sampling 250 ms |
| 单个高频变量 | 单独订阅, 100 ms |
| 模拟量趋势显示 | Deadband Percent 1%, 减少无用通知 |
| 报警推送 | 事件订阅 (EventFilter) 而非变量订阅 |
| 批量读 1000 变量 | 单次 Read Call 用 ReadBatch, 不用循环 |
OPC UA 伴随规范
IDE 内置支持以下 Companion Specifications:
| 规范 | 用途 | 节点前缀 |
|---|---|---|
| DI (Device Integration) | 设备管理 | /Objects/DeviceSet |
| PLCopen UA | PLC 程序结构暴露 | /Objects/PLCopen |
| Robotics | 机器人状态 | /Objects/Motion |
| Machine Tool | 机床专用 | /Objects/MachineTool |
这些规范定义了标准的节点层次和类型, 便于上位系统免配置接入。
排错
| 症状 | 处理 |
|---|---|
| 客户端连不上 | 端口 4840 放行, 证书信任 |
| 0x80440000 BadIdentityTokenInvalid | 账号密码错或证书未信任 |
| 订阅不推送 | KeepAlive 太小导致被清 |
| 大量变量时 CPU 高 | 减少 Sampling Interval |
| 历史数据为空 | 未启用历史或超过保留期 |
| 方法调用超时 | PLC 侧 FB 执行过慢 |