【问题标题】:How to correctly work with ExtensionObject and Struct in milo opc ua如何在 milo opc ua 中正确使用 ExtensionObject 和 Struct
【发布时间】:2020-11-20 18:34:19
【问题描述】:

我想问当我试图从 opc ua 服务器读取一些对象时,我应该如何正确使用 Struct。我通过了这个example 并且能够读取数据。

但现在我不知道如何正确阅读它们。假设我正在读取一些数据结构,包括 x 和 y 值的两个数组。我试图做这样的事情:

 Float[] x = (Float[])struct.getMember("x").getValue()
 Float[] y = (Float[])struct.getMember("y").getValue()

但我收到异常“无法将 'java.lang.Object[]' 转换为 'java.lang.Float[]'”我可以这样做:

float[] x = new float[100];
        int i = 0;
        for(Object o: (Object[])struct.getMember("x").getValue()){
            x[i] = (Float)o;
            i++;
        }

但我不认为这是对的。

无论如何,我想实现类似使用杰克逊读取 json 文件的功能。要有一些具有相同命名的类,“成员是并且具有合适的类型,并执行以下操作:

OpcuaReader reader = ...
MyClass myClass = reader.read(struct, MyClass.class)

我可能完全错了,所以任何人都可以建议我应该如何解决这个问题?

【问题讨论】:

    标签: java opc-ua milo


    【解决方案1】:

    首先,您不能像那样转换对象数组。 相反,您可以使用流 API 来构造 Float,如下所示:

    Object[] objectArray = { 1.0f, 2.0f, 3, 4, 5 };
    Float floatArray[] = Arrays.stream(objectArray)
      .map(Object::toString)
      .map(Float::valueOf)
      .toArray(Float[]::new);
    

    关于 Milo 客户端,ReadWriteCustomDataTypeNodeExample 中有一个很好的读取自定义数据类型的示例。

    您可以创建自己的类似于CustomStructType 的类型并自己覆盖解码方法。解码器还有一个内置的readFloatArray 方法在手:

    @Override
    public CustomStructType decode(
        SerializationContext context,
        UaDecoder decoder) throws UaSerializationException {
    
        String foo = decoder.readString("Foo");
        UInteger bar = decoder.readUInt32("Bar");
        boolean baz = decoder.readBoolean("Baz");
    
        Float[] floatArray = decoder.readFloatArray("floatArray");
    
        return new CustomStructType(foo, bar, baz);
    }
    

    【讨论】:

    • 非常感谢您的回复,我会努力解决的。这正是我想知道的。谢谢!
    • 嗨,我浏览了代码,我不太确定“getTypeId”和“getBinaryEncodingId”方法是什么以及我应该如何处理它们。
    • 我得到这个异常:java.lang.ClassCastException: class org.eclipse.milo.opcua.binaryschema.Struct 不能转换为类 OpcuaCurve (org.eclipse.milo.opcua.binaryschema.Struct和 OpcuaCurve 位于加载程序“app”的未命名模块中)
    • 您连接的是哪种 OPC 服务器?您是否首先在服务器上定义了“OpcuaCurve”?在示例中,解码器已经返回CustomStructType,因此如果您注册编解码器并编写解码器,则不应出现强制转换异常,如示例中所示。这是 CustomStructType 在示例服务器上的外观:i.imgur.com/8qgdXmE.png
    • 我自己没有实现服务器,需要从plc服务器读取数据。这是我在使用 UaExpert imgur.com/a/wUZNT1s 时看到的。
    【解决方案2】:

    非常感谢 istibekesi,我们设法让它正常工作。对于遇到同样问题的人,您需要做的是:

    1) 查找 TYPE_ID

    • 您需要找到要通过 OPC UA 读取的结构(对象)的 DataType 的 NamespaceIndex 和标识符,例如使用 UaExpert
    • 如果您不确定它是哪个 DataType,只需找到一些表示该结构的变量,当您单击它时,您将在屏幕右侧看到 DataType 信息。

    2) 查找 BINARY_ENCODING_ID

    • 要找到这个,您需要使用 UaExpert 搜索 DataType 本身,它会在 Types/DataTypes 下...
    • 当你找到它时,点击它以获取更多信息
    • 然后在屏幕右下角会出现“HasEncoding|Default Binary”,然后双击它
    • 这样您将收到 NamespaceIndex 和 BINARY_ENCODING_ID 的标识符

    3) 关注此example

    • 要拥有 milo 所需的所有部分,您需要在您的依赖关系
    • 创建类似这样的类:
    public class OpcuaCurve implements UaStructure {
    
        public static final ExpandedNodeId TYPE_ID = ExpandedNodeId.parse("ns=3;s=DT_\"PrServo_typeRuntimeDriveDiagnosticsProcessValuesTrends\".\"hmiTrend\"");
    
        public static final ExpandedNodeId BINARY_ENCODING_ID = ExpandedNodeId.parse("ns=3;s=TE_\"PrServo_typeRuntimeDriveDiagnosticsProcessValuesTrends\".\"hmiTrend\"");
    
        private final Float[] torque;
        private final Float[] speed;
    
        public OpcuaCurve() {
            this(null, null);
        }
    
        public OpcuaCurve(Float[] torque, Float[] speed) {
            this.torque = torque;
            this.speed = speed;
        }
    
        public Float[] getSpeed() {
            return speed;
        }
    
        public Float[] getTorque() {
            return torque;
        }
    
        @Override
        public ExpandedNodeId getTypeId() {
            return TYPE_ID;
        }
    
        @Override
        public ExpandedNodeId getBinaryEncodingId() {
            return BINARY_ENCODING_ID;
        }
    
        @Override
        public ExpandedNodeId getXmlEncodingId() {
            // XML encoding not supported
            return ExpandedNodeId.NULL_VALUE;
        }
    
    
    
    
    
    
    
        public static class Codec extends GenericDataTypeCodec<OpcuaCurve> {
            @Override
            public Class<OpcuaCurve> getType() {
                return OpcuaCurve.class;
            }
    
            @Override
            public OpcuaCurve decode(
                SerializationContext context,
                UaDecoder decoder) throws UaSerializationException {
    
                Float[] torqueArray = decoder.readFloatArray("motorTorque");
                Float[] speedArray = decoder.readFloatArray("motorSpeed");
    
                return new OpcuaCurve(torqueArray,speedArray);
            }
    
            @Override
            public void encode(
                    SerializationContext context,
                    UaEncoder encoder, OpcuaCurve value) throws UaSerializationException {
    
                encoder.writeFloatArray("motorTorque", value.torque);
                encoder.writeFloatArray("motorTorque", value.speed);
            }
        }
    
    }
    
    • 并将解码器注册到客户端,如下所示:
    private void registerCustomCodec(OpcUaClient client) {
            NodeId binaryEncodingId = OpcuaCurve.BINARY_ENCODING_ID
                    .local(client.getNamespaceTable())
                    .orElseThrow(() -> new IllegalStateException("namespace not found"));
    
            // Register codec with the client DataTypeManager instance
            client.getDataTypeManager().registerCodec(
                    binaryEncodingId,
                    new OpcuaCurve.Codec().asBinaryCodec()
            );
        }
    

    【讨论】:

      猜你喜欢
      • 2017-04-29
      • 2022-07-08
      • 2021-12-19
      • 2017-05-30
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多