Websocket - Create_Connection not working options

Hi all,

i’m using:
Requirement already satisfied: robotframework-websocketclient in /usr/local/lib/python3.10/dist-packages (1.3.0)
Requirement already satisfied: robotframework in /usr/local/lib/python3.10/dist-packages (from robotframework-websocketclient) (6.0.2)
Requirement already satisfied: websocket-client in /usr/local/lib/python3.10/dist-packages (from robotframework-websocketclient) (1.6.1)

And i have problems to create a connection to a unsecure local server. I get a typical ssl-error:
SLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1007)

I know almost everything about this and i also know the solution about sending the option:
sslopt={“cert_reqs”: ssl.CERT_NONE}

So my problem is that i don’t know why this code is not working:
Library WebSocketClient

${auth}= Create Dictionary X-KVMD-User=blah X-KVMD-Passwd=blub
${ssl_opt}= Set Variable sslopt={“cert_reqs”: ssl.CERT_NONE}
${my_websocket}= WebSocketClient.connect wss://x.x.x.x/api/ws header=${auth} sslopt=${ssl_opt}

If you look in the keywords of WebSocketClient.connect then you see this:

from websocket import create_connection
class WebSocketClientKeywords:
def connect(self, URL, timeout=None, **options):
return create_connection(URL, timeout, **options)

So beside the URL i have to provide the header (as my server require auth-headers) and also the sslopt to accept self signed certs. But my code above does not work - it looks like i do not pass the sslopt correctly to the connect method. - I don’t know whats wrong there.

BUT i found a solution which is the following. I have added this small python code:

import ssl
import websocket

def open_ws_pikvm(uri, header, sslopt=None):
if sslopt is None:
sslopt = {“cert_reqs”: ssl.CERT_NONE}
ws = websocket.create_connection(uri, header=header, sslopt=sslopt)
return ws

And in RF i do this:
Library WebSocketClient
Library rfws.py

${auth}= Create Dictionary X-KVMD-User=blah X-KVMD-Passwd=blub
${ssl_opt}= Set Variable sslopt={“cert_reqs”: ssl.CERT_NONE}
${my_websocket}= rfws.open_ws_pikvm wss://${PIKVM}/api/ws header=${auth}

As you can see now i’m calling the open_ws_pikvm function from the python code above and now i do not pass the sslopt as this is already in the python code.

Doing so everything is working fine!.
So what’s wrong here.

So this code does not work:
${auth}= Create Dictionary X-KVMD-User=blah X-KVMD-Passwd=blub
${ssl_opt}= Set Variable sslopt={“cert_reqs”: ssl.CERT_NONE}
${my_websocket}= WebSocketClient.connect wss://x.x.x.x/api/ws header=${auth} sslopt=${ssl_opt}

Where this code does:
${auth}= Create Dictionary X-KVMD-User=blah X-KVMD-Passwd=blub
${ssl_opt}= Set Variable sslopt={“cert_reqs”: ssl.CERT_NONE}
${my_websocket}= rfws.open_ws_pikvm wss://${PIKVM}/api/ws header=${auth}

Could it be that the create_connection from RF WebSockerClient library is not working fine?
Has anyone worked with this Library?

btw - here is the trace back from DEBUG LOG.

