Search code examples
javadatetimeopc-uainstantmilo

How do I (only) update the timestamp of an OPC UA Node using an Eclipse Milo OpcUa Server?


Thanks for reading this post. I am gratefull for every help!

Goal:

I am trying to write a ValueNode with the same value, but different timestamp on an Eclipse Milo OpcUa Server. I'm doing all this with Java 11 and Milo 0.3.7.

I tested it among others with the example in the github project. I modified the function addScalarNodes in the class ExampleNamespace to write the same value with an updated timestamp once a second. Checking the node with UaExpert, the timestamp remains on the same value. Only if I update the value too, the timestamp updates.

private void addScalarNodes(UaFolderNode rootNode) {
        UaFolderNode scalarTypesFolder = new UaFolderNode(
            getNodeContext(),
            newNodeId("HelloWorld/ScalarTypes"),
            newQualifiedName("ScalarTypes"),
            LocalizedText.english("ScalarTypes")
        );

        getNodeManager().addNode(scalarTypesFolder);
        rootNode.addOrganizes(scalarTypesFolder);

        for (Object[] os : STATIC_SCALAR_NODES) {
            String name = (String) os[0];
            NodeId typeId = (NodeId) os[1];
            Variant variant = (Variant) os[2];

            UaVariableNode node = new UaVariableNode.UaVariableNodeBuilder(getNodeContext())
                .setNodeId(newNodeId("HelloWorld/ScalarTypes/" + name))
                .setAccessLevel(ubyte(AccessLevel.getMask(AccessLevel.READ_WRITE)))
                .setUserAccessLevel(ubyte(AccessLevel.getMask(AccessLevel.READ_WRITE)))
                .setBrowseName(newQualifiedName(name))
                .setDisplayName(LocalizedText.english(name))
                .setDataType(typeId)
                .setTypeDefinition(Identifiers.BaseDataVariableType)
                .build();

            node.setValue(new DataValue(variant));

            node.setAttributeDelegate(new ValueLoggingDelegate());

            getNodeManager().addNode(node);
            scalarTypesFolder.addOrganizes(node);

            if (name.equals("Boolean")) {
                Thread t = new Thread(() -> {
                    while (true) {
                        try {
                            Thread.sleep(1000L);
                            node.setValue(new DataValue(new Variant(Boolean.FALSE)));
                            System.out.println(node.getValue().getSourceTime());
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                });
                t.start();
            }
        }
    }

My Question(s):

1) Is updating the timestamp only allowed in OPC UA specs.

2) How can I achive this with Milo?

Thanks in advance!

EDIT I check the timestamp by active reading:

Server-side writing:

private void handleValueUpdate(Object value, DateTime dateTime) {
        node.setValue(new DataValue(
            new Variant(value),
            StatusCode.GOOD,
            dateTime));
    }

Client-side reading:

VariableNode variableNode = getOpcClient().getAddressSpace().getVariableNode(new NodeId(namespaceIndex, nodeIdentifier)).get();
return variableNode.readValue().get().getSourceTime();

Solution

  • Are you checking by reading (refreshing attributes pane) or with a subscription and monitored item?

    If you're using MonitoredItems the default MonitoringFilter when not otherwise specified uses DataChangeTrigger.StatusValue, which includes changes to value or quality, but not timestamp, so most clients will not ask for or receive timestamp-only changes by default.