事件订阅
OPC UA 事件 (Alarms & Conditions) 通过 subscribeEvents 订阅. 这是 OPC UA 协议事件, 与 SDK 内部 ua.events.* 不是一回事.
区别
ua.subscribeEvents(...)— OPC UA 协议事件 (报警 / 条件, 服务端推送, 本节)ua.events.*— SDK 内部事件 (会话 / 订阅生命周期, 与协议无关)
签名
public OpcUaEventSubscription subscribeEvents();
public OpcUaEventSubscription subscribeEvents(String nodeId);
public OpcUaEventSubscription subscribeEvents(String nodeId,
OpcUaSubscription existingSubscription);
| 参数 | 默认 | 说明 |
|---|---|---|
nodeId | null (Server, i=2253) | 事件源节点 |
existingSubscription | null | 复用已存在的 Subscription, null 则内部新建 (1000ms 间隔) |
OpcUaEventSubscription
| 成员 | 说明 |
|---|---|
onEventArrived | List<Consumer<EventArrivedEventArgs>> 事件到达回调 |
close() | 移除该 Event MI; 如果是内部新建容器还会销毁容器 |
实现 AutoCloseable, 必须在 try-with-resources 内使用.
EventArrivedEventArgs
| 字段 | 类型 | 说明 |
|---|---|---|
severity | int | 严重度 1-1000 |
message | String | 事件文本 |
sourceName | String | 事件源名 |
timeFt | long | 事件发生时间 (FileTime, 0 = null) |
eventType | String | 事件类型 NodeId |
arrivedAtUtc | Instant | Java 端记录的到达时间 |
用法
默认订阅 Server 节点
try (OpcUaEventSubscription evSub = ua.subscribeEvents()) {
evSub.onEventArrived.add(e -> {
System.out.printf("[%d] %s: %s%n", e.severity, e.sourceName, e.message);
long ft = e.timeFt;
Instant t = (ft > 0)
? Instant.ofEpochMilli((ft - 116444736000000000L) / 10000L)
: Instant.now();
System.out.println(" EventType=" + e.eventType + " Time=" + t);
});
Thread.sleep(java.time.Duration.ofMinutes(5).toMillis());
}
订阅指定节点的事件
try (OpcUaEventSubscription evSub = ua.subscribeEvents("ns=2;s=Line1")) {
// Line1 必须是 EventNotifier
evSub.onEventArrived.add(e -> /* ... */);
Thread.sleep(60_000);
}
复用已有 Subscription 容器
try (OpcUaSubscription sub = ua.createSubscription(500.0)) {
sub.add("ns=2;s=Counter", null); // 数据订阅
// 把 Event MI 挂到同一个容器
try (OpcUaEventSubscription evSub = ua.subscribeEvents("ns=2;s=Line1", sub)) {
// evSub.close 只移除 Event MI, 不销毁 sub
evSub.onEventArrived.add(e -> /* ... */);
Thread.sleep(60_000);
}
}
EventNotifier
只有 EventNotifier Attribute (12) 非 0 的节点才能产生事件. 默认 Server (i=2253) 是 EventNotifier. 自定义节点是否有事件源能力, 看服务端实现.
EventFilter (高级)
OPC UA EventFilter 可以过滤 EventType / Severity / SourceNode, 当前 SDK 默认订阅 BaseEventType 并选 4 个标准字段 (Severity / Message / SourceName / Time), 复杂过滤待后续版本暴露.
报警操作 (Acknowledge / Confirm)
收到 AlarmConditionType 事件后, 操作员通常要 Acknowledge (确认). 通过 call 调用报警节点的 Acknowledge Method:
try (OpcUaVariant evtId = new OpcUaVariant().setString("event-id-bytes-as-string");
OpcUaVariant cmnt = new OpcUaVariant().setString("Operator confirmed")) {
ua.call(conditionId, conditionId + ".Acknowledge", evtId, cmnt);
}
JNA Callback 保活
事件订阅内部为每个 EventSubscription 创建一个 JNA trampoline callback, 由 OpcUaEventSubscription.keepAlive 持有强引用防 GC. 用户不要手动销毁 callback, 只要不释放 OpcUaEventSubscription 就安全.