跳到主要内容

添加 MonitoredItem

前置阅读

sub.add(...)

public int add(String nodeId, Consumer<DataChangeEventArgs> onChange);
public int add(String nodeId, Consumer<DataChangeEventArgs> onChange,
Enums.AttributeId attribute, double samplingIntervalMs);
参数默认说明
nodeId监控的 NodeId
onChange单 MI 专属回调, 也会触发 sub.onDataChanged 列表里的全局回调 (传 null 跳过专属)
attributeValue (13)监控的 Attribute
samplingIntervalMs-1 (跟订阅)服务端采样间隔. 0 = 尽快

返回: int MonitoredItem handle (本地句柄, 用于后续 modify / remove)

异常: OpcUaException (BadNodeIdUnknown 等)

int h  = sub.add("ns=2;s=Temperature", e ->
System.out.println(e.nodeId + " = " + e.valueString));
int h2 = sub.add("ns=2;s=Pressure", null,
Enums.AttributeId.Value, 100.0);

sub.addMany 批量添加

一次 RPC 添加多个 MI, 比循环 add 快得多:

public List<int[]> addMany(List<String> nodeIds,
Consumer<DataChangeEventArgs> onChange,
Enums.AttributeId attribute);

返回: List<int[]>, 每项是 { handle, statusCode } 二元组.

List<String> nodes = java.util.stream.IntStream.rangeClosed(1, 100)
.mapToObj(i -> "ns=2;s=T" + i)
.toList();

List<int[]> results = sub.addMany(nodes, e -> {
// 共享回调, 通过 e.nodeId / e.monitoredItemHandle 区分
System.out.println(e.nodeId + " = " + e.valueString);
}, Enums.AttributeId.Value);

for (int i = 0; i < nodes.size(); i++) {
int handle = results.get(i)[0];
int status = results.get(i)[1];
if (status == 0) {
System.out.println(" " + nodes.get(i) + " -> handle=" + handle);
} else {
System.out.println(" " + nodes.get(i) + " FAILED: " + Enums.StatusCode.fromCode(status));
}
}

性能: 100 个 MI 用 addMany 约 1 次 RPC (~10 ms), 用循环 add 约 100 次 RPC (~500-1000 ms).


DataChangeEventArgs 字段

回调参数 OpcUaSubscription.DataChangeEventArgs:

字段类型说明
monitoredItemHandleint触发的 MI 句柄
nodeIdString该 MI 的 NodeId
valueStringString值的字符串表示 (预抽取, 跨线程安全)
dataTypeNameString内置数据类型枚举名 (如 Double)
statusEnums.StatusCodeDataValue 的 Status
sourceTimestampFtlong数据源 FileTime, 0 = null
serverTimestampFtlong服务端 FileTime, 0 = null
arrivedAtUtcInstantJava 端记录的到达时间
安全设计

valueString / dataTypeName 已在 native Publish 线程内同步抽取, 跨线程使用安全. 不再暴露原始 DataValue 指针, 避免 use-after-free 闪退.

JNA Callback 保活

add 内部为每个 MI 创建一个 JNA trampoline callback, 由 OpcUaSubscription.keepAlive 列表持有强引用防 GC. 用户不要手动销毁 callback, 只要不释放 OpcUaSubscription 就安全.


移除

sub.remove(handle);
sub.removeByNodeId("ns=2;s=Temperature"); // 按 NodeId 移除全部对应

不同 Attribute 的监控

除了默认监控 Value, 也能监控 Status / Quality:

sub.add("ns=2;s=T1", null, Enums.AttributeId.Value, -1);
sub.add("ns=2;s=T1", null, Enums.AttributeId.NodeClass, -1); // 只关心节点类别变化

DataChangeFilter (死区)

当前 SDK 默认不设 filter (任何变化都推). 如需 Absolute / Percent 死区, 走底层 API (后续版本会暴露).

下一步