milo opcuaでExtensionObjectとStructを正しく操作する方法

Nov 20 2020

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)

私は完全に間違っている可能性があるので、誰かが私にそのような問題を解決する方法を提案できますか?

回答

1 IstvánBékési Nov 23 2020 at 08:19

まず第一に、そのようなオブジェクトの配列をキャストすることはできません。代わりに、ストリーム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);
}
JakubZnamenáček Nov 26 2020 at 16:15

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-clientdictionary-readerbsd-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()
        );
    }