事件订阅
OPC UA 事件 (Alarms & Conditions) 通过 s.SubscribeEvents(...) 订阅. 这是 OPC UA 协议事件, 与 SDK 内部 s.Events().* 不是一回事.
区别
s.SubscribeEvents(...)— OPC UA 协议事件 (报警 / 条件, 服务端推送, 本节)s.Events().on_*— SDK 内部事件 (会话 / 订阅生命周期, 与协议无关)
签名
EventSubscription SubscribeEvents(
std::string const& node_id = "",
Subscription* existing = nullptr);
| 参数 | 默认 | 说明 |
|---|---|---|
node_id | "" (Server, i=2253) | 事件源节点 |
existing | nullptr | 复用已存在的 Subscription, nullptr 则内部新建一个 1000ms 容器 |
EventSubscription
EventSubscription 是 Move-only 栈对象, 析构时:
- 如果是内部新建容器: 销毁容器 (Subscription_Delete)
- 如果是借用外部容器: 仅移除该 Event MI
| 成员 | 说明 |
|---|---|
SetOnEvent(cb) | 设置事件回调 |
on_event() = cb | 同 SetOnEvent 的语法糖 |
EventArrivedEventArgs
struct EventArrivedEventArgs {
uint16_t severity = 0; // 1-1000
std::string message;
std::string source_name;
int64_t time = 0; // FileTime (UTC 100ns since 1601)
std::string event_type; // 事件类型 NodeId
};
用法
默认订阅 Server 节点
auto ev_sub = s.SubscribeEvents();
ev_sub.SetOnEvent([](EventArrivedEventArgs const& e) {
std::cout << "[" << e.severity << "] " << e.source_name << ": " << e.message
<< " ft=" << e.time << " type=" << e.event_type << "\n";
});
std::this_thread::sleep_for(std::chrono::minutes(5));
// ev_sub 离开作用域: 自动移除 Event MI + 销毁内部容器
订阅指定节点的事件
auto ev_sub = s.SubscribeEvents("ns=2;s=Line1");
// Line1 必须是 EventNotifier
复用已有 Subscription 容器
auto sub = s.CreateSubscription(500.0);
sub.AddNode("ns=2;s=Counter", [](DataValue const& dv) { /* 数据订阅 */ });
// 把 Event MI 挂到同一个容器 (借用)
auto ev_sub = s.SubscribeEvents("ns=2;s=Line1", &sub);
ev_sub.SetOnEvent([](EventArrivedEventArgs const& e) { /* ... */ });
// ev_sub 析构: 只移除 Event MI, 不销毁 sub
EventNotifier
只有 EventNotifier Attribute (12) 非 0 的节点才能产生事件. 默认 Server (i=2253) 是 EventNotifier. 自定义节点是否有事件源能力, 看服务端实现.
EventFilter (高级)
OPC UA EventFilter 可以过滤 EventType / Severity / SourceNode, 当前 SDK 默认订阅 BaseEventType (全部事件), 复杂过滤待后续版本暴露.
报警操作 (Acknowledge / Confirm)
收到 AlarmConditionType 事件后, 操作员通常要 Acknowledge (确认). 通过 Call 调用报警节点的 Acknowledge Method:
std::vector<Variant> args;
{ Variant a; a.SetByteString(event_id.data(), event_id.size()); args.push_back(std::move(a)); }
{ Variant b; b.SetString("Operator confirmed"); args.push_back(std::move(b)); }
s.Call(condition_id, condition_id + ".Acknowledge", args);