如何在 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-client、dictionary-reader、 bsd-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()
);
}
我想问一下,当我试图从 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-client、dictionary-reader、 bsd-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()
);
}