Jak poprawnie pracować z ExtensionObject i Struct w milo opc ua
Chciałbym zapytać, jak mam poprawnie pracować ze Struct, gdy próbuję odczytać jakiś obiekt z serwera OPC UA. Przeszedłem przez ten przykład i udało mi się odczytać dane.
Ale w tej chwili nie wiem, jak je poprawnie odczytać. Wyobraźmy sobie, że czytam pewną strukturę danych, w tym dwie tablice dla wartości x i y. Próbowałem zrobić coś takiego:
Float[] x = (Float[])struct.getMember("x").getValue()
Float[] y = (Float[])struct.getMember("y").getValue()
ale otrzymuję wyjątek „Nie można przesłać 'java.lang.Object []' na 'java.lang.Float []'" Mogę to zrobić w ten sposób:
float[] x = new float[100];
int i = 0;
for(Object o: (Object[])struct.getMember("x").getValue()){
x[i] = (Float)o;
i++;
}
ale nie sądzę, żeby to mogło być właściwe.
W każdym razie chciałbym osiągnąć coś podobnego, jak czytanie pliku json z jacksonem. Aby mieć jakąś klasę z takimi samymi nazwami jak „członkowie są” i z odpowiednimi typami i wykonaj coś takiego:
OpcuaReader reader = ...
MyClass myClass = reader.read(struct, MyClass.class)
Mogę się całkowicie mylić, więc czy ktoś mógłby mi podpowiedzieć, jak mam rozwiązać taki problem?
Odpowiedzi
Po pierwsze, nie możesz rzucać tablicy takich obiektów. Zamiast tego możesz użyć interfejsu API strumienia do skonstruowania pływaków w następujący sposób:
Object[] objectArray = { 1.0f, 2.0f, 3, 4, 5 };
Float floatArray[] = Arrays.stream(objectArray)
.map(Object::toString)
.map(Float::valueOf)
.toArray(Float[]::new);
Jeśli chodzi o klienta Milo, istnieje doskonały przykład odczytu niestandardowych typów danych w ReadWriteCustomDataTypeNodeExample .
Możesz stworzyć własny typ podobny do CustomStructType
metody dekodowania i nadpisać ją dla siebie. Dekoder ma również wbudowaną readFloatArray
metodę:
@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);
}
Wielkie dzięki dla istibekesi , udało nam się to uruchomić. Dla kogoś, kto miałby tutaj ten sam problem, musisz zrobić:
1) Znajdź TYPE_ID
- musisz znaleźć NamespaceIndex i Identifier of the DataType struktury (obiektu), którą chcesz odczytać przez OPC UA, używając na przykład UaExpert
- jeśli nie jesteś pewien, który to jest typ danych, po prostu znajdź jakąś zmienną reprezentującą tę strukturę, a po kliknięciu zobaczysz informację o typie danych po prawej stronie ekranu.
2) Znajdź BINARY_ENCODING_ID
- aby znaleźć ten, musisz wyszukać sam DataType za pomocą UaExpert, niektóre z nich były w Typach / Typach danych ...
- kiedy go znajdziesz, kliknij go, aby uzyskać więcej informacji
- następnie w prawej dolnej części ekranu pojawi się "HasEncoding | Default Binary" i klikasz na niego dwukrotnie
- w ten sposób otrzymasz NamespaceIndex i identyfikator dla BINARY_ENCODING_ID
3) Postępuj zgodnie z tym przykładem
- Aby mieć wszystkie części milo, musisz uwzględnić w swoich zależnościach klienta sdk , słownik-czytnik , parser bsd
- utwórz klasę podobną do tej:
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);
}
}
}
- i zarejestruj dekoder do klienta w ten sposób:
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()
);
}