java 使用milo库 获取opc ua节点数据类型

文章讲述了在OPCUA客户端向服务器写入数据时,需要确保数据类型与服务器节点的DataType匹配。BuiltinDataType枚举用于表示预定义的数据类型,提供了从NodeId获取数据类型的方法。检查数据类型是否匹配的函数是关键,以防止写入异常。
摘要由CSDN通过智能技术生成

目的

我们知道,opc ua 的节点,其value是有固定的数据类型的,即DataType
在这里插入图片描述

那么opc ua client向 opc ua server写入数据时,写入的值必须与server中的数据类型相匹配才能成功的写入进去。如果数据类型不匹配会抛出异常。

所以,我们需要获取opc ua server中节点的数据类型,通过将其与写入数据的数据类型进行对比,只有符合类型的才进行写入。

milo库中的数据类型存在BuiltinDataType 类中

BuiltinDataType类源码

/*
 * Copyright (c) 2019 the Eclipse Milo Authors
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 */

package org.eclipse.milo.opcua.stack.core;

import java.util.UUID;

import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
import org.eclipse.milo.opcua.stack.core.types.builtin.XmlElement;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
import org.eclipse.milo.opcua.stack.core.types.enumerated.IdType;
import org.eclipse.milo.opcua.stack.core.util.Namespaces;
import org.jetbrains.annotations.Nullable;

public enum BuiltinDataType {

    Boolean(1, Boolean.class),
    SByte(2, Byte.class),
    Byte(3, UByte.class),
    Int16(4, Short.class),
    UInt16(5, UShort.class),
    Int32(6, Integer.class),
    UInt32(7, UInteger.class),
    Int64(8, Long.class),
    UInt64(9, ULong.class),
    Float(10, Float.class),
    Double(11, Double.class),
    String(12, String.class),
    DateTime(13, DateTime.class),
    Guid(14, UUID.class),
    ByteString(15, ByteString.class),
    XmlElement(16, XmlElement.class),
    NodeId(17, NodeId.class),
    ExpandedNodeId(18, org.eclipse.milo.opcua.stack.core.types.builtin.ExpandedNodeId.class),
    StatusCode(19, StatusCode.class),
    QualifiedName(20, QualifiedName.class),
    LocalizedText(21, org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText.class),
    ExtensionObject(22, ExtensionObject.class),
    DataValue(23, org.eclipse.milo.opcua.stack.core.types.builtin.DataValue.class),
    Variant(24, Variant.class),
    DiagnosticInfo(25, org.eclipse.milo.opcua.stack.core.types.builtin.DiagnosticInfo.class);

    private final int typeId;
    private final Class<?> backingClass;

    BuiltinDataType(int typeId, Class<?> backingClass) {
        this.typeId = typeId;
        this.backingClass = backingClass;
    }

    public NodeId getNodeId() {
        return new NodeId(0, typeId);
    }

    public int getTypeId() {
        return typeId;
    }

    public Class<?> getBackingClass() {
        return backingClass;
    }

    private static final BiMap<Integer, Class<?>> BackingClassesById;
    private static final BiMap<NodeId, Class<?>> BackingClassesByNodeId;
    private static final BiMap<NodeId, BuiltinDataType> DataTypesByNodeId;

    static {
        ImmutableBiMap.Builder<Integer, Class<?>> builder = ImmutableBiMap.builder();
        ImmutableBiMap.Builder<NodeId, Class<?>> builder2 = ImmutableBiMap.builder();
        ImmutableBiMap.Builder<NodeId, BuiltinDataType> builder3 = ImmutableBiMap.builder();

        for (BuiltinDataType dataType : values()) {
            builder.put(dataType.getTypeId(), dataType.getBackingClass());
            builder2.put(dataType.getNodeId(), dataType.getBackingClass());
            builder3.put(dataType.getNodeId(), dataType);
        }

        BackingClassesById = builder.build();
        BackingClassesByNodeId = builder2.build();
        DataTypesByNodeId = builder3.build();
    }

    /**
     * @param backingClass the backing {@link Class} of the builtin type.
     * @return the id of the builtin type backed by {@code backingClass}.
     */
    public static int getBuiltinTypeId(Class<?> backingClass) {
        return BackingClassesById.inverse().get(maybeBoxPrimitive(backingClass));
    }

    /**
     * @param typeId the id of the builtin type.
     * @return the {@link Class} backing the builtin type.
     */
    @Nullable
    public static Class<?> getBackingClass(int typeId) {
        return BackingClassesById.get(typeId);
    }

    @Nullable
    public static Class<?> getBackingClass(NodeId typeId) {
        return BackingClassesByNodeId.get(typeId);
    }

