跳到主要内容

事件订阅

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_idNone (Server, i=2253)事件源节点
existingNone复用已存在的 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);
})?;

下一步