diff options
| author | xengineering <me@xengineering.eu> | 2026-03-25 21:37:20 +0100 |
|---|---|---|
| committer | xengineering <me@xengineering.eu> | 2026-03-25 21:37:20 +0100 |
| commit | 4bc67b734dc8c90dd4679877e8825da32e67b7eb (patch) | |
| tree | fc4b97bdb6b91caff22b771bb9d8f5ca64791772 /tools | |
| parent | 7afbc98e6d715eef8809beb9793ccf5096104e26 (diff) | |
| parent | 6001997a66c4c4b12e9d8b0853fef0fc0ff14768 (diff) | |
| download | sia-server-4bc67b734dc8c90dd4679877e8825da32e67b7eb.tar sia-server-4bc67b734dc8c90dd4679877e8825da32e67b7eb.tar.zst sia-server-4bc67b734dc8c90dd4679877e8825da32e67b7eb.zip | |
Merge branch 'shelly'
This adds basic support for Shelly 2PM Gen3 devices.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/meson.build | 15 | ||||
| -rw-r--r-- | tools/websocket.go | 158 |
2 files changed, 173 insertions, 0 deletions
diff --git a/tools/meson.build b/tools/meson.build new file mode 100644 index 0000000..1322ce0 --- /dev/null +++ b/tools/meson.build @@ -0,0 +1,15 @@ +websocket_linux_amd64 = custom_target( + input : [ + meson.current_source_dir() / 'websocket.go', + ], + output : 'websocket-linux-amd64', + env : {'GOOS': 'linux', 'GOARCH': 'amd64'}, + command : [ + go, + 'build', + '-o', + '@OUTPUT@', + '@INPUT@', + ], + build_by_default : true, +) diff --git a/tools/websocket.go b/tools/websocket.go new file mode 100644 index 0000000..af23959 --- /dev/null +++ b/tools/websocket.go @@ -0,0 +1,158 @@ +// Websocket debug tool +// +// Usage: ./websocket-linux-amd64 ws://<shelly-ip>/rpc +// +// This tools is intended to support development of the Websocket-based +// application programming interface (API) of the Shelly Internet of Things +// (IoT) devices. + +package main + +import ( + "encoding/json" + "log" + "net/url" + "os" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/gorilla/websocket" +) + +func main() { + log.SetFlags(0) + + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + + var u url.URL = getURL() + log.Printf("connecting to %s", u.String()) + + c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) + if err != nil { + log.Fatal(err) + } + defer c.Close() + + go rx(c) + + getConfig(c) + coverClose(c) + time.Sleep(1 * time.Second) + coverOpen(c) + + Await(syscall.SIGTERM, syscall.SIGINT) +} + +func getURL() url.URL { + if len(os.Args) != 2 { + log.Fatalf("Exactly one argument expected but got %d.", len(os.Args) - 1) + } + + maybeURL, err := url.Parse(os.Args[1]) + if err != nil { + log.Fatalf("Cannot parse given URL: %s", os.Args[1]) + } + + return *maybeURL +} + +func Await(signals ...os.Signal) { + listener := make(chan os.Signal, 1) + signal.Notify(listener, signals...) + defer signal.Stop(listener) + + sig := <-listener + log.Printf("Received OS signal '%v'\n", sig) +} + +func getConfig(c *websocket.Conn) { + tx(c, ` +{ + "jsonrpc":"2.0", + "id": 1, + "src":"user_1", + "method":"Sys.GetConfig", + "params": { + "id":2 + } +} +`) +} + +func coverClose(c *websocket.Conn) { + tx(c, ` +{ + "jsonrpc":"2.0", + "id": 1, + "src":"user_1", + "method":"Cover.Close", + "params": { + "id":0 + } +} +`) +} + +func coverOpen(c *websocket.Conn) { + tx(c, ` +{ + "jsonrpc":"2.0", + "id": 1, + "src":"user_1", + "method":"Cover.Open", + "params": { + "id":0 + } +} +`) +} + +func rx(c *websocket.Conn) { + for { + _, message, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + return + } + log.Println("") + log.Println(quote(prettify(string(message)), "< ")) + } +} + +func tx(c *websocket.Conn, d string) { + log.Println(quote(prettify(d), "> ")) + + err := c.WriteMessage(websocket.TextMessage, []byte(d)) + if err != nil { + log.Fatal(err) + } +} + +func prettify(input string) string { + var parsed any + + err := json.Unmarshal([]byte(input), &parsed) + if err != nil { + log.Fatal(err) + } + + pretty, err := json.MarshalIndent(parsed, "", " ") + if err != nil { + log.Fatal(err) + } + + return string(pretty) +} + +func quote(input string, quotation string) string { + lines := strings.Split(input, "\n") + + for i, line := range lines { + lines[i] = quotation + line + } + + return strings.Join(lines, "\n") +} |
