Commit Graph

16 Commits

Author SHA1 Message Date
Levi Woodard
6d0748e4c5 Add camera module: drive UVC webcam controls via cameractrls
New `camera` module in modules.example.yaml (and the embedded copy) with
four functions: `set` (any control=value list, incl. preset/colour buttons),
`toggle` (flip between two values), `adjust` (step a numeric control by a
delta, clamped to the min/max parsed from `cameractrls -l`, with optional
`extra` controls applied first), and `is` (poll helper, exit 0 on match).

Device comes from CAMERA_DEVICE in .env (default /dev/video0) or a per-key
`device` param. cameractrls exits 0 for unknown controls, so polls must
use `is`; stderr is discarded to drop Python deprecation warnings.

README: Camera module section with setup, function table, a folder
example, and the oksvg viewBox-offset centring gotcha for SVG icons.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017iodiNMYL9iuT7f6WCe5iv
2026-10-08 14:02:29 -06:00
Levi Woodard
4158165410 Add folder support: keys that open sub-pages with a back key
A key with `folder: NAME` swaps the deck to the keys defined under
`folders.NAME`. Every folder shows a back key (slot 0 by default, drawn
with a built-in chevron) that pops back to the parent; folders nest.

The daemon now runs one page at a time: per-key setup moved into
setupKey(), openPage() draws a page under its own context, and
page.stop() tears it down before the next page is drawn (and on exit,
so device death no longer waits on uncancelled goroutines).

streamdeck-ctl gains `key set -folder`, reports kind "folder", lists
every folder in status, and refuses to `key press` a navigation-only
key. The Omarchy grid shows a folder glyph.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012ARLa4moGb154fzc9TevgV
2026-10-01 18:39:24 -06:00
Levi Woodard
c143db6b68 Fix HID read busy-spin: pass 250ms, not 250ns, to ReadWithTimeout
go-hid's ReadWithTimeout takes a time.Duration, so the bare 250 was
250ns, which truncates to a 0 ms hid_read_timeout. On both Linux
(poll) and macOS (cond_timedwait) 0 ms means non-blocking, so the
button loop spun continuously: ~1.2 cores and ~7.5k context
switches/sec at idle, from startup.

Pass 250*time.Millisecond and match hid.ErrTimeout with errors.Is
ahead of the string fallback. Idle CPU drops to ~0%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yH8jHn1SNzNnL58CRwTi9
(cherry picked from commit 69d2926a1a)
2026-09-29 18:49:41 -06:00
Levi Woodard
8cff4f8418 Add streamdeck-ctl JSON control CLI
streamdeck-ctl reports device/daemon/key status as JSON and edits the
config (brightness, key set/clear/press, daemon control) so front-ends
don't have to reimplement YAML handling or device probing.

- internal/config/edit.go: comment-preserving, node-level YAML edits with
  atomic writes; key indices written as !!int so config.Load accepts them.
- internal/device: add model names, Lookup() and Present() for probing
  without opening the HID handle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjuZBBfzXqZgxRhxzJvkkC
2026-09-27 18:21:33 -06:00
lwoodard
cef6f72712 Slack modules: declare charset in Content-Type
Add "; charset=utf-8" to the JSON Content-Type header so Slack's
users.profile.set no longer returns the missing_charset warning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-12 09:50:15 -06:00
lwoodard
d1d5d88508 Add text_command + refresh live-text keys
Introduce a per-key `text_command` + `refresh` feature: the service
periodically runs a shell command and renders its stdout as the key's
text overlay, compositing over the base icon (or a black background for
text-only keys) each tick. `text` acts as the static fallback shown
before the first run or when the command errors/outputs nothing. A
refresh goroutine owns the key's image and also handles an optional poll
block (choosing icon_true/icon_false per tick). Adds `$(...)` sugar in
`text` as shorthand for `text_command`.

- internal/config: add TextCommand/Refresh fields to KeyConfig
- cmd/streamdeck: refreshTextKey goroutine, runTextCommand, unwrapCmdSubst
- config.example.yaml: document the feature with a `flow` pomodoro
  live-countdown example (status --short, toggle/skip/stop/gui)
- modules.example.yaml: example config updates

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEoLyNbtbjbDq7aTWAymUG
2026-08-07 13:23:43 -06:00
Levi Woodard
38893cbb84 adding things and fixing sgv 2026-04-18 16:13:39 -06:00
Levi Woodard
962ee747fd Text overlay support 2026-04-18 11:55:18 -06:00
lwoodard
6f2290bd6c adding OBS support 2026-04-16 15:23:46 -06:00
lwoodard
6c5f3072a2 Fixing slack stuff 2026-04-14 05:43:30 -06:00
lwoodard
91b7028382 adding init program 2026-04-13 12:45:41 -06:00
lwoodard
639a08a808 Adding Slack modules 2026-04-13 11:27:18 -06:00
lwoodard
0f5a136764 adding mac support mainly 2026-04-13 08:11:19 -06:00
Levi Woodard
acd890fb69 adding support for if\else type situations 2026-03-15 17:50:11 -06:00
Levi Woodard
b428f4861a Fix HID timeout/EINTR errors and relative icon paths
- Treat "timeout" and "interrupted system call" from ReadWithTimeout as
  non-fatal — hidraw on Linux returns errors instead of (0, nil) for
  both, causing false device-dead detection and reconnect loops
- Resolve icons_dir relative to the config file when the path is not
  absolute, so the service finds icons regardless of working directory
- Installer now copies bundled icons to the config dir on first install
2026-03-15 10:36:44 -06:00
Levi Woodard
663d452ca3 Initial Push 2026-03-15 10:10:13 -06:00