跳到主要内容

NodeCollection — ua.nodes

NodeCollection 是 Session 的节点访问入口, 通过 get(String nodeId) 返回 OpcUaNode 包装对象, 不立即触发 RPC (Lazy Load).

前置阅读

入口方法

方法返回说明
nodes.get(String nodeId)OpcUaNode字符串 NodeId 访问 (对应 C# Nodes[nodeId] 索引器)
nodes.makeNumeric(String nsUri, long id)OpcUaNode按 ns URI + Numeric Id 构造 (内部走 namespaces.indexOf)
nodes.makeString(String nsUri, String id)OpcUaNode按 ns URI + String Id 构造

预定义入口方法 (标准节点)

为方便, 内置常用入口:

类别属性类型访问说明
标准入口root()OpcUaNodeRAddress Space 根 (i=84)
objects()OpcUaNodeR业务数据根 (i=85)
types()OpcUaNodeR类型定义根 (i=86)
views()OpcUaNodeR视图根 (i=87)
server()OpcUaNodeRServer 自身对象 (i=2253)
// 这两行等价
try (OpcUaDataValue t1 = ua.nodes.server().get("ServerStatus").get("CurrentTime").getValue()) {
// ...
}
try (OpcUaDataValue t2 = ua.nodes.get("i=2253").get("ServerStatus").get("CurrentTime").getValue()) {
// ...
}

Lazy Load 机制

OpcUaNode node = ua.nodes.get("ns=2;s=Temperature");  // ← 不触发 RPC
try (OpcUaDataValue dv = node.getValue()) { // ← 第一次 .getValue() 才触发 Read
// ...
}

第二次访问 getValue() 还是会重新 Read (无缓存), 因为变量值随时变. 想缓存自己存变量.


子节点 BrowseName 索引

OpcUaNode sub = node.get("ChildName");  // 通过 BrowseName 浏览子节点

底层逻辑:

  1. 立即用 browse(currentNodeId) 拿到子节点列表
  2. 找到 BrowseName == "ChildName" (或 DisplayName) 的子, 返回 OpcUaNode 包装
  3. 找不到返回 null (Java 风格, 不抛异常)

第一次访问会有 RPC 开销 (~5-10 ms), 后续路径访问连串都是单次 Browse 的结果.


按 NamespaceUri 构造 NodeId (推荐)

NamespaceIndex 不稳定, 生产代码用 NamespaceUri:

// 服务端的 ns 索引可能是 2 / 3 / 5, 不稳定 — 用 URI 反查
OpcUaNode temp = ua.nodes.makeString("urn:my-company:plc1", "Temperature");
try (OpcUaDataValue dv = temp.getValue()) {
// ...
}
Namespace 必须存在

makeNumeric / makeString 在 URI 不存在时抛 OpcUaException(DarraInvalidArgument). 调用前确保 ua.connect() 成功 (NamespaceArray 已加载).


何时用入口方法, 何时用字符串

场景推荐
已知精确 NodeId字符串 (ua.read("ns=2;s=..."))
标准节点 (Server 状态等)nodes.server().get(...)
浏览树 / 写一次性脚本索引器 (nodes.get("...").get("..."))
跨 Server NamespaceUri 移植nodes.makeString(uri, id)
批量 (100+ 节点)readMany / browseMany, 不要循环

下一步