From 44dc22d8ee9c000c5db8d66bf020d03a2e2a0a96 Mon Sep 17 00:00:00 2001 From: lwoodard <92559124+WoodardDigital@users.noreply.github.com> Date: Thu, 16 Apr 2026 15:38:46 -0600 Subject: [PATCH] Adding readme updates --- README.md | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f73844..bc8f1e6 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ No Elgato software required — communicates directly with the device over USB H - PNG, JPEG, and SVG icons, automatically scaled to key size - Animated GIF support — frames pre-encoded at startup, cycled at the GIF's native rate - Runs any shell command on key press -- **Status/toggle keys** — poll any shell command on an interval, swap icons based on output; icon updates on press +- **Status/toggle keys** — poll any shell command on an interval, swap icons based on output; icon updates on press. Either icon can be an animated GIF (e.g. a flashing record indicator when recording is active). - **Live config reload** — save your config and the deck updates instantly, no restart needed - **Privileged commands** — run whitelisted root/admin commands; Linux uses a root helper daemon, macOS uses the native admin auth dialog - Automatic reconnect — survives USB unplug, KVM switches, and suspend/resume - Runs as a systemd user service (Linux) or launchd agent (macOS), starts automatically at login - No Stream Deck app, no Node.js, no Electron -- **Modules** — define reusable, parameterised commands in `modules.yaml` with Go templates; secrets stay in env vars, config stays in dotfiles. First built-in example: Slack (status, presence, snooze). See [Modules](#modules). +- **Modules** — define reusable, parameterised commands in `modules.yaml` with Go templates; secrets stay in env vars, config stays in dotfiles. Built-in examples: Slack (status, presence, snooze) and OBS Studio (recording, streaming, scene switching, media control). See [Modules](#modules). - **Interactive config builder** — TUI tool (`streamdeck-init`) that walks you through key setup: pick a slot, pick a module/function, customize params, choose an icon. No YAML editing required. See [Config builder](#config-builder). **Planned:** text/label overlays on keys, multi-page layouts, AUR package — see [Roadmap](#roadmap) @@ -669,6 +669,67 @@ modules: A full example is included at [`modules.example.yaml`](modules.example.yaml) in the repo root. +#### OBS Studio module + +The example `modules.yaml` also includes an `obs` module that drives OBS over WebSocket using [`obs-cmd`](https://github.com/grigio/obs-cmd). + +**Setup:** + +1. Install `obs-cmd`: + - macOS: `brew install grigio/obs-cmd/obs-cmd` + - Linux: `cargo install obs-cmd` or download a release binary +2. Requires **OBS 30.2 or newer** — earlier versions fail `obs-cmd`'s version check. +3. In OBS, enable **Tools → WebSocket Server Settings** and note the port + password. +4. Export env vars (see [Secrets and tokens](#secrets-and-tokens) for launchd/systemd setup): + ```bash + export OBS_WEBSOCKET_PASSWORD="your-password" + export OBS_HOST="localhost" # or remote IP, e.g. 192.168.1.28 + export OBS_PORT="4455" + ``` + +**Functions:** + +| Function | Purpose | Params | +|---|---|---| +| `play` / `pause` / `stop` / `restart` | Media input controls | `source` (default `"Media Source"`) | +| `toggle_record` | Start/stop recording | — | +| `toggle_record_pause` | Pause/resume recording | — | +| `toggle_stream` | Start/stop streaming | — | +| `scene_switch` | Switch active scene | `scene` (default `"Scene 1"`) | +| `toggle_mute` | Toggle input mute | `source` (default `"Mic/Aux"`) | +| `is_recording` | Status check for poll blocks | — | +| `is_recording_paused` | Status check for poll blocks | — | +| `is_streaming` | Status check for poll blocks | — | + +**Example — record button with flashing GIF when active:** + +```yaml +keys: + 7: + icon_true: recording.gif # animated — flashes while recording + icon_false: camera.png # static — shown when stopped + module: obs + function: toggle_record + poll: + module: obs + function: is_recording + match: "Active: true" # obs-cmd output contains this when recording + interval: 2s + + 15: + icon_true: pause.svg + icon_false: play.svg + module: obs + function: toggle_record_pause + poll: + module: obs + function: is_recording_paused + match: "Paused: true" + interval: 2s +``` + +**Note — absolute paths in modules:** The example templates call `/usr/local/bin/obs-cmd` rather than just `obs-cmd`. This is because launchd (macOS) and systemd (Linux) give the service a minimal `PATH` that doesn't include `/usr/local/bin` or Homebrew. Use the absolute path returned by `which obs-cmd` in your own module templates, or set `PATH` in the launchd plist / systemd unit. + #### Using modules in config.yaml Reference a module function instead of writing inline commands: @@ -741,6 +802,36 @@ keys: match: "snooze_enabled.*true" ``` +#### Adding your own modules + +Modules are purely YAML — no Go code changes required. + +1. Open `~/.config/streamdeck-go/modules.yaml`. +2. Add a new top-level key under `modules:` (e.g. `home_assistant`, `spotify`). +3. Define functions, each with an `exec` template and optional default `params`. Use `{{env "VAR"}}` for secrets and `{{.paramName}}` for parameters. +4. Save — the daemon reloads automatically. +5. Reference the new module from `config.yaml` with `module:` / `function:` / `params:`. + +**Skeleton:** + +```yaml +modules: + my_api: + do_thing: + params: + target: "default-value" + exec: | + curl -s -X POST https://example.com/api/thing \ + -H "Authorization: Bearer {{env "MY_API_TOKEN"}}" \ + -d '{"target":"{{.target}}"}' +``` + +**Tips:** + +- If the template calls an external binary (like `curl`, `obs-cmd`, `osascript`), use the absolute path — service `PATH` is minimal. +- Chain multiple API calls with `&&` inside a single `exec` (see `go_offline` in the example). +- Status functions for poll blocks should output text matching a substring you set in the key's `poll.match`. + #### Template helpers Two helpers are available in `exec` templates: