Open Jackarnd opened 12 months ago
timeout happens if the server is not reachable or not responding to a request... the actual reason can only be guessed 😅
get_child under the hood sends a browse request to the server thats why you need to await it.
possibly every network request could fail so you could use try/excepts to catch the specific errors
@AndreasHeine I tried connecting with 2 opcua client (Opc.Ua.SampleClient from OPC foundation and UaExpert) and they can connect properly so my server is reachable that's why I'm really wondering why I'm stuck. Also I can access the server when I don't use the await. If I run this code :
client = Client("opc.tcp://192.168.1.88:4840")
client.connect()
root = client.get_root_node()client.connect()
I get the right identifier number. But when I try the same with an async def
I can't connect
async def connect_to_opc_server():
client = Client(url="opc.tcp://192.168.1.88:4840")
client.name = "Re_Shoes"
await client.connect() # Exception here
root_node = await client.get_root_node()
print("root node is: ", root_node)
@AndreasHeine I tried connecting with 2 opcua client (Opc.Ua.SampleClient from OPC foundation and UaExpert) and they can connect properly so my server is reachable that's why I'm really wondering why I'm stuck. Also I can access the server when I don't use the await. If I run this code :
client = Client("opc.tcp://192.168.1.88:4840") client.connect() root = client.get_root_node()client.connect()
I get the right identifier number. But when I try the same with an
async def
I can't connectasync def connect_to_opc_server(): client = Client(url="opc.tcp://192.168.1.88:4840") client.name = "Re_Shoes" await client.connect() # Exception here root_node = await client.get_root_node() print("root node is: ", root_node)
if so you probably blocking the eventloop...
if you try to run multiple clients in one python program you need to create a asyncio task for each which can run independently
@AndreasHeine How can I unblock the eventloop ? (I'm sorry I'm just starting with Python and asyncua so not ideal I understand) At the end of my code I have this :
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(connect_to_opc_server())
Would it be the reason of all this fuss ?
Because my code is fairly simple and always include a client.disconnect() somewhere. So I'm not running multiple clients in one program.
maybe this could help you https://github.com/AndreasHeine/opcua-tutorial/blob/main/client/BaseClient.py
if you want to use asyncua you should look into the basics of python asyncio!
client.get_root_node()
doesn't do anything with the server, so it does work if you are not connected.
If you want to know why connect
doesn't work, activate logging and post the result.
@schroeder- The code doesn't go to client.get_root_node() since it gets stuck at connect. Using @AndreasHeine 's code I get this exception at connect :
Exception has occurred: TimeoutError
exception: no description
asyncio.exceptions.CancelledError:
The above exception was the direct cause of the following exception:
File "C:\Users\...\Code\Python\OPCUA.py", line 24, in main
await client.connect()
File "C:\Users\...\Code\Python\OPCUA.py", line 42, in <module>
asyncio.run(main())
TimeoutError:
And the log gives nothing much :
Code\Python> & 'C:\Users\...\AppData\Local\Programs\Python\Python311\python.exe' 'c:\Users\...\.vscode\extensions\ms-python.python-2023.14.0\pythonFiles\lib\python\debugpy\adapter/../..\debugpy\launcher' '25870' '--' 'c:\Users\...\Code\Python\OPCUA.py'
WARNING:asyncua.client.ua_client.UaClient:disconnect_socket was called but connection is closed
Are you sure you are using the correct hostname/ip and port?
this basic example has to work first:
import asyncio
import logging
from asyncua import Client, ua
logging.basicConfig(level=logging.WARNING)
_logger = logging.getLogger('asyncua')
async def main():
client = Client(url="opc.tcp://127.0.0.1:48010", timeout=4)
try:
await client.connect()
except Exception as e:
print(e)
return
'''
clientcode!
'''
try:
await client.disconnect()
except Exception as e:
print(e)
return
if __name__ == "__main__":
asyncio.run(main())
@schroeder- Yes it works on UA sample client and ua expert, that's why I 'm very confused. On both programs I'm able to browse through the nodes...
@AndreasHeine I tried this exemple you sent and I'm still stuck at connect()
I may add that I'm working on visual studio code and my interpreter is set to the global python in my computer
@schroeder- I'm sure I'm using the right IP because when I change the port I get a different exception telling me the connection has been refused
whats the logging output in the console?
you can set the loglevel from WARNING to DEBUG as well!
@AndreasHeine
PS C:\Users\...\Code\Python> c:; cd 'c:\Users\...\Code\Python'; & 'C:\Users\...\AppData\Local\Programs\Python\Python311\python.exe' 'c:\Users\...\.vscode\extensions\ms-python.python-2023.14.0\pythonFiles\lib\python\debugpy\adapter/../..\debugpy\launcher' '26121' '--' 'c:\Users\...\Code\Python\OPCUA.py'
WARNING:asyncua.client.ua_client.UaClient:disconnect_socket was called but connection is closed
could you try:
logging.basicConfig(level=logging.DEBUG)
and repost output!
@AndreasHeine Yes sorry, here it is :
DEBUG:asyncio:Using proactor: IocpProactor
INFO:asyncua.client.client:connect
INFO:asyncua.client.ua_client.UaClient:opening connection
INFO:asyncua.uaprotocol:updating client limits to: TransportLimits(max_recv_buffer=65536, max_send_buffer=65536, max_chunk_count=10, max_message_size=0)
INFO:asyncua.client.ua_client.UASocketProtocol:open_secure_channel
DEBUG:asyncua.client.ua_client.UASocketProtocol:Sending: OpenSecureChannelRequest(TypeId=FourByteNodeId(Identifier=446, NamespaceIndex=0, NodeIdType=<NodeIdType.FourByte: 1>), RequestHeader_=RequestHeader(AuthenticationToken=NodeId(Identifier=0, NamespaceIndex=0, NodeIdType=<NodeIdType.TwoByte: 0>), Timestamp=datetime.datetime(2023, 9, 7, 8, 34, 11, 975082), RequestHandle=1, ReturnDiagnostics=0, AuditEntryId=None, TimeoutHint=1000, AdditionalHeader=ExtensionObject(TypeId=NodeId(Identifier=0, NamespaceIndex=0, NodeIdType=<NodeIdType.TwoByte: 0>), Body=None)), Parameters=OpenSecureChannelParameters(ClientProtocolVersion=0, RequestType=<SecurityTokenRequestType.Issue: 0>, SecurityMode=<MessageSecurityMode.None_: 1>, ClientNonce=b'', RequestedLifetime=3600000))
INFO:asyncua.client.ua_client.UASocketProtocol:Socket has closed connection
WARNING:asyncua.client.ua_client.UaClient:disconnect_socket was called but connection is closed
I know some server don't like when max_chunk_count=10
, max_message_size=0
are set to 0 or a low value so I tried to add this to my code
client.max_chunkcount = 5000
client.max_messagesize = 16777216
However max_chunk_count doesn't seem to be affected and stays at 10
, maybe it comes from that ?
DEBUG:asyncio:Using proactor: IocpProactor
INFO:asyncua.client.client:connect
INFO:asyncua.client.ua_client.UaClient:opening connection
INFO:asyncua.uaprotocol:updating client limits to: TransportLimits(max_recv_buffer=65536, max_send_buffer=65536, max_chunk_count=10, max_message_size=16777216)
INFO:asyncua.client.ua_client.UASocketProtocol:open_secure_channel
DEBUG:asyncua.client.ua_client.UASocketProtocol:Sending: OpenSecureChannelRequest(TypeId=FourByteNodeId(Identifier=446, NamespaceIndex=0, NodeIdType=<NodeIdType.FourByte: 1>), RequestHeader_=RequestHeader(AuthenticationToken=NodeId(Identifier=0, NamespaceIndex=0, NodeIdType=<NodeIdType.TwoByte: 0>), Timestamp=datetime.datetime(2023, 9, 7, 8, 35, 24, 328039), RequestHandle=1, ReturnDiagnostics=0, AuditEntryId=None, TimeoutHint=1000, AdditionalHeader=ExtensionObject(TypeId=NodeId(Identifier=0, NamespaceIndex=0, NodeIdType=<NodeIdType.TwoByte: 0>), Body=None)), Parameters=OpenSecureChannelParameters(ClientProtocolVersion=0, RequestType=<SecurityTokenRequestType.Issue: 0>, SecurityMode=<MessageSecurityMode.None_: 1>, ClientNonce=b'', RequestedLifetime=3600000))
INFO:asyncua.client.ua_client.UASocketProtocol:Socket has closed connection
WARNING:asyncua.client.ua_client.UaClient:disconnect_socket was called but connection is closed
max_chunksize max_messagesize
will be negotiated while Hello/Ack Message
i am currently not on windows... not sure if "IocpProactor" is the correct EventLoop
there was a thing for post python 3.7 with the default eventloops
from sys import platform
from os import name
if __name__ == "__main__":
if platform.lower() == "win32" or name.lower() == "nt":
from asyncio import (
set_event_loop_policy,
WindowsSelectorEventLoopPolicy
)
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
asyncio.run(main())
@AndreasHeine Still doesn't work, I tried on another computer and I still get the same output.
I'm wondering if there isn't a problem in the hello/Ack message, I see that the chunk stays at 10 but what if my server can't negotiate and needs a bigger chunk ? Because on UAExpert the MaxChunkCount
is set to 5000 and it can connect properly.
actually the server decides in last position what to use for the communication. the client just sends his possible max and the server uses them if possible or lower if the server cant handle large messages. even if UA Expert shows the setting at 5k does it not mean that it actually uses it...
if there is an issue with that there should be an UaError of some kind but you get an socket error after you try to create a secure channel (OpenSecureChannelRequest) which does not get an response, so the issue might be there!
OPC UA Reference: https://reference.opcfoundation.org/Core/Part6/v104/docs/7.1.2.3 https://reference.opcfoundation.org/Core/Part6/v104/docs/7.1.2.4
do you have access to the logs of the server? maybe there is a hint why it closes the connection!?
maybe the server does not like a empty Nonce -> ClientNonce=b''
@AndreasHeine I am trying to get in touch with the manufacturer regarding this, still waiting...
How can I modify the hello message ? Or just not send it ? Because in UAExpert's log I don't see a hello message being sent.
I found this in the client.py file in C:\Users\...\AppData\Local\Programs\Python\Python311\Lib\site-packages\asyncua\client
. Is it what I'm supposed to modify or is it something else somewhere ?
async def send_hello(self):
"""
Send OPC-UA hello to server
"""
ack = await self.uaclient.send_hello(self.server_url.geturl(), self.max_messagesize, self.max_chunkcount)
if isinstance(ack, ua.UaStatusCodeError):
raise ack
FYI : here's the connection log of UAExpert
even if you modify the settings in the client the revised values will be dictated by the server! i assume the open secure channel with empty nonce could be a reason for the server to drop the connection!
@AndreasHeine I'm sorry I'm not sure what you mean, how do I change the nonce or even open a not secure channel? In all the program I've used, I have never used a secure connection. For example in UaExpert these settings are used (and they work) :
@AndreasHeine So I have made some researches based on what you've told me and I tried multiple things and it was indeed due to the nonce being empty.
Thanks to another issue discussion on the freeopcua lib I added this code before the connect()
method and it works, I can now connect.
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 think I should leave this open as it's still opened in the freeopcua repo and doesn't seem to have been fixed in asyncua ?
I check for the source. It looks like os.urandom(0) generates None
on some platforms and on others it creates b''
.
This translates to either -1 or 0 as nonce.
As of the docs in python 3.11 the urandom source got changed on windows.
@schroeder- I'm on windows, os.random(0)
returns b''
. I have tried to bypass os.random(0) in the create.nonce
function and make it return a None
and the result is the same. So I think my server just doesn't like something other than a positive sized string...
I like to fix this issues somehow. But I fear some servers will followed the specs and raise an error if we send a nonce, that is not null. Maybe we add a parameter to client class?
@schroeder- Maybe that would be the best option an optional argument with a null
default value. If you need me to try something I have the server for about two more weeks !
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
But when I use the basic example using an
async
function with the await the line,await client.connect() Returns a
timeoutError
withasyncio.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.
The code can connect with await when I launch locally an opcua server using
\Python311\Scripts>uaserver --populate