    @Nullable
    public static Class<?> getBackingClass(ExpandedNodeId typeId) {
        if (typeId.getNamespaceIndex().intValue() == 0 && typeId.getType() == IdType.Numeric) {
            Number id = (Number) typeId.getIdentifier();
            return BackingClassesById.get(id.intValue());
        }

        return null;
    }

    @Nullable
    public static BuiltinDataType fromBackingClass(Class<?> backingClass) {
        NodeId nodeId = BackingClassesByNodeId.inverse().get(maybeBoxPrimitive(backingClass));

        return nodeId != null ? DataTypesByNodeId.get(nodeId) : null;
    }

    @Nullable
    public static BuiltinDataType fromNodeId(NodeId nodeId) {
        return DataTypesByNodeId.get(nodeId);
    }

    @Nullable
    public static BuiltinDataType fromNodeId(ExpandedNodeId nodeId) {
        if (nodeId.getIdentifier() instanceof UInteger &&
            (Namespaces.OPC_UA.equals(nodeId.getNamespaceUri()) || nodeId.getNamespaceIndex().intValue() == 0)) {

            return fromNodeId(new NodeId(0, (UInteger) nodeId.getIdentifier()));
        } else {
            return null;
        }
    }

    public static boolean isBuiltin(int typeId) {
        return BackingClassesById.containsKey(typeId);
    }

    public static boolean isBuiltin(NodeId typeId) {
        return BackingClassesByNodeId.containsKey(typeId);
    }

    public static boolean isBuiltin(ExpandedNodeId typeId) {
        return BuiltinDataType.fromNodeId(typeId) != null;
    }

    private static Class<?> maybeBoxPrimitive(Class<?> clazz) {
        if (clazz.isPrimitive()) {
            if (clazz == boolean.class) {
                return Boolean.class;
            } else if (clazz == byte.class) {
                return Byte.class;
            } else if (clazz == short.class) {
                return Short.class;
            } else if (clazz == int.class) {
                return Integer.class;
            } else if (clazz == long.class) {
                return Long.class;
            } else if (clazz == float.class) {
                return Float.class;
            } else if (clazz == double.class) {
                return Double.class;
            }
        }

        return clazz;
    }

}

获取DataType方法

NodeId serverNode = opcUaClient.getAddressSpace().getVariableNode(nodeId).getDataType();
BuiltinDataType type = BuiltinDataType.fromNodeId(serverNode);
type.toString()或者type.name就是诸如String,Integer,Boolean这些字符串。

下面是比较写入值和服务器节点类型的方法:

public static Boolean checkDataType(OpcUaClient opcUaClient, NodeId nodeId, Object value) throws UaException {
        NodeId serverNode = opcUaClient.getAddressSpace().getVariableNode(nodeId).getDataType();
        BuiltinDataType type = BuiltinDataType.fromNodeId(serverNode);
        if (type != null) {
            return value.getClass().getSimpleName().equals(type.toString());
        }
        return false;
    }
使用Java实现OPC UA读取节点数据以及对应的数据类型,需要使用OPC UAJava SDK。下面是一个简单的示例代码,演示了如何使用OPC UA Java SDK读取节点数据和数据类型: ```java public class OpcUaReader { public static void main(String[] args) throws Exception { // 创建一个OPC UA客户端 OpcUaClient client = OpcUaClient.create( new EndpointDescription("opc.tcp://localhost:4840")); // 连接到OPC UA服务器 client.connect().get(); // 读取节点数据和数据类型 NodeId nodeId = new NodeId(2, "/MyObject/MyVariable"); DataValue value = client.readValue(0, TimestampsToReturn.Both, nodeId).get(); Variant variant = value.getValue(); Object data = variant.getValue(); NodeId dataType = variant.getDataType(); System.out.println("Data: " + data); System.out.println("Data Type: " + dataType); // 断开连接 client.disconnect().get(); } } ``` 在上面的代码中,首先创建了一个OPC UA客户端,然后连接到OPC UA服务器。接着,使用`readValue`方法读取节点的数据和数据类型。最后,输出读取到的数据和数据类型。 需要注意的是,上面的代码中读取节点数据和数据类型是同步的,也就是说会阻塞当前线程,直到读取完成。如果需要异步读取节点数据和数据类型,可以使用`readValueAsync`方法,并指定回调函数。 此外,还需要在项目中引入OPC UA Java SDK的依赖,在`pom.xml`文件中添加如下内容: ```xml <dependency> <groupId>org.eclipse.milo</groupId> <artifactId>milo-client-sdk</artifactId> <version>0.4.1</version> </dependency> ``` 以上代码仅供参考,具体实现方式还需根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值