有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何可靠地写入OPC UA服务器?

我正在尝试向OPC UA服务器写入一些值。为了可靠地做到这一点,我可能需要知道我试图写入的节点的数据类型,否则我似乎很容易得到数据类型不匹配

假设我的服务器有一个数据类型为Int16的节点TestNodeOne

我的API被告知将值3写入该节点。现在我需要做一个决定:我是将3作为一个整数处理还是作为一个UShort处理?为此,我似乎需要节点的数据类型

我试过的

我的方法是浏览服务器,并使用相应的数据类型创建其所有节点的缓存。这看起来是这样的:

// Recursively browse entire server
@SuppressWarnings("deprecation")
private HashMap<String, NodeId> browseNode(String indent, OpcUaClient client, NodeId browseRoot, HashMap<String, NodeId> nodesMap) {

    BrowseDescription browse = new BrowseDescription(
            browseRoot,
            BrowseDirection.Forward,
            Identifiers.References,
            true, uint(NodeClass.Object.getValue() | NodeClass.Variable.getValue()),
            uint(BrowseResultMask.All.getValue()));

    try {
        BrowseResult browseResult = client.browse(browse).get();
        List<ReferenceDescription> references = toList(browseResult.getReferences());

        for (ReferenceDescription rd : references) {

            UShort namespaceIndex = rd.getNodeId().getNamespaceIndex();
            String identifier = rd.getNodeId().getIdentifier().toString();
            NodeId node = new NodeId(namespaceIndex, identifier);
            nodesMap.put(rd.getNodeId().getIdentifier().toString(), node);

            logger.info("----------------------------------------------------------------");
            logger.info(identifier);
            logger.info("TYPE " + rd.getTypeDefinition()); // Not the right node
            logger.info("TYPE " + rd.getTypeId().getIdentifier().toString()); // Not the right node
            logger.info("TYPE " + rd.getReferenceTypeId().getIdentifier().toString()); // Not the right node

            rd.getNodeId().local().ifPresent(nodeId -> {
                browseNode(indent + "  ", client, nodeId, nodesMap);
            });
        }

    } catch (InterruptedException | ExecutionException e) {
        logger.error("Browsing nodeId={} failed: {}", browseRoot, e.getMessage(), e);
    }

    return nodesMap;
}

我不知道如何获取节点的数据类型。我想我走错了方向。 如何查找节点的数据类型


共 (3) 个答案

  1. # 1 楼答案

    最简单的方法是在每次写入之前读取数据类型属性,以便知道要发送什么类型的值

    一旦你有了这个工作,你可以尝试一些更棘手的事情,比如缓存数据类型,这样以后对同一个节点的写入就不需要再次读取数据类型属性,然后如果一次写入失败,并且错误的类型不匹配,你可以使该节点的缓存中的条目无效,然后重试读+写

  2. # 2 楼答案

    要知道在节点的值中写入哪种数据类型,最简单的方法是在写入之前发送读取请求值

    ReadRequest
      -  ...
      -  NodesToRead [ReadValueId]
        - ReadValue[0]
          - NodeId:       {NodeId of your Node}
          - AttribueId:   Value (0x0d)
          - IndexRange:   Null
          - DataEncoding: Null
    

    在读取响应中,您将获得节点的当前值及其OPC UA数据类型

    ReadResponse
      - ResponseHeader
      - Results [DataValue]
         - DataValue[0]
           - EncodingMask
           - Value 
             - VariantType: Int16
             - Int16:       3
    

    编辑:如注释中所述,当前值也可能为空。因此,除了读取节点的Value属性,还可以读取DataType属性

    对于“非内置”OPC UA数据类型,您必须:

    • 已经知道数据类型及其结构,以允许您编写正确的信息

    • 浏览HasTypeDefinition的TargetNode

    ie:Server_ServerStatus(NodeId[i=2256])有一个数据类型ServerStatusDataType(NodeId[i=862])和一个HasTypeDefinition ServerStatusType(NodeId[i=2138])。 通过浏览ServerStatusType,您将获得这个复杂数据类型的结构。在这种情况下:

     - ServerStatusType      [ServerStatusDataType]
       - BuildInfo           [BuildInfoType] -> Also a complex Datatype
       - CurrentTime         [UtcTime]
       - SecondsTillShutdown [UInt32]
       - ShutdownReason      [LocalizedText]
       - StartTime           [UtcTime]
       - State               [ServerState] -> Also a complex Datatype
    
  3. # 3 楼答案

    首先,我认为你应该阅读值类型,比如

    DataValue value = opcUaClient.readValue(0.0, TimestampsToReturn.Neither, nodeId).get();
    Optional<ExpandedNodeId> dataType = value.getValue().getDataType();
    

    其次,使用Unsigned类方法来查找您想要的类型:

    Variant v = new Variant(Unsigned.ushort(22));