RPC over Websocket

RPC api is reachable over websocket. A websocket server is instantiated and listen on path /rpc.

The following python code example call RPC Totem.Layer.Steady using a simple websocket client.

import hashlib
import json
import websocket 
from datetime import datetime

def digest_message(nonce,cnounce, cmd):
    cnonce = int(datetime.now().timestamp() * 1000)
    digest_uri = {"method": "dummy_method", "path": "dummy_uri"}
    user = "admin"
    realm = "sdnesp01"
    password = "password"

    HA1 = hashlib.md5(f"{user}:{realm}:{password}".encode()).hexdigest()
    HA2 = hashlib.md5(f"{digest_uri['method']}:{digest_uri['path']}".encode()).hexdigest()
    combined = f"{HA1}:{nonce}:{cnounce}:{cnonce}:auth:{HA2}"
    response = hashlib.md5(combined.encode()).hexdigest()

    cmd['auth'] = {"realm": realm, "username": user, "nonce": nonce, "cnonce": cnonce, "response": response}
    return json.dumps(cmd)

nonce_value = 0
id = int(datetime.now().microsecond * 1000)
cmd_data = {"src":"rpc","id":id, "method":"Totem.Layer.Steady","params":{"layer": 0, "color": "008888"}}
cnounce = 1
result = digest_message(nonce_value,cnounce, cmd_data)

ws = websocket.create_connection("ws://<device-ip>/rpc")
ws.send(result)
response = json.loads(ws.recv())

if response["error"]["code"] == 401:
    message = json.loads(response["error"]["message"])
    nonce_value = message["nonce"]
    cnounce = message["nc"]
    result = digest_message(nonce_value,cnounce, cmd_data)
    ws.send(result)
    response = json.loads(ws.recv())

print(response)
ws.close()

Client can’t know nonce’s value until he received an Unauthorized (401) response that contain the nonce.

Note

This example require python’s library websocket-client.