如何在 milo opc ua 中正确使用 ExtensionObject 和 Struct

How to correctly work with ExtensionObject and Struct in milo opc ua

我想问一下,当我试图从 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++;
        }

但我认为这可能不对。

无论如何,我想实现类似的东西,比如用 jackson 读取 json 文件。有一些 class 具有相同的命名作为“成员是并且具有合适的类型并做类似的事情:

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

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

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

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 的类型,并为自己覆盖 decode 方法。解码器还有一个内置的 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);
}

非常感谢 istibekesi,我们设法使其正常运行。对于遇到同样问题的人,您需要做的是:

1) 找到TYPE_ID

  • 您需要找到要通过 OPC UA 读取的结构(对象)的数据类型的名称空间索引和标识符,例如 UaExpert
  • 如果您不确定它是哪种数据类型,只需找到一些表示此结构的变量,当您单击它时,您将在屏幕右侧看到数据类型信息。

2) 找到BINARY_ENCODING_ID

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

3) 关注这个example

  • 要拥有您需要的 milo 的所有部分,您需要包括 sdk-clientdictionary-readerbsd-parser 在你的依赖中
  • 创建 class 类似于:
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()
        );
    }