14:11, EET
November 29, 2021
I was trying to decode some extensionObject that I receive from some OPC UA server written
in python. For some custom structures, everything worked fine. Here, I automatically received a dynamicStructure
by calling
DynamicStructure dynamicStructure = uaValueNode.getValue().getValue().asClass(DynamicStructure.class, null);
For others, I only received an extensionObject. I tried to decode it using
uaClient.getTypeDictionary().decode()
This did not work. I looked into the typeDictionary, it did not contain the StructureSpecification for the structure in question.
I know that typeDictionary might not be used anymore since 1.04, so I tried
extensionObject.decode(uaClient.getEncoderContext()) and
uaClient.getEncoderContext().decode().
I am using the version 4.5.0.
I received
Caused by: com.prosysopc.ua.stack.encoding.DecodingException: Bad_DecodingError (code=0x80070000, description=”Cannot decode null”)
at com.prosysopc.ua.stack.encoding.utils.SerializerComposition.getEncodeable(SourceFile:107)
at com.prosysopc.ua.stack.builtintypes.ExtensionObject.decode(SourceFile:500)
at com.prosysopc.ua.stack.builtintypes.ExtensionObject.decode(SourceFile:396)
at com.prosysopc.ua.stack.builtintypes.ExtensionObject.decode(SourceFile:355)
The custom structure that doesn’t work was defined as follows:
structBuffer[‘my_type’], _ = await new_struct(opcuaServer, nsIdx, “my_type”, [
new_struct_field(“a”, ua.VariantType.String),
new_struct_field(“b”, ua.VariantType.String, array=True),
new_struct_field(“c”, ua.VariantType.String, array=True)
])
The difference to the working complex type is that they don’t contain arrays.
13:26, EET
April 3, 2012
Hi,
By python you mean this https://github.com/FreeOpcUa/python-opcua or something else?
Anyway, your version of our SDK is kinda old. Could you please try with the latest release 4.6.2, some thing are fixed after the version you have (https://downloads.prosysopc.com/opcua/Prosys_OPC_UA_SDK_for_Java_4_Release_Notes.html).
Given that this functionality completely relies on the server to send the correct data, the most logical explanation would be that either the DataTypeDefinition (if the server uses that new 1.04 Attribute) or the old DataTypeDictionaries data is incorrect. I would need to see those for the structure type in question to know better. Alternatively the encoding might have been done incorrectly, for that typically the only practical way would be to check with wireshark: https://www.prosysopc.com/blog/opc-ua-wireshark/ i.e. what the actual binary was.
Or it is possible that it could be a bug in our SDK, custom structures is one of the more complicated OPC UA features.
In OPC UA 1.04 the structure fields can be multidimensional arrays, since your code just shows array=True, I’m assuming they are onedimensional.
You could try turning logging to DEBUG on the package ‘com.prosysopc.ua.typedictionary’. However, please do the SDK update to 4.6.2 before that, as the logging as also been improved in the later releases.
Also, note that in the encoded form the TypeId within an ExtensionObject is not the DataType NodeId of the type, but the NodeId of an ‘Encodings node’ below that (they are liked with non-hierarchical reference HasEncoding type, so they are typically not visible in trees that show the address space). So if custom Structure types are created, so must the encodings nodes. Then when the old DataTypeDictionaries are in use, the “path continues” sort of from the Encodings nodes to description nodes that then do link to the actual dictionary, which is an XML document as UTF-8 as ByteString in the dictionary node and within the dictionary xml namespaces are used i.e. it gets complicated quite fast).
The TypeDictionary class of the SDK in 4.x along with StructureSpecification etc. is an abstraction (initially it was just for the dictionaries). The TypeDictionary prefers DataTypeDefinition nowadays, but if not all types were successfully resolved via them it will revert to looking also the old DataTypeDictionaries. In practice all the ways you tried to decode is the same operation, but just accessed in a different way (and also what the SDK does internally whenever ExtensionObjects are received over the wire, thus in 4.x manual decoding pretty much cannot work if the automatic didn’t, unless you explicitly disable that automatic logic).
In 4.x, you should be fine with just asking Structure.class instead of DynamicStructure.class, as the API to use both should be pretty much the same.
P.S.
Not related to this, since you only have Strings as the type, but any ‘OptionSet’ Structure subtype would be a problem for us currently (as they use EnumDefition and not StructureDefinition and SDK sort of assumes every Structure type has a StructureDefinition in the DataTypeDefinition).
12:10, EET
November 29, 2021
Hi,
thanks for the detailed answer!
By python I mean https://github.com/FreeOpcUa/opcua-asyncio.
I updated the sdk to 4.6.2, but the problem is still there.
I sent a mail with the dataTypeDefinition and with what I received from wireshark.
One information that I forgot: I also tried to read the value of the complex type with UaExpert and it did work.
From debugging, I received
Could not resolve id http://…/customNamespace/:17 to StructureSpecification via DataTypeDefinition Attribute: java.lang.IllegalArgumentException: The given ValueRank must be either -1 or 1 or larger)
at com.prosysopc.ua.typedictionary.FieldSpecification$Builder.setValueRank(SourceFile:149)
at com.prosysopc.ua.typedictionary.TypeDictionary.b(SourceFile:660)
at com.prosysopc.ua.typedictionary.TypeDictionary.b(SourceFile:1460)
at com.prosysopc.ua.typedictionary.TypeDictionary.getStructureSpecification(SourceFile:426)
at com.prosysopc.ua.client.UaClient$3.get(SourceFile:6273)
at com.prosysopc.ua.stack.encoding.EncoderContext.getStructureSpecification(SourceFile:354)
at com.prosysopc.ua.stack.builtintypes.ExtensionObject.decode(SourceFile:488)
at com.prosysopc.ua.stack.builtintypes.ExtensionObject.decode(SourceFile:391)
at com.prosysopc.ua.stack.builtintypes.ExtensionObject.decode(SourceFile:350)
at com.prosysopc.ua.stack.encoding.binary.BinaryDecoder.getVariant(SourceFile:1758)
at com.prosysopc.ua.stack.encoding.binary.BinaryDecoder.getDataValue(SourceFile:694)
at com.prosysopc.ua.stack.encoding.binary.BinaryDecoder$17.s(SourceFile:276)
at com.prosysopc.ua.stack.encoding.binary.BinaryDecoder$17.c(SourceFile:272)
at com.prosysopc.ua.stack.encoding.binary.BinaryDecoder.get(SourceFile:498)
at com.prosysopc.ua.types.opcua.Serializers$ReadResponseSerializer.getEncodeable(SourceFile:11514)
at com.prosysopc.ua.StructureSerializer.getEncodeable(SourceFile:83)
at com.prosysopc.ua.stack.encoding.utils.AbstractSerializer.getEncodeable(SourceFile:155)
at com.prosysopc.ua.stack.encoding.utils.SerializerComposition.getEncodeable(SourceFile:109)
at com.prosysopc.ua.stack.encoding.binary.BinaryDecoder.getMessage(SourceFile:1306)
at com.prosysopc.ua.stack.transport.tcp.io.TcpConnection$b$1.run(SourceFile:783)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
12:47, EET
November 29, 2021
9:56, EET
April 3, 2012
(Note that I answered this without looking the mail, since it should be “solved” based on this)
Then this is really easy to answer: Structure fields are not allowed to have ValueRank of 0. See https://reference.opcfoundation.org/Core/docs/Part3/8.51/ the table 35 row ” valueRank Int32 The value rank for the field.It shall be Scalar (-1) or a fixed rank Array (>=1).” i.e. the dimensions of the field must be known.
It is basically an error in the python implementation if it allows you to do that.
While theoretically you could encode such structure, it would be impossible to decode. Structure fields are put to the binary “as-is” sequentially without any “headers”. This means the decoder would have no way to know if it is a scalar (get the value directly) or array (get first the Int32 for the array length). Multidim fields would be even more complicated as they have a sort of a custom form to decode.
You should be getting quite the same semantics by using ValueRank 1 and when it is “scalar” just put the array with single element there. Or you could do some crazy things like define an Union that has the scalar and array and use that as the field of the Structure, though I would only do this if there is semantic difference of scalar and array having the same scalar as the single element.
P.S.
UaExpert sometimes allows stuff which is incorrect. It is possible that your version of UaExpert is reading the old DataTypeDictionaries, in which I do not think there was a concept where one could accidentally model “ValueRank 0”, since the dictionary cannot even model multidimensional fields in the first place. So maybe UaExpert sort of just ignored the issue.
Most Users Ever Online: 1919
Currently Online:
17 Guest(s)
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Heikki Tahvanainen: 402
hbrackel: 144
rocket science: 88
pramanj: 86
Francesco Zambon: 83
Ibrahim: 78
Sabari: 62
kapsl: 57
gjevremovic: 49
Xavier: 43
Member Stats:
Guest Posters: 0
Members: 735
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1523
Posts: 6449
Newest Members:
rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerley, Thomassnism, biancacraft16Moderators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1