如何在 Eclipse Milo OpcUa 服务器上正确编写 ExtensionObject 数组?

How do I properly write an ExtensionObject Array on an Eclipse Milo OpcUa Server?

我正在尝试在 Eclipse Milo OpcUa 服务器上编写一个 ExtensionObject 数组。 我在 Java 8 和 Milo 0.2.3.

中完成所有这些工作

我测试写入服务器内容的方法是统一自动化 UaExpert 客户端和一个小 Python 客户端。两者显示相同的结果。

我有以下结构(我为此场景将其命名为 MyStructure)。它已经作为数组存在,我想将它写入相应的节点。

@Getter
@Setter
@AllArgsConstructor
public class MyStructure implements UaStructure {
    private String name;
    private Integer dataType;
    private String stringValue;
    private Integer intValue;
    private Float floatValue;

    public static final String Description = "MyStructure ";

    public static NodeId getNodeId() {
        return new NodeId(2, 3081);
    }

    @Override
    public NodeId getTypeId() {
        return getNodeId();
    }

    @Override
    public NodeId getBinaryEncodingId() {
        return getNodeId();
    }

    @Override
    public NodeId getXmlEncodingId() {
        return getNodeId();
    }

    public static class Codec extends GenericDataTypeCodec<MyStructure > {

        @Override
        public Class<MyStructure > getType() {
            return MyStructure .class;
        }

        @Override
        public MyStructure decode(SerializationContext context, UaDecoder reader) {
            return new MyStructure (
                reader.readString("Name"),
                reader.readInt32("DataType"),
                reader.readString("StringValue"),
                reader.readInt32("IntValue"),
                reader.readFloat("FloatValue")
            );
        }

        @Override
        public void encode(SerializationContext context, MyStructure myStructure, UaEncoder writer) {
            writer.writeString("Name", myStructure.getName());
            writer.writeInt32("DataType", myStructure.getDataType());
            writer.writeString("StringValue", myStructure.getStringValue());
            writer.writeInt32("IntValue", myStructure.getIntValue());
            writer.writeFloat("FloatValue", myStructure.getFloatValue());
        }
    }
}

我这样写节点,其中节点是 UaVariableNode 的一个实例,数组是我的 Array 对象,我是这样创建的:

node.setValue(new DataValue(new Variant(array)));

Object array = Array.newInstance(MyStructure.class, myStructureList.size());
for (int i = 0; i < myStructureList.size(); i++) {
    Array.set(array, i,myStructureList.get(i));
}

我像这样预先注册了 MyStructure 定义:

OpcUaBinaryDataTypeDictionary dictionary = new OpcUaBinaryDataTypeDictionary("mynamespace");
dictionary.registerStructCodec(
        new MyStructure.Codec().asBinaryCodec(),
        "MyStructure",
        new NodeId(2, 3081)
    );
OpcUaDataTypeManager.getInstance().registerTypeDictionary(dictionary);

每当我设置我的节点时,服务器都不会抱怨。它实际上设置了一些东西,准确地说它设置了42个Extension Objects。在 UaExpert 中,我看到值(包括它的时间戳)发生了变化,但我看不到实际值。该值只是 ExtensionObject 的 Array 类型,我无法读取任何嵌套值。但这是我在其他项目中看到的。它们具有自定义结构,嵌套字段在 UaExpert 中是人类可读的。

如果我在没有 Array 的情况下只写一个 MyStructure,问题不会改变。

你知道我做错了什么或根本没做吗?

现在 Milo 中的自定义结构只有在客户 reading/writing 他们提前知道结构的情况下才有效。

您缺少的(Milo 尚未实现)是围绕创建 DataTypeDictionary、在地址 space 中注册它以及将您的编解码器链接到该词典中的条目的所有复杂性通过数据类型编码。

如果您使用像 UaModeler 这样的工具并在其中创建自定义结构,然后查看生成的 XML,您会发现还有一大堆其他支持节点有了它。

当这些东西到位后,客户可以在事先不知道的情况下学习如何解码自定义结构。 Milo 的客户端也包含此功能。

另外,首先,您应该通过制作一个 ExtensionObject[] 来编码您的结构数组,每个 ExtensionObject 持有一个标量结构值。