opcua-asyncio
opcua-asyncio copied to clipboard
DataType syntax
Hello,
I've been working on integrating some asyncio servers with LabVIEW's SystemLink OPC UA plug-in.
Following a couple of service requests we've noticed that there is a slight difference how DataType is represented. In the older opcua-python library this is represended as, for example 'String' or 'Double'. The asyncio version seems to display DataType as an ENUM for example i=12 (string). Is there a reason for this change and is it possible to enforce a particular format for DataType as it seems to prevent some clients from connecting?
Many thanks!
There isn't any change, DataTypes are always NodeIds, there are no Enums behind it. Maybe you have a minimal example?
Hi, thanks for getting back to me!
I've fired up the minimal example for python-opcua and connected using the OPC UA client in SystemLink. It shows the DataType as Double and allows me to create a monitored item.
Double is also returned when using the Open2541 library.
The same minimal example in asyncua and DataType appears as i=11 and can not be used by the client to create a monitored item?
National Instruments believe there is something slightly different between the two impliementations that is causing this?
Thanks again!
I've tried to use the same functions and syntax for both implimentations but i'm still getting the same DataType difference when using the asyncio vs pyton-opcua (DataType i=11 rather than DataType=Double)
Interestingly in UaExpert it doesn't seem to make a difference and in both instances DataType is shown as Double.
python-opcua
import time
from opcua import ua, Server
if __name__ == "__main__":
server = Server()
server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")
uri = "http://examples.freeopcua.github.io"
idx = server.register_namespace(uri)
myobj = server.nodes.objects.add_object(idx, "MyObject")
myvar = myobj.add_variable(idx, "MyVariable", 6.7)
myvar.set_writable()
server.start()
try:
count = 0
while True:
time.sleep(1)
count += 0.1
myvar.set_value(count)
finally:
server.stop()
opcua-ascyncio
import asyncio
from asyncua import ua, Server
async def main():
server = Server()
await server.init()
server.set_endpoint('opc.tcp://0.0.0.0:4840/freeopcua/server/')
uri = 'http://examples.freeopcua.github.io'
idx = await server.register_namespace(uri)
myobj = await server.nodes.objects.add_object(idx, 'MyObject')
myvar = await myobj.add_variable(idx, 'MyVariable', 6.7)
await myvar.set_writable()
async with server:
while True:
await asyncio.sleep(1)
new_val = await myvar.get_value() + 0.1
await myvar.write_value(new_val)
if __name__ == '__main__':
asyncio.run(main())
what is you see in the UI does not mean anything i=11 and Double are the same datatype. But it is a bit strange that what is shown in UI is differnet between python-opcua and opcua-asyncio. Something is confusing them. Maybe if you monitor the network with datashark you can find a difference when readong a simple double variable? maybe we are not encoding the nodeid the same way...
If compared the differences between python-opcua and asyncua and found the following:
I will make a fix to address the difference.
if that is true, there is something strange. DataTypeDefinition should only be set for ObjectTypes. No idea where the bug is but this must somewhere very deep
The default is an empty ExtensionObject. We must return a error AttributeIdInvalid if the ExtensionObject is empty. This change triggers some errors in some other code that does expect empty ExtensionObjects instead of StatusCode errors...
OK looks like your screenshot is for DataType under Types/DataTypes. Great you are looking at it. Did you check the spec for the correct behaviour?
There is nothing in the spec about empty DataTypeDefinitions. Found the following: node-ua same as asyncua open62541 same as python-opcua
I think we should return an error to keep some clients happy like UAExpert and maybe NI.
@om327 can you test it with fix #937 ? If it works we can merge it, if it doesn't help I will do some more research about the spec.
@schroeder- Aren't the clients more happy with None instead of error? I do not remember if we can set an ExtensionObject to None, but we probably can. Maybe that is what python-opcua does?
we shoul check what prosys does. They are usually very good at following spec.
OK I checked they do:
I may not have the latest server from them though...
Ok DataTypeDefinition is optional as of https://reference.opcfoundation.org/v104/Core/docs/Part3/5.8.3/. So return BadAttributeIdInvalid is ok if it doesn't exists or is empty ExtensionObject.
More than happy to test with NI SystemLink OPC UA - thanks for looking into this!
How do i download the latest changes before they are merged?
How do i use the command gh pr checkout 937
to checkout the new code?
Does this need to part of a git fetch origin
statement?
Sorry my knowledge of git is little vague beyond cloning, pulling and pushing!
Ok DataTypeDefinition is optional as of https://reference.opcfoundation.org/v104/Core/docs/Part3/5.8.3/. So return BadAttributeIdInvalid is ok if it doesn't exists or is empty ExtensionObject.
BadAttributeInvalid is fine if attribute is invalid. but I am wondering if creating empty ExtensionObject is a good idea at all in any places... maybe the default should be None instead of empty EntensionObject. Extension objects seems to be nullable: https://reference.opcfoundation.org/v105/Core/docs/Part6/5.1.2/
In that particular case the attribute should probably do not exist for these typoes apart for structs and enums
Ah found it - if in doubt just read the manual!!!
Just waiting for NI to update our license and then will be able to test out! If you want to have two versions of the attribute i can test both to see if they are both compatable?
In that particular case the attribute should probably do not exist for these typoes apart for structs and enums
I agree on this.
I recently had a similar problem, and I think it may be related to this: https://github.com/FreeOpcUa/opcua-asyncio/issues/1082
In fact, the existence of the attribute (even if it returns BadAttributeIdInvalid), I think is incorrect. The attribute is mandatory for structure or Enumeration datatypes, so I think it is optional "for other DataTypes". Finding it on types, as it happens now, I think is wrong.
Any update on this?
I quickly checked against a server with Softing SDK and I found we are missing a reference.
. This has to be fixed in the schema generator.
Also in OPC UA there is nothing like a list of available attributes. The client decides which attributes to read, based on the nodetype and references. The server can only return BadAttributeInvalid or a concret value.
How's the work going? Any progress?