Traceback (most recent call last):
File “/home/camilb/.local/lib/python3.10/site-packages/WebSocketClient/keywords.py”, line 7, in connect
return create_connection(URL, timeout, **options)
File “/usr/local/lib/python3.10/dist-packages/websocket/_core.py”, line 608, in create_connection
websock.connect(url, **options)
File “/usr/local/lib/python3.10/dist-packages/websocket/_core.py”, line 249, in connect
self.sock, addrs = connect(url, self.sock_opt, proxy_info(**options),
File “/usr/local/lib/python3.10/dist-packages/websocket/_http.py”, line 136, in connect
sock = _ssl_socket(sock, options.sslopt, hostname)
File “/usr/local/lib/python3.10/dist-packages/websocket/_http.py”, line 271, in _ssl_socket
sock = _wrap_sni_socket(sock, sslopt, hostname, check_hostname)
File “/usr/local/lib/python3.10/dist-packages/websocket/_http.py”, line 247, in _wrap_sni_socket
return context.wrap_socket(
File “/usr/lib/python3.10/ssl.py”, line 513, in wrap_socket
return self.sslsocket_class._create(
File “/usr/lib/python3.10/ssl.py”, line 1071, in _create
self.do_handshake()
File “/usr/lib/python3.10/ssl.py”, line 1342, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1007)

you see that the connect fails in the do_handshake

I have the felling that the way i try to call this connect is wrong. Maybe i miss some space? or tab?
Even if i try to remove the header from the call and only put the sslopt is not working. I still get the ssl error. I would assume that if the call is correct but the header are missing i would get an authenticate error but the ssl handshake and the connection would be established.

But even if i try to do this:
${my_websocket}= WebSocketClient.connect wss://x.x.x.x/api/ws sslopt=${ssl_opt}

it get the ssl error :frowning:

First time I see this library mentioned, so went searching for info about it.
PyPi.org:

GitHub.com:

Conclusion: Project is archived since October 2022, highest supported Python is 3.6

Question: Why you want to use this library?
Wouldn’t be better to use RequestLibrary or RestInstance?
Or even palin Python HTTP modules?

1 Like

Hi, thx for your answer.

In my project i use RequestLibrary to sent GET POST requests to a server. But before i can do this i have to open the streamer on the device which i use for my tests - It’s a piKVM (pivkm.org).
So piKVM runs a ustreamer (streamer). You can use the api e.g. like this:

${get_bios_enter_password}= GET url=https://${PIKVM}/api/streamer/snapshot?ocr=1&ocr_langs=eng&ocr_left=576&ocr_top=316&ocr_right=691&ocr_bottom=330 headers=${auth} verify=${False}

with this i can capture the screen on the device which in that case shows a “Enter Password” field. So then i know that i have to enter the bios password and then i can continue with my test automation.

Well the bad thing is that the streamer is made not to run forever but only if you login to the pikvm webui. It’s only this streamer component which does not run forever.

Talking on discord to the devs (very good guys) they told me that if i want to sent GET requests to /api/streamer/ i fist need to create a session using websockets to /api/ws (without anything else).
i can use websocat for this too or i use a wss request.
Once i do this the streamer will start and accept the GET Requests i sent - otherwise i get a 503.

The streamer is made as a component of another component - and so i can’t sent a GET/POST using RequestLibrary. I also can’t use header to change the connection to websocket.

So what i need is to create a websocket then do my tests (using POST/GET) and close the websocket which will trigger to stop the streamer on the pikvm.

You think using 3.8 or 3.10 will cause this problem for this library not run?
I mean using a 3.10 create_connection() works fine if i use it in plain python and call it from my rf-test.

Also i do not need to send anything to this websocket - i just have to create it - do my rf-tests - and close the socket. Thats why i do:

def open_ws_pikvm(uri, header, sslopt=None):
if sslopt is None:
sslopt = {“cert_reqs”: ssl.CERT_NONE}
ws = websocket.create_connection(uri, header=header, sslopt=sslopt)
return ws

For what I can understand of your problem, you may not use the obsolete library, and use direct python to create your RF keyword.

You can use the python code directly like in:

Library    your_websocket_manager.py

It may also be possible to adapt the Python 3.60 code to Python 3.10, for the whole library, but looks simpler to just get the relevant function.

Yes - exactly.
I use a python code and do the create_connection() as i need it - which works totaly fine.
So only for this i have to use this one-liner python code.

I thought that someone might know this websocket-library and can tell me that my syntax about
WebSocketClient.connect is wrong or i miss something?

But looks like using this (outdated) library is not possible if you have to use wss and you want to ignore the ssl-cert.
Well it might work if i would get the cert the pikvm is using and add it to my ca-certificates on my server - but thats not i want to do.

I’m totaly fine with the current working soultion.

At least i can use WebSocketClient.close to close the client :wink: - This works.

Thanks for your quick support.

1 Like

HI - i’ve created the following python code

import ssl
import threading
import websocket

websocket_thread = None
ws_app = None

def open_websocket_pikvm(uri, header):
print(f"Open Websocket to pikvm")

def websocket_handler():
    def on_message(ws, message):
        # Handle incoming WebSocket messages here
        print(f"Received message: {message}")

    def on_error(ws, error):
        # Handle WebSocket errors here
        print(f"WebSocket error: {error}")

    def on_close(ws, close_status_code, close_msg):
        # Handle WebSocket close here
        print(f"WebSocket closed with status code {close_status_code}: {close_msg}")

    # Create a WebSocket instance
    global ws_app
    ws_app = websocket.WebSocketApp(uri,
                                    header=header,
                                    on_message=on_message,
                                    on_error=on_error,
                                    on_close=on_close)

    # Start the WebSocket connection
    ws_app.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})

# Create a thread for the WebSocket connection
global websocket_thread
websocket_thread = threading.Thread(target=websocket_handler)

# Start the WebSocket thread
websocket_thread.start()

def close_websocket_pikvm():
print(f"Close Websocket to pikvm")
ws_app.close()
websocket_thread.join()

class Open_Wss_PiKVM:
pass

And then i use the python code in my rf test like this

Library Websocket_Helper.py

Open Websocket to piKVM
${auth}= Create Dictionary X-KVMD-User=blah X-KVMD-Passwd=blub
Open Websocket Pikvm wss://${PIKVM}/api/ws header=${auth}

Close Websocket from piKVM
Close Websocket Pikvm

2 Likes