OPC UA Milo - 在数据更改通知回调中收集受监视的项目



我正在使用Eclipse Milo OPC-UA项目的SubscriptionExample(https://github.com/eclipse/milo(测试一些东西,并发现了一种我不确定它是否有意的行为。我在 Milo 测试服务器 (opc.tcp://milo.digitalpetri.com:62541/milo/( 上为两个不同的节点分别创建了两个 MonitoredItemCreateRequests,并将它们传递给订阅的 createMonitoredItems(( 方法。这两个项目的状态代码都很好。由于我想同时获取两个受监视项目的所有收集值,因此我向订阅中添加了一个通知侦听器。

NodeId dynNodeId = NodeId.parse("ns=2;s=Dynamic/RandomInt32");
NodeId statNodeId = NodeId.parse("ns=2;s=Dynamic/RandomDouble");

下面是接收数据值的回调方法:

@Override
public void onDataChangeNotification(UaSubscription subscription, List<UaMonitoredItem> monitoredItems, List<DataValue> dataValues, DateTime publishTime) {
Iterator<UaMonitoredItem> itemIterator = monitoredItems.iterator();
Iterator<DataValue> dataValueIterator = dataValues.iterator();
while(itemIterator.hasNext() && dataValueIterator.hasNext()) {
logger.info("subscription value received: item={}, value={}",
itemIterator.next().getReadValueId().getNodeId(), dataValueIterator.next().getValue());
}
}

我期望受监视项列表按照与数据值列表对应的顺序保存具有 OPC-UA 节点 ID 的项目。通过调试,可以看到两个集合的大小相等 - 这很好。但是回调中的所有监控项都有相同的节点 ID?记录的双精度值的节点 ID 应具有 ID ns=2;s=动态/随机双倍。

15:32:01.221 [milo-shared-thread-pool-0] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=0.19167566173987927}
15:32:01.221 [milo-shared-thread-pool-0] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=0.17914743791503218}
15:32:01.221 [milo-shared-thread-pool-0] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=-1911450762}
15:32:01.221 [milo-shared-thread-pool-0] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=-238565139}
15:32:02.172 [milo-shared-thread-pool-1] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=0.004420353528696297}
15:32:02.173 [milo-shared-thread-pool-1] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=1391780361}
15:32:03.171 [milo-shared-thread-pool-2] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=0.5815483661983246}
15:32:03.172 [milo-shared-thread-pool-2] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=560950904}
15:32:04.245 [milo-shared-thread-pool-2] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=0.18123040450226635}
15:32:04.246 [milo-shared-thread-pool-2] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=521198031}
15:32:05.258 [milo-shared-thread-pool-2] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=0.42193483414925215}
15:32:05.258 [milo-shared-thread-pool-2] INFO  o.e.m.e.client.SubscriptionExample - subscription value received: item=NodeId{ns=2, id=Dynamic/RandomInt32}, value=Variant{value=680732464}

我知道可以为每个节点使用单独的回调,但我想一次处理它们。

此行为是有意的还是服务器实现中的错误?

编辑:

在调试过程中,我发现回调中受监控项的集合包含 x 次相同的对象(相同的内存地址(,但 x dataValues 不同。

如果我使用 milo 示例中的本地 OPC 服务器尝试这样做,则行为相同。

您可能在创建项目时MonitoringParameters在两个项目中使用了相同的clientHandle值。

如果没有,您可以发布整个示例代码吗?

我没有获得所有订阅节点的值,而是只获取 newArrayList 中传递的最后一个节点。 尝试传递时类转换异常出错项创建于 列表项 = 订阅.创建监视项( TimestampsToReturn.Both, newArrayList(powerRequest,pressureRequest,speedRequest(, onItemCreated (.get((;

这是我的完整代码:

private void getUaSubscription(OpcUaClient client( 抛出 ExecutionException, InterruptedException {

NodeId powerNodeIdGuid = NodeId.parse("ns=2;g=14e74bd5-d38f-4f78-855f-160562262a36");
NodeId pressureNodeIdGuid = NodeId.parse("ns=2;g=14447164-47d3-44df-920d-2e22650f3cea");
NodeId windspeedNodeIdGuid = NodeId.parse("ns=2;g=0e1c766a-0c72-4d40-aa46-d181e5b08de1");
UaSubscription subscription = client.getSubscriptionManager().createSubscription(1000.0).get();
// subscribe to the Value attribute of the Power Node of R80711 device
ReadValueId readPowerValueId = new ReadValueId(
powerNodeIdGuid,
AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE
);
ReadValueId readPressureValueId = new ReadValueId(
pressureNodeIdGuid,
AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE
);
ReadValueId readSpeedValueId = new ReadValueId(
windspeedNodeIdGuid,
AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE
);
// UInteger clientHandle = subscription.nextClientHandle();
UInteger clientHandle = uint(clientHandles.getAndIncrement());
MonitoringParameters parameters = new MonitoringParameters(
clientHandle,
1000.0,     // sampling interval
null,       // filter, null means use default
uint(10),   // queue size
true        // discard oldest
);
MonitoredItemCreateRequest powerRequest = new MonitoredItemCreateRequest(
readPowerValueId,
MonitoringMode.Reporting,
parameters
);
MonitoredItemCreateRequest pressureRequest = new MonitoredItemCreateRequest(
readPressureValueId,
MonitoringMode.Reporting,
parameters
);
MonitoredItemCreateRequest speedRequest = new MonitoredItemCreateRequest(
readSpeedValueId,
MonitoringMode.Reporting,
parameters
);

BiConsumer<UaMonitoredItem, Integer> onItemCreated =
(item, id) -> item.setEventConsumer(this::onSubscriptionValue);

List<UaMonitoredItem> items = subscription.createMonitoredItems(
TimestampsToReturn.Both, //Return both the SourceTimestamp and ServerTimestamp
newArrayList(powerRequest,pressureRequest,speedRequest),
onItemCreated
).get();

for (UaMonitoredItem item : items) {
if (item.getStatusCode().isGood()) {
logger.info("item created for nodeId={}", item.getReadValueId().getNodeId());

} else {
logger.warn(
"failed to create item for nodeId={} (status={})",
item.getReadValueId().getNodeId(), item.getStatusCode());
}
}
// let the example run for 5 seconds then terminate
Thread.sleep(5000);
future.complete(client);

}

private void onSubscriptionValue(UaMonitoredItem uaMonitoredItem, DataValue dataValue( { logger.info( "收到的订阅值:项目={},值={},时间={}", uaMonitoredItem.getReadValueId((.getNodeId((, dataValue.getValue((, dataValue.getServerTime((.getJavaDate(((; } }

最新更新