milo opc ua에서 ExtensionObject 및 Struct를 올바르게 사용하는 방법
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)
내가 완전히 틀릴 수 있으므로 누군가가 그러한 문제를 어떻게 해결 해야하는지 제안 할 수 있습니까?
답변
우선, 이와 같은 객체 배열을 캐스팅 할 수 없습니다. 대신 스트림 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);
}
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()
);
}