Can't connect asynchronously to opcua server
Question:
I’m trying to get a value of a node in my OPCUA server.
I’m using asyncua
on a windows 10 x64 computer.
The server is on a PLC.
When I write this in a normal task it works
client = Client("opc.tcp://192.168.1.88:4840")
# client.max_chunkcount = 5000 # in case of refused connection by the server
# client.max_messagesize = 16777216 # in case of refused connection by the server
client.connect()
But when I use the basic example using an async function with the await the line,
await client.connect()
Returns a timeoutError
with asyncio.exceptions.CancelledError
but nothing else to explain why it doesn’t work.
I would’ve kept trying without the the await
but when I try to get my value with client.nodes.root.get_child([...])
the returned value prints <coroutine object Node.get_child at 0x000002C38EE45E40>
(when it should be a simple integer or boolean) and I don’t know what to do with that so I guess I should keep going with the examples.
Do you have any idea why await client.connect()
return this exception ?
I also tried with 2 different (and built under different langages) opcua clients just to be sure it wasn’t the server that was broken. And the clients can connect properly.
EDIT: in case that helps, the console gives :
disconnect_socket was called but connection is closed
close_session was called but connection is closed
close_secure_channel was called but connection is closed
disconnect_socket was called but connection is closed
Traceback (most recent call last):
File "Python311Libasynciotasks.py", line 490, in wait_for
return fut.result()
^^^^^^^^^^^^
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "OPCgpt.py", line 28, in <module>
loop.run_until_complete(connect_to_opc_server())
File "Python311Libasynciobase_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "OPCgpt.py", line 12, in connect_to_opc_server
await client.connect()
File "Python311Libsite-packagesasyncuaclientclient.py", line 287, in connect
await self.open_secure_channel()
File "Python311Libsite-packagesasyncuaclientclient.py", line 374, in open_secure_channel
result = await self.uaclient.open_secure_channel(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Python311Libsite-packagesasyncuaclientua_client.py", line 315, in open_secure_channel
return await self.protocol.open_secure_channel(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Python311Libsite-packagesasyncuaclientua_client.py", line 232, in open_secure_channel
await asyncio.wait_for(self._send_request(request, message_type=ua.MessageType.SecureOpen), self.timeout)
File "Python311Libasynciotasks.py", line 492, in wait_for
raise exceptions.TimeoutError() from exc
TimeoutError
EDIT 2 : Someone asked me to post my code for people to be able to reproduce it. It’s very simple so the bug is pretty odd. Someone on github mentionned that I may be blocking the eventloop but I didn’t go too far off from freeopcua’s examples..
import asyncio
from asyncua import Client
async def connect_to_opc_server():
# Créez un client OPC UA
client = Client(url="opc.tcp://192.168.1.88:4840")
# client.max_chunkcount = 5000
# client.max_messagesize = 16777216
client.name = "Re_Shoes"
try:
# Connexion au serveur OPC UA
await client.connect()
# Lister tous les nœuds enfants du nœud racine (Object)
root_node = await client.get_root_node()
print("root node is: ", root_node)
finally:
# Déconnexion du serveur OPC UA
await client.disconnect()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(connect_to_opc_server())
loop.close()
This is my main code but I have tried many variations of this.
Answers:
After some back&forth I found that the issue came from the Nonce
being empty.
If you dive into the library the Nonce
is created in the open_secure_channel()
method when you call the connect()
function.
If you call the connect()
method without specifying a security_policy
the nonce size will be 0
(b''
on windows and apparently None
and some other platforms) and as I’ve seen in another github post, some servers do not like empty nonce string…
So to solve this problem with the asyncua
lib I added this code before the connect()
method and it solved my issue, I can now connect to the server.
client.security_policy.secure_channel_nonce_length = 8
def signature(self, data):
return None
fixed_signature = types.MethodType(signature, CryptographyNone)
client.security_policy.asymmetric_cryptography.signature = fixed_signature
I’m trying to get a value of a node in my OPCUA server.
I’m using asyncua
on a windows 10 x64 computer.
The server is on a PLC.
When I write this in a normal task it works
client = Client("opc.tcp://192.168.1.88:4840")
# client.max_chunkcount = 5000 # in case of refused connection by the server
# client.max_messagesize = 16777216 # in case of refused connection by the server
client.connect()
But when I use the basic example using an async function with the await the line,
await client.connect()
Returns a timeoutError
with asyncio.exceptions.CancelledError
but nothing else to explain why it doesn’t work.
I would’ve kept trying without the the await
but when I try to get my value with client.nodes.root.get_child([...])
the returned value prints <coroutine object Node.get_child at 0x000002C38EE45E40>
(when it should be a simple integer or boolean) and I don’t know what to do with that so I guess I should keep going with the examples.
Do you have any idea why await client.connect()
return this exception ?
I also tried with 2 different (and built under different langages) opcua clients just to be sure it wasn’t the server that was broken. And the clients can connect properly.
EDIT: in case that helps, the console gives :
disconnect_socket was called but connection is closed
close_session was called but connection is closed
close_secure_channel was called but connection is closed
disconnect_socket was called but connection is closed
Traceback (most recent call last):
File "Python311Libasynciotasks.py", line 490, in wait_for
return fut.result()
^^^^^^^^^^^^
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "OPCgpt.py", line 28, in <module>
loop.run_until_complete(connect_to_opc_server())
File "Python311Libasynciobase_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "OPCgpt.py", line 12, in connect_to_opc_server
await client.connect()
File "Python311Libsite-packagesasyncuaclientclient.py", line 287, in connect
await self.open_secure_channel()
File "Python311Libsite-packagesasyncuaclientclient.py", line 374, in open_secure_channel
result = await self.uaclient.open_secure_channel(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Python311Libsite-packagesasyncuaclientua_client.py", line 315, in open_secure_channel
return await self.protocol.open_secure_channel(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Python311Libsite-packagesasyncuaclientua_client.py", line 232, in open_secure_channel
await asyncio.wait_for(self._send_request(request, message_type=ua.MessageType.SecureOpen), self.timeout)
File "Python311Libasynciotasks.py", line 492, in wait_for
raise exceptions.TimeoutError() from exc
TimeoutError
EDIT 2 : Someone asked me to post my code for people to be able to reproduce it. It’s very simple so the bug is pretty odd. Someone on github mentionned that I may be blocking the eventloop but I didn’t go too far off from freeopcua’s examples..
import asyncio
from asyncua import Client
async def connect_to_opc_server():
# Créez un client OPC UA
client = Client(url="opc.tcp://192.168.1.88:4840")
# client.max_chunkcount = 5000
# client.max_messagesize = 16777216
client.name = "Re_Shoes"
try:
# Connexion au serveur OPC UA
await client.connect()
# Lister tous les nœuds enfants du nœud racine (Object)
root_node = await client.get_root_node()
print("root node is: ", root_node)
finally:
# Déconnexion du serveur OPC UA
await client.disconnect()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(connect_to_opc_server())
loop.close()
This is my main code but I have tried many variations of this.
After some back&forth I found that the issue came from the Nonce
being empty.
If you dive into the library the Nonce
is created in the open_secure_channel()
method when you call the connect()
function.
If you call the connect()
method without specifying a security_policy
the nonce size will be 0
(b''
on windows and apparently None
and some other platforms) and as I’ve seen in another github post, some servers do not like empty nonce string…
So to solve this problem with the asyncua
lib I added this code before the connect()
method and it solved my issue, I can now connect to the server.
client.security_policy.secure_channel_nonce_length = 8
def signature(self, data):
return None
fixed_signature = types.MethodType(signature, CryptographyNone)
client.security_policy.asymmetric_cryptography.signature = fixed_signature