事件订阅
OPC UA 事件 (Alarms & Conditions) 通过 Session::subscribe_events 订阅. 这是
OPC UA 协议事件, 与 SDK 内部 s.events.* 不是一回事.
区别
s.subscribe_events(...)— OPC UA 协议事件 (报警 / 条件, 服务端推送, 本节)s.events.*— SDK 内部事件 (会话 / 订阅生命周期, 与协议无关)
签名
pub fn Session::subscribe_events<F>(
&self,
node_id: Option<&str>,
existing: Option<Arc<Subscription>>,
callback: F,
) -> Result<EventSubscription, OpcUaError>
where F: FnMut(&EventArrivedEventArgs) + Send + 'static;
| 参数 | 默认 | 说明 |
|---|---|---|
node_id | None (Server, i=2253) | 事件源节点 |
existing | None | 复用已存在的 Arc<Subscription>; None 内部新建 |
callback | (必填) | 事件到达回调 |
EventSubscription
| 方法 | 说明 |
|---|---|
monitored_item_handle() | 当前 Event MI 本地句柄 |
Drop EventSubscription 时:
- 容器 = Owned (内部新建): 删 MI + 销毁 Subscription
- 容器 = Borrowed (用户传入): 只删 MI, 不动 Subscription
EventArrivedEventArgs
pub struct EventArrivedEventArgs {
pub severity: u16,
pub message: Option<String>,
pub source_name: Option<String>,
pub time: Option<SystemTime>,
pub event_type: Option<String>,
}
| 字段 | 说明 |
|---|---|
severity | 严重度 1-1000 |
message | 事件文本 |
source_name | 事件源名 |
time | 事件发生时间 |
event_type | 事件类型 NodeId |
用法
默认订阅 Server 节点
use darra_opcua::Session;
let mut s = Session::new("opc.tcp://localhost:4840")?;
s.connect()?;
let _ev_sub = s.subscribe_events(None, None, |e| {
println!("[{}] {:?}: {:?}", e.severity, e.source_name, e.message);
println!(" EventType={:?} Time={:?}", e.event_type, e.time);
})?;
std::thread::sleep(std::time::Duration::from_secs(60));
// _ev_sub Drop, 内部 Subscription 一并销毁
订阅指定节点的事件
let _ev_sub = s.subscribe_events(
Some("ns=2;s=Line1"), // Line1 必须是 EventNotifier
None,
|e| { println!("Line1 event: {:?}", e.message); },
)?;
复用已有 Subscription 容器
use std::sync::Arc;
let data_sub = Arc::new(s.create_subscription(500.0)?);
data_sub.add_node("ns=2;s=Counter", |args| {
println!("counter = {:?}", args.value_string);
})?;
// 把 Event MI 挂到同一个容器
let _ev_sub = s.subscribe_events(
Some("ns=2;s=Line1"),
Some(data_sub.clone()),
|e| { println!("event = {:?}", e.message); },
)?;
// _ev_sub Drop 只移除 Event MI, 不销毁 data_sub
EventNotifier
只有 EventNotifier Attribute (12) 非 0 的节点才能产生事件. 默认 Server (i=2253) 是
EventNotifier. 自定义节点是否有事件源能力, 看服务端实现.
EventFilter (高级)
OPC UA EventFilter 可以过滤 EventType / Severity / SourceNode, 当前 SDK 默认订阅 BaseEventType (全部事件, 内置 SelectClauses: Severity / Message / SourceName / Time), 复杂过滤待后续版本暴露.
报警操作 (Acknowledge / Confirm)
收到 AlarmConditionType 事件后, 操作员通常要 Acknowledge (确认). 通过
call 调用报警节点的 Acknowledge Method:
use darra_opcua::Variant;
let mut event_id = Variant::new();
event_id.set_string("event-123");
let mut comment = Variant::new();
comment.set_string("Operator confirmed");
s.call(
&condition_id,
&format!("{}.Acknowledge", condition_id),
&[event_id, comment],
)?;
闭包要求
F: FnMut(&EventArrivedEventArgs) + Send + 'static
跨线程闭包要求与 DataChange 回调相同, 用 Arc<Mutex<...>> / mpsc 在线程间传数据.
历史事件
实时事件 + 历史事件常常组合用:
use std::time::{Duration, SystemTime};
// 启动时拉过去 24 小时的历史事件
let now = SystemTime::now();
let history = s.read_history_events(
"i=2253",
now - Duration::from_secs(24 * 3600), now, 1000,
)?;
for e in &history {
println!("HISTORY [{}] {:?}: {:?}", e.severity, e.source_name, e.message);
}
// 然后订阅实时
let _live = s.subscribe_events(None, None, |e| {
println!("LIVE [{}] {:?}: {:?}", e.severity, e.source_name, e.message);
})?;