milo opc ua에서 ExtensionObject 및 Struct를 올바르게 사용하는 방법

Nov 20 2020

opc ua 서버에서 일부 개체를 읽으려고 할 때 Struct에서 올바르게 작동하는 방법을 묻고 싶습니다. 이 예제 를 살펴보고 데이터를 읽을 수있었습니다.

하지만 지금은 올바르게 읽는 방법을 모르겠습니다 . x 및 y 값에 대한 두 개의 배열을 포함하는 일부 데이터 구조를 읽고 있다고 가정 해 봅시다. 나는 다음과 같은 것을 시도했다.

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

하지만 "Cannot cast 'java.lang.Object []'to '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를 사용하여 다음과 같이 Floats를 생성 할 수 있습니다.

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 및 식별자를 찾아야합니다.
  • 어떤 데이터 유형이 있는지 확실하지 않은 경우이 구조를 나타내는 일부 변수를 찾고 클릭하면 화면 오른쪽에 데이터 유형 정보가 표시됩니다.

2) BINARY_ENCODING_ID 찾기

  • 이것을 찾으려면 UaExpert를 사용하여 DataType 자체를 검색해야합니다. 일부는 Types / DataTypes 아래에 있습니다.
  • 더 많은 정보를 원하시면 클릭하세요
  • 그러면 화면 오른쪽 하단에 "HasEncoding | Default Binary"가 있고 더블 클릭합니다.
  • 이렇게하면 BINARY_ENCODING_ID에 대한 NamespaceIndex 및 식별자를 받게됩니다.

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