问题
I would like to ask how should I work correctly with Struct when I am trying to read some object from opc ua server. I went trough this example and I was able to read the data.
But right now I don't know how to correctly read them. Let's imagine I am reading some datastructure including two arrays for x and y values. I tried to do something like this:
Float[] x = (Float[])struct.getMember("x").getValue()
Float[] y = (Float[])struct.getMember("y").getValue()
but I receive exception "Cannot cast 'java.lang.Object[]' to 'java.lang.Float[]'" I am able to do it this way:
float[] x = new float[100];
int i = 0;
for(Object o: (Object[])struct.getMember("x").getValue()){
x[i] = (Float)o;
i++;
}
but I don't think this could be right.
Anyway I would like to achieve something similar like reading json file with jackson. To have some class with same naming asi the "members are and with suitable types and do something like:
OpcuaReader reader = ...
MyClass myClass = reader.read(struct, MyClass.class)
I could be totally wrong so could anyone suggest me how should I solve such problem?
回答1:
First of all, you cannot cast array of objects like that. Instead, you could use the stream API to construct Floats like this:
Object[] objectArray = { 1.0f, 2.0f, 3, 4, 5 };
Float floatArray[] = Arrays.stream(objectArray)
.map(Object::toString)
.map(Float::valueOf)
.toArray(Float[]::new);
About the Milo client, there is a great example of reading custom data types in ReadWriteCustomDataTypeNodeExample.
You can create your own type similar to CustomStructType
and override the decode method for yourself. The decoder also has a built in readFloatArray
method in hand:
@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);
}
回答2:
Big thanks to istibekesi, we manage to get it working. For someone who would have same problem here is what you need to do:
1) Find the TYPE_ID
- you need to find the NamespaceIndex and Identifier of the DataType of the structure (object) you want to read over OPC UA using for example UaExpert
- if you are not sure which DataType it is just find some variable representing this structure and there you will see the DataType info on the right side of the screen when you click on it.
2) Find the BINARY_ENCODING_ID
- to find this one you need to search for the DataType itself using UaExpert it will be some were under Types/DataTypes ...
- when you find it click on it for more info
- then on the right bottom part of your screen there will be "HasEncoding|Default Binary" and you double click on it
- this way you will receive the NamespaceIndex and the Identifier for BINARY_ENCODING_ID
3) Follow this example
- To have all parts of milo you need you will need to include sdk-client, dictionary-reader, bsd-parser in your dependencies
- create class similar to this:
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);
}
}
}
- and in register the decoder to the client like this:
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()
);
}
来源:https://stackoverflow.com/questions/64935020/how-to-correctly-work-with-extensionobject-and-struct-in-milo-opc-ua