Как правильно написать массив ExtensionObject на сервере Eclipse Milo OpcUa?
Я пытаюсь написать массив ExtensionObject на сервере Eclipse Milo OpcUa. Я делаю все это на Java 8 и на Milo 0.2.3.
Мой способ проверить то, что я написал на свой Сервер, - это клиент Unified Automation 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 объекта расширения. В UaExpert я вижу, что значение, включая его метку времени, изменилось, но я не вижу фактическое значение. Значение имеет тип Array для ExtensionObject, и я не могу прочитать ни одно из вложенных значений. Но это то, что я видел в других проектах. У них есть пользовательские структуры, а вложенные поля читаются человеком в UaExpert.
Проблема не изменится, если я сделаю это без массива и просто напишу одну MyStructure.
У вас есть идея, что я делаю неправильно или не делаю вообще?
1 ответ
В настоящее время пользовательские структуры в Milo работают только в том случае, если клиент, читающий / записывающий их, заранее знает о структуре.
То, что вы упускаете (и еще не реализовано в Milo), это вся сложность вокруг создания DataTypeDictionary, регистрации его в адресном пространстве и связывания вашего кодека с записью в этом словаре через DataTypeEncoding.
Если бы вы использовали такой инструмент, как UaModeler, и создали в нем собственную структуру, а затем взглянули на сгенерированный XML, вы бы увидели целую кучу других поддерживающих узлов, которые поддерживают его.
Когда все это происходит, клиенты могут научиться декодировать пользовательские структуры, не зная о них заранее. Клиент Майло включает в себя и эту функциональность.
Кроме того, fwiw, вы должны закодировать ваш массив структур, сделав ExtensionObject[]
, с каждым ExtensionObject
удерживая одно значение скалярной структуры.