Usage of ExtensionObjects #839
Replies: 10 comments 18 replies
-
Is it also possible to decode a ExtensionObject returned by a position = client.get_node('ns=6;s=::Sample:System.Shuttles[0].Info.Position')
data = await position.read_value() which gives me the following object ( ExtensionObject(TypeId=NodeId(Identifier=100011, NamespaceIndex=6, NodeIdType=<NodeIdType.Numeric: 2>), Body=b'{\xf7\xa8>H\x99\x99>!\xe7]9\x00\x80V:\x00@\xf7:\x00\x00 \xb8') Is it possible to decode this object? It seems like the data type / variable type is not loaded with |
Beta Was this translation helpful? Give feedback.
-
So now that I'm a step further I stumbled accross the following problem: I have the following two custom structs: @dataclass
class Sample_Cmd_MoveAsync_ParameterType:
TargetPos: List['ua.Sample_Cmd_MoveAsync_ShTargetPos_type'] = field(default_factory=list)
AccDec: ua.Float = 0
Speed: ua.Float = 0
@dataclass
class Sample_Cmd_MoveAsync_ShTargetPos_type:
X: ua.Float = 0
Y: ua.Float = 0 It seems like the serializers for I tried the following two methods: positions = [(0.05, 0.06), (0.19, 0.18), (0.33, 0.3), (0.42, 0.42),
(0, 0), (0, 0), (0, 0), (0, 0)]
speed = 0.3
accdec = 0.1
param = autogenerated.Sample_Cmd_MoveAsync_ParameterType(
Speed=speed,
AccDec=accdec,
TargetPos=ua.Variant(
[autogenerated.Sample_Cmd_MoveAsync_ShTargetPos_type(*pos) for pos in positions],
ua.VariantType.ExtensionObject,
[8],
),
) This gives me a And this: positions = [(0.05, 0.06), (0.19, 0.18), (0.33, 0.3), (0.42, 0.42),
(0, 0), (0, 0), (0, 0), (0, 0)]
speed = 0.3
accdec = 0.1
param = autogenerated.Sample_Cmd_MoveAsync_ParameterType(
Speed=speed,
AccDec=accdec,
TargetPos=positions,
) gives me a Is this currently not supported or am I doing something wrong? |
Beta Was this translation helpful? Give feedback.
-
This should work
|
Beta Was this translation helpful? Give feedback.
-
Hi, I am trying to use the client API and reading an extension object with nested structures in it. I get Not Enough Data error as shown below. Which configuration parameter can be updated to read a larger blob for the same. raise NotEnoughData(f"Not enough data left in buffer, request for {size}, we have {self._size}") |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Hi, I'm trying to figure out if there's a problem when ExtensionObjects have fields that are optional arrays. When trying to read the value from a Python client, it works fine when the optional field is populated, even with an empty list, but when that optional field is omitted, we get a decode error. Seems like the field is being treated as mandatory for deserialization. I did notice that the server is giving null ArrayDimensions for this field, rather than 0 like it apparently should according to opc spec, so that could be a problem. (https://reference.opcfoundation.org/Core/Part3/v104/docs/8.51) Also I can't use Just wondering if anyone can reproduce this or if it's an issue with the server Code using example type from OPC-30060 import asyncio
from asyncua import Client, ua
from asyncua.common.structures104 import load_custom_struct, load_enums
async def main():
async with Client(SERVER_ENDPOINT) as client:
# Example variable node instance of MaterialDefinitionType
node = client.get_node("ns=3;s=1012/9:MaterialDefinition")
# # Can't load all types for some reason from this companion nodeset, separate issue?
# await client.load_data_type_definitions() # Broken
# I had to fix this function in the library to load the type structure manually
await load_enums(client)
await load_custom_struct(client.get_node("ns=9;i=3019")) # DataDescriptionType
await load_custom_struct(client.get_node("ns=9;i=3011")) # DataValueType
await load_custom_struct(client.get_node("ns=9;i=3010")) # MaterialDefinitionType
# Can't read the value now that the structure is loaded
print(await node.read_value()) # Broken - decode error
if __name__ == "__main__":
asyncio.run(main()) Looking into ua_binary.py in the library, I see that in enc_count = 0
field_deserializers = []
# TODO: adding the 'ua' module to the globals to resolve the type hints might not be enough.
# its possible that the type annotations also refere to classes defined in other modules.
resolved_fieldtypes = typing.get_type_hints(objtype, {'ua': ua})
for field in fields(objtype):
optional_enc_bit = 0
field_type = resolved_fieldtypes[field.name]
subtypes = type_allow_subclass(field.type)
# if our member has a switch and it is not set we will need to skip it
if type_is_union(field_type):
optional_enc_bit = 1 << enc_count
enc_count += 1
if subtypes:
deserialize_field = extensionobject_from_binary
else:
deserialize_field = _create_type_deserializer(field_type, objtype)
field_deserializers.append((field, optional_enc_bit, deserialize_field)) Value read from server before decode: Sample decode error:
|
Beta Was this translation helpful? Give feedback.
-
I should be able to look at the issue at the weekend. Can you lower the logging to debug around the struct creation and copy out the created python code for these structs? |
Beta Was this translation helpful? Give feedback.
-
Hi i was not able to figure out how to access fields in a custom ExtensionObject. After playing around with the code i could do it. Maybe posting the code here is helpful for someone else as well. In the Server:
In the Client:
|
Beta Was this translation helpful? Give feedback.
-
Hi, I was wondering if someone figured out a way to cache the datatypes?
guess I need to serialize and deserialze the enums, has someone done that? Or is there an out of the box solution i've overseen? Thanks in advance |
Beta Was this translation helpful? Give feedback.
-
Many of you struggle with them ^^ let me give you some hints:
ExtensionObjects are DataTypes/Structures
some of them are built-in into OPC UA Core like "Range"
with more OPC UA Companion Spec. being released, custom structures get more and more common in the field! that means a client which just knows the core structures is unable to interact with them (simply because the client does not know them!)
but a client can load them with:
it will create classes under ua-module on the fly and can be accessed by their name:
Debugger:
and if you want to write a Variable of type ExtensionObject, please note:
A "ExtensionObject" is a "VariantType" that means you need to create a "Variant-Class" instance of datatype "ua.VariantType.ExtensionObject" so now we know its value is a structure (but atm not what type of structure exactly!) then you pass a class instance to the variants value property (e.g. "StandstillReasonType") now its clear that the Variant is an "ExtensionObject" of type "StandstillReasonType"
Example:
Happy coding!
Beta Was this translation helpful? Give feedback.
All reactions