milo opcuaでExtensionObjectとStructを正しく操作する方法
opc uaサーバーからオブジェクトを読み取ろうとしているときに、Structを正しく操作するにはどうすればよいかを尋ねたいと思います。この例をたどって、データを読み取ることができました。
しかし、今は正しく読む方法がわかりません。x値とy値の2つの配列を含むいくつかのデータ構造を読んでいると想像してみましょう。私はこのようなことをしようとしました:
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++;
}
しかし、私はこれが正しいとは思わない。
とにかく、私はジャクソンでjsonファイルを読むような何かを達成したいと思います。同じ名前のクラスを作成するには、「メンバーは適切なタイプであり、次のようなことを行います。
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
自分でデコード方法に似た独自のタイプを作成し、オーバーライドすることができます。デコーダーには、次の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を見つけます
- たとえばUaExpertを使用して、OPC UAで読み取る構造(オブジェクト)のDataTypeのNamespaceIndexとIdentifierを見つける必要があります。
- どのDataTypeかわからない場合は、この構造を表す変数を見つけるだけで、クリックすると画面の右側にDataType情報が表示されます。
2)BINARY_ENCODING_IDを見つけます
- これを見つけるには、UaExpertを使用してDataType自体を検索する必要があります。これは、Types / DataTypesの下にあるものもあります...
- あなたがそれを見つけたら、それをクリックして詳細をご覧ください
- 次に、画面の右下に「HasEncoding | Default Binary」が表示され、それをダブルクリックします
- このようにして、BINARY_ENCODING_IDのNamespaceIndexとIdentifierを受け取ります。
3)この例に従ってください
- miloのすべての部分を必要とするためには、依存関係にsdk-client、dictionary-reader、bsd-parserを含める必要があります。
- 次のようなクラスを作成します。
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()
);
}