报警与条件 (Acknowledge / Confirm / Refresh / Shelve)
概述
OPC UA Part 9 (Alarms & Conditions) 在 ConditionType / AlarmConditionType 上定义了固定 NodeId 的标准 Method。SDK 把这 7+3 个 Method 封装为形参清晰的 C# 方法, 让上层报警面板不用手拼 Variant[] 入参。
固定 NodeId (Part 9 / Part 6 标准空间 0):
| Method | NodeId | 入参 |
|---|---|---|
| Acknowledge | i=9111 | (eventId : ByteString, comment : LocalizedText) |
| Confirm | i=9113 | (eventId : ByteString, comment : LocalizedText) |
| AddComment | i=9029 | (eventId : ByteString, comment : LocalizedText) |
| Enable | i=2803 | 无 |
| Disable | i=2805 | 无 |
| ConditionRefresh | i=3875 | (subscriptionId : IntegerId) |
| ConditionRefresh2 | i=12912 | (subscriptionId, monitoredItemId) |
| OneShotShelve | i=9211 | 无 |
| TimedShelve | i=9213 | (shelvingTime : Duration ms) |
| Unshelve | i=9215 | 无 |
API
| 方法 | 类别 | 读写 | 说明 |
|---|---|---|---|
| ua.Acknowledge(conditionId, eventId, comment) | 报警 | 写 | 用户已知 |
| ua.Confirm(conditionId, eventId, comment) | 报警 | 写 | 现场已处理 |
| ua.AddComment(conditionId, eventId, comment) | 报警 | 写 | 加备注 |
| ua.EnableCondition(conditionId) | 报警 | 写 | 启用 |
| ua.DisableCondition(conditionId) | 报警 | 写 | 禁用 |
| ua.ConditionRefresh(subscriptionId) | 报警 | 写 | 让服务端补发当前所有激活报警 |
| ua.ConditionRefresh2(subscriptionId, miId) | 报警 | 写 | 仅指定 MI 的补发 |
| ua.OneShotShelve(shelvingStateId) | 报警 | 写 | 一次性屏蔽 (下次激活自动恢复) |
| ua.TimedShelve(shelvingStateId, ms) | 报警 | 写 | 限时屏蔽 N 毫秒 |
| ua.Unshelve(shelvingStateId) | 报警 | 写 | 取消屏蔽 |
返回 StatusCode, 失败 不抛异常, 上层自决重试。
代码示例
using DarraOpcUa_Client;
using var ua = new DarraOpcUa("opc.tcp://server:4840");
ua.Connect();
// 1) 订阅报警事件
using var sub = ua.CreateSubscription(500);
using var ev = sub.SubscribeEvents("i=2253"); // ServerObject
ev.EventArrived += (s, e) =>
{
// 抽 EventId / ConditionId (从 EventFieldList)
byte[] eventId = e.GetField("EventId").AsByteString;
string conditionId = e.GetField("ConditionId").AsString;
// a. 让服务端补发当前所有激活报警 (面板首次打开时)
ua.ConditionRefresh(sub.SubscriptionId);
// b. 用户点 "确认"
var rc = ua.Acknowledge(conditionId, eventId, "操作员已知");
if (rc != StatusCode.Good) MessageBox.Show($"Acknowledge 失败: {rc}");
// c. 现场处理后点 "确认完成"
ua.Confirm(conditionId, eventId, "现场已处理");
// d. 临时屏蔽 30 秒
string shelvingId = conditionId + ".ShelvingState";
ua.TimedShelve(shelvingId, 30_000.0);
};
// 2) 加备注 (不影响 Ack/Confirm 状态)
ua.AddComment(conditionId, eventId, "等待夜班巡检");
// 3) 启用 / 禁用整条 Condition (维护期间)
ua.DisableCondition("ns=2;s=Tank.HighLevel");
// ... 维护完
ua.EnableCondition("ns=2;s=Tank.HighLevel");
错误处理
| StatusCode | 含义 |
|---|---|
| Good (0x00000000) | 成功 |
| BadEventIdUnknown | EventId 不匹配当前 Condition |
| BadConditionAlreadyEnabled | 已启用 |
| BadConditionAlreadyDisabled | 已禁用 |
| BadConditionAlreadyShelved | 已屏蔽 |
| BadConditionNotShelved | 未屏蔽, 无法 Unshelve |
最佳实践
- 首次订阅后必调
ConditionRefresh— 不然只能收到新事件, 不见已激活的旧报警 Acknowledge后再Confirm— 两步流程, 不要跳 Confirm- TimedShelve 单位 ms — 不是秒, 30 秒 = 30000 ms
- comment 用中文 —
LocalizedText.Text自动 UTF-8 - 不要在 EventArrived 里同步 Ack — 用 ConcurrentQueue 推队列, 后台线程处理
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| Acknowledge | acknowledge | acknowledge | Acknowledge | acknowledge | DarraUa_Condition_Acknowledge |
| Confirm | confirm | confirm | Confirm | confirm | DarraUa_Condition_Confirm |
| ConditionRefresh | condition_refresh | conditionRefresh | ConditionRefresh | condition_refresh | DarraUa_Condition_Refresh |
| TimedShelve | timed_shelve | timedShelve | TimedShelve | timed_shelve | DarraUa_Condition_TimedShelve |