Node
Node 是 NodeCollection 返回的轻量值对象, 表示远程一个节点.
Lazy Load — 只有访问属性才触发 RPC.
前置阅读
- 入口请看 NodeCollection.
- 想避免链式调用的多次 RPC 请用 TranslateBrowsePaths 一次性解析路径.
公共方法
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 标识 (无 RPC) | node_id() | &str | R | 节点 ID 字符串 |
| 数据 (触发 RPC) | value() | Result<DataValue, OpcUaError> | R | 当前值 — 触发 Read(Value) |
display_name() | Option<String> | R | 显示名 — 触发 Read(DisplayName) | |
browse_name() | Option<String> | R | 浏览名 — 触发 Read(BrowseName) | |
description() | Option<String> | R | 描述 — 触发 Read(Description) | |
node_class() | NodeClass | R | 节点类别 — 触发 Read(NodeClass) | |
is_readable() | bool | R | AccessLevel bit0 — 触发 Read(AccessLevel) | |
is_writable() | bool | R | AccessLevel bit1 — 触发 Read(AccessLevel) | |
| 子节点 (触发 RPC) | children() | Result<Vec<Reference>, OpcUaError> | R | 子节点列表 — 触发 Browse |
child(browse_name) | Option<Node> | R | 按 BrowseName 取子节点 — 触发 Browse |
公共方法
| 方法 | 说明 |
|---|---|
read_attribute(attr) | 读指定 Attribute, 返回 Result<DataValue, OpcUaError> |
write(&Variant) | 写 Value, 返回 Result<StatusCode, OpcUaError> |
write_attribute(attr, &Variant) | 写指定 Attribute |
resolve(path) | 相对本节点解析 BrowsePath, 返回 Option<Node> |
call(parent_obj_id, &[Variant]) | 当本节点是 Method, 调用之 |
例子
use darra_opcua::Variant;
// 1. 拿节点 (无 RPC)
let temp = s.nodes().get("ns=2;s=Temperature");
// 2. 读基本信息 (各 1 次 RPC)
println!("NodeId = {}", temp.node_id());
println!("DisplayName = {:?}", temp.display_name());
println!("NodeClass = {:?}", temp.node_class());
// 3. 读值
let dv = temp.value()?;
let val = dv.variant().try_get_f64().unwrap_or(0.0);
println!("Value = {} °C @ {:?}", val, dv.source_timestamp());
// 4. 写
let mut v = Variant::new();
v.set_f64(25.5);
temp.write(&v)?;
// 5. 浏览子节点
for child in temp.children()? {
println!(" {} -> {}", child.browse_name, child.node_id);
}
// 6. 链式访问 (Server.ServerStatus.CurrentTime)
if let Some(status) = s.nodes().server().child("ServerStatus") {
if let Some(time) = status.child("CurrentTime") {
println!("Server time = {:?}", time.value()?.source_timestamp());
}
}
Node 与 Reference 的区别
Reference 是 Browse 返回的字段快照 (BrowseName / DisplayName / NodeId / NodeClass),
不挂 Session 句柄. 通过 to_node(&session) 转可操作的 Node:
use darra_opcua::NodeClass;
for r in s.browse("ns=2;s=Boiler1", NodeClass::Unspecified)? {
let node = r.to_node(&s);
let dv = node.value()?;
println!("{} = {:?}", r.browse_name, dv.variant());
}
注意事项
- 所有触发 RPC 的方法都是"读一次返回一次", 不缓存. 想缓存自己存变量
- 链式访问
node.child("a").unwrap().child("b").unwrap()每段都是一次 Browse RPC, 总计 N 次. 如果路径已知, 用Session::resolve()/translate_browse_paths()一次性解析更快 DataValue离开作用域自动 Drop, 不需要手动释放- 跨线程使用
Node安全 (Send + Sync)
与 Resolve 的对比
// 方式 A: 链式 child - 4 次 RPC
let time = s.nodes().server()
.child("ServerStatus").unwrap()
.child("CurrentTime").unwrap()
.value()?;
// 1次 2次 3次 4次 Read
// 方式 B: 路径解析 - 2 次 RPC
let node = s.resolve("/Objects/Server/ServerStatus/CurrentTime")?.unwrap(); // 1 次
let time = node.value()?; // 1 次
// 方式 C: 直接 NodeId - 1 次 RPC
let time = s.read("i=2258")?;
如果路径已知 → 方式 C; 探索式开发 → 方式 A.