Comment travailler correctement avec ExtensionObject et Struct dans Milo OPC UA

Nov 20 2020

Je voudrais demander comment dois-je travailler correctement avec Struct lorsque j'essaie de lire un objet à partir du serveur opc ua. J'ai parcouru cet exemple et j'ai pu lire les données.

Mais pour le moment, je ne sais pas comment les lire correctement . Imaginons que je lis une structure de données comprenant deux tableaux pour les valeurs x et y. J'ai essayé de faire quelque chose comme ça:

 Float[] x = (Float[])struct.getMember("x").getValue()
 Float[] y = (Float[])struct.getMember("y").getValue()

mais je reçois l'exception "Impossible de convertir 'java.lang.Object []' en 'java.lang.Float []'" Je peux le faire de cette façon:

float[] x = new float[100];
        int i = 0;
        for(Object o: (Object[])struct.getMember("x").getValue()){
            x[i] = (Float)o;
            i++;
        }

mais je ne pense pas que cela puisse être juste.

Quoi qu'il en soit, je voudrais réaliser quelque chose de similaire, comme la lecture d'un fichier json avec jackson. Pour avoir une classe avec le même nom que les "membres sont et avec des types appropriés et faites quelque chose comme:

OpcuaReader reader = ...
MyClass myClass = reader.read(struct, MyClass.class)

Je pourrais me tromper totalement, alors quelqu'un pourrait-il me suggérer comment résoudre un tel problème?

Réponses

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

Tout d'abord, vous ne pouvez pas lancer de tableau d'objets comme ça. Au lieu de cela, vous pouvez utiliser l'API de flux pour construire des Floats comme ceci:

Object[] objectArray = { 1.0f, 2.0f, 3, 4, 5 };
Float floatArray[] = Arrays.stream(objectArray)
  .map(Object::toString)
  .map(Float::valueOf)
  .toArray(Float[]::new);

À propos du client Milo, il existe un excellent exemple de lecture de types de données personnalisés dans ReadWriteCustomDataTypeNodeExample .

Vous pouvez créer votre propre type similaire à CustomStructTypeet remplacer la méthode de décodage pour vous-même. Le décodeur a également une readFloatArrayméthode intégrée en main:

@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

Un grand merci à istibekesi , nous parvenons à le faire fonctionner. Pour quelqu'un qui aurait le même problème, voici ce que vous devez faire:

1) Trouvez le TYPE_ID

  • vous devez trouver le NamespaceIndex et l'identifiant du DataType de la structure (objet) que vous voulez lire sur OPC UA en utilisant par exemple UaExpert
  • si vous n'êtes pas sûr de quel DataType il s'agit, trouvez simplement une variable représentant cette structure et vous verrez les informations DataType sur le côté droit de l'écran lorsque vous cliquez dessus.

2) Trouvez le BINARY_ENCODING_ID

  • pour trouver celui-ci, vous devez rechercher le DataType lui-même en utilisant UaExpert, il y en aura sous Types / DataTypes ...
  • lorsque vous le trouvez, cliquez dessus pour plus d'informations
  • puis sur la partie inférieure droite de votre écran il y aura "HasEncoding | Default Binary" et vous double-cliquez dessus
  • de cette façon, vous recevrez le NamespaceIndex et l'identifiant pour BINARY_ENCODING_ID

3) Suivez cet exemple

  • Pour avoir toutes les parties de milo dont vous avez besoin, vous devrez inclure sdk-client , dictionary-reader , bsd-parser dans vos dépendances
  • créez une classe similaire à celle-ci:
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);
        }
    }

}
  • et enregistrez le décodeur auprès du client comme ceci:
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()
        );
    }