Copyright © https://mongoose-os.com

Mongoose OS Forum

frame
ATTENTION! This forum has moved to:

https://community.mongoose-os.com

Do not post any new messages.

Are bidirectional websocket channels possible in JS (or C)?

Hello,

Could someone tell me if bidirectional websockets are possible with Mongoose-os?
So the slave initiates a persistent ws connection, and the master can do RPC calls through that connection towards the slave?

I have been struggling to get this to work for over a week now, and can't find any documentation about this.

So far I have this working:
- Master is configured to use ssl/mutual authentication using certificates.
- Slave can connect to master, do the handshake and activate the persistent connection using the client certificates.
- Slave can do RPC calls to the Master through the secure channel

What I would like to have working:
- Master can do RPC calls to the Slave through the persistent channel.

At first I thought I had it working by doing an RPC call like this:

RPC.call('ws://clientIP/rpc', 'GPIO.Toggle', {pin: 2}, function (resp, ud) {
print('Response:', JSON.stringify(resp));}, null);

But then I realized this wasn't doing the calls over SSL but rather over plain http.
I confirmed this by configuring the slave as well as an HTTPS server, after doing this the RPC call above failed to work.

Best regards,
Jan

Comments

  • This 'issue' is solved.

    Once the slave has connected and setup the secured websocket channel AND sent at least one RPC call to the master (can be a dummy call of some sort), at this point the master can do rpc calls towards the slave.
    As destination you just set the slave's device ID in the RPC call and that's it.

    Best regards,
    Jan

  • Hi,

    how did you create a websocket? I can't find appropriate documentation.

    Thanks in advance!

  • Hi,

    This is how you do it on two ESP32"s for example:

    If you want websockets going over plain http, you simply create an RPC handler on the master ESP32:

    RPC.addHandler('MyRPC',function(args){
    // put your magic stuff here...
    print(arg.myargument);
    return true;
      });
    

    from the second 'slave' ESP32 you can call the 'MyRPC' service like this:

     RPC.call('ws://ip-of-master/rpc', 'MyRPC', {myarguement: 5}, function (resp, ud) {
      print('Response:', JSON.stringify(resp));}, null);
    

    This should print 5 in the logs on the master. This way you could do for example a GPIO.Toggle of pin 5.

    If you want security, create the certificates like explained here: https://mongoose-os.com/docs/book/security.html
    In short:
    Self-signed certificate for mutual TLS
    # Common parameters
    SUBJ="/C=IE/ST=Dublin/L=Docks/O=MyCompany/CN=howdy"

    # Generate CA
    openssl genrsa -out ca.key 2048
    openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
      -subj /C=IE/ST=Dublin/L=Docks/O=mos/CN=me 
    
    # Generate client cert
    openssl genrsa -out client.key 2048
    openssl req -new -key client.key -out client.csr -subj $SUBJ
    openssl x509 -req -days 365 -in client.csr -CA ca.crt \
      -CAkey ca.key -set_serial 01 -out client.crt
    
    # Generate server cert
    openssl genrsa -out server.key 2048
    openssl req -new -key server.key -out server.csr -subj $SUBJ
    openssl x509 -req -days 365 -in server.csr -CA ca.crt \
      -CAkey ca.key -set_serial 01 -out server.crt
    

    Copy ca.crt, server.key and server.crt on the master crt ('mos put ca.crt' and so on).
    Configure the ESP32 to use HTTP over SSL (https) instead of plain HTTP:
    Cfg.set({http: {ssl_key:"server.key",ssl_cert:"server.crt",ssl_ca_cert:"ca.crt"}});

    On the client side I copied the client.key and client.crt files into one file: clientfile.crt.
    Copy it to the client ESP32: mos put clientfile.crt

    If you then want to toggle the pin on the master ESP32 for example using the default GPIO.Toggle call:

    RPC.call('wss://ip-of-master/rpc#ssl_client_cert_file=clientfile.crt', 'GPIO.Toggle', {pin: 2}, function (resp, ud) {
      print('Response:', JSON.stringify(resp));}, null);
    

    You can also setup a 'default' secure channel to the server that stays open. For that configure the default websocket on the client ESP32:
    Cfg.set({rpc: {ws:{server_address: ip-of-master,ssl_client_cert_file: "clientfile.crt"}}});

    After reboot, you should be able to do the same call from above like this:

    RPC.call('', 'GPIO.Toggle', {pin: 2}, function (resp, ud) {
      print('Response:', JSON.stringify(resp));}, null);
    

    It will use the default open channel to do the call. This speeds up consecutive calls to the master, otherwiser for each call a handshake must be done that takes some time.

    Thanked by 1Sterling
Sign In or Register to comment.