EventFilter — 自定义事件字段与过滤
概述
OPC UA Part 4 §7.18 EventFilter 由两部分组成:
- SelectClauses — 抓哪些字段 (按顺序对应到
EventFieldList) - WhereClause — 过滤条件 (
ContentFilter表达式树, V1 暂未实现)
每个 SelectClause 是一个 SimpleAttributeOperand (Part 4 §7.4.4.5):
| 字段 | 说明 |
|---|---|
| TypeDefinitionId | 事件类型 NodeId (如 i=2041 BaseEventType) |
| BrowsePath | 字段路径 (如 ["Severity"] / ["EnabledState", "Id"]) |
| AttributeId | 属性 Id, 默认 Value |
| IndexRange | 数组下标范围 (一般 null) |
不传 EventFilter 时, SDK 默认订阅 5 个字段: EventId / EventType / SourceName / Time / Message。
API
| 类 / 字段 | 类别 | 读写 | 说明 |
|---|---|---|---|
| EventFilter | 类 | — | 过滤器容器 |
| .SelectClauses | 属性 | 读写 | SimpleAttributeOperand[] |
| .WhereClause | 属性 | 读写 | string (V1 占位) |
| SimpleAttributeOperand | 类 | — | 单个字段定义 |
| eventSub.Subscribe(nodeId, filter) | 方法 | 写 | 带 filter 的事件订阅重载 |
代码示例
using DarraOpcUa_Client;
using var ua = new DarraOpcUa("opc.tcp://localhost:4840");
ua.Connect();
using var sub = ua.CreateSubscription(500);
// 1) 自定义抓 8 字段 (默认 5 + 报警特有 3)
var filter = new EventFilter
{
SelectClauses = new[]
{
// 默认 5 字段
new SimpleAttributeOperand { TypeDefinitionId = "i=2041", BrowsePath = new[] { "EventId" } },
new SimpleAttributeOperand { TypeDefinitionId = "i=2041", BrowsePath = new[] { "EventType" } },
new SimpleAttributeOperand { TypeDefinitionId = "i=2041", BrowsePath = new[] { "SourceName" } },
new SimpleAttributeOperand { TypeDefinitionId = "i=2041", BrowsePath = new[] { "Time" } },
new SimpleAttributeOperand { TypeDefinitionId = "i=2041", BrowsePath = new[] { "Message" } },
// 报警特有
new SimpleAttributeOperand { TypeDefinitionId = "i=2041", BrowsePath = new[] { "Severity" } },
new SimpleAttributeOperand { TypeDefinitionId = "i=2782", BrowsePath = new[] { "ConditionId" } },
new SimpleAttributeOperand { TypeDefinitionId = "i=2915", BrowsePath = new[] { "ActiveState", "Id" } },
}
};
using var ev = sub.SubscribeEvents("i=2253", filter);
ev.EventArrived += (s, e) =>
{
// EventFieldList 顺序与 SelectClauses 一致
var eid = e.Fields[0].AsByteString;
var etype = e.Fields[1].AsString;
var src = e.Fields[2].AsString;
var time = e.Fields[3].AsDateTime;
var msg = e.Fields[4].AsString;
var sev = e.Fields[5].AsUInt16;
var condId = e.Fields[6].AsString;
var active = e.Fields[7].AsBoolean;
Console.WriteLine($"[{time:HH:mm:ss}] sev={sev} {src}: {msg} active={active}");
};
实现说明
- Stack 不支持自定义 SelectClauses 时, SDK graceful 降级:
- 回退默认 5 字段
- 推一条
Diagnostic类别 Info 事件
- WhereClause 当前只是占位字符串, V2 接通后会支持完整 ContentFilter (
ElementOperand树)
字段速查 (常用 EventType + BrowsePath)
| EventType | BrowsePath | 含义 |
|---|---|---|
| BaseEventType (i=2041) | ["EventId"] | 事件唯一 ID (ByteString) |
| BaseEventType | ["EventType"] | 事件类型 NodeId |
| BaseEventType | ["SourceName"] | 触发源名 |
| BaseEventType | ["Time"] | 事件时间 (UTC) |
| BaseEventType | ["Message"] | 文本消息 |
| BaseEventType | ["Severity"] | 严重度 1-1000 |
| ConditionType (i=2782) | ["ConditionId"] | 条件 NodeId |
| ConditionType | ["ConditionName"] | 条件名 |
| ConditionType | ["EnabledState", "Id"] | Bool 是否启用 |
| AcknowledgeableConditionType (i=2881) | ["AckedState", "Id"] | Bool 是否已 Ack |
| AlarmConditionType (i=2915) | ["ActiveState", "Id"] | Bool 是否激活 |
| AlarmConditionType | ["ShelvingState", "CurrentState"] | LocalizedText 屏蔽态 |
最佳实践
- 明确列字段 — 不要靠"默认 5 字段", 显式声明易调试
- 顺序与读出顺序对齐 —
e.Fields[i]顺序就是 SelectClauses 顺序 - 报警面板必抓 ConditionId — 后续
Acknowledge / Confirm都需要它 - ActiveState 用嵌套 BrowsePath —
["ActiveState", "Id"]拿 Bool,["ActiveState"]拿 LocalizedText
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| EventFilter | EventFilter | EventFilter | EventFilter | EventFilter | DarraUa_EventFilter |
| SimpleAttributeOperand | SimpleAttributeOperand | SimpleAttributeOperand | SimpleAttributeOperand | SimpleAttributeOperand | DarraUa_SimpleAttributeOperand |