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
This commit is contained in:
@@ -57,6 +57,30 @@ modules:
|
||||
curl -s -X POST https://slack.com/api/dnd.endSnooze \
|
||||
-H "Authorization: Bearer {{env "SLACK_TOKEN"}}"
|
||||
|
||||
# Pomodoro / focus timer — the `flow` CLI.
|
||||
#
|
||||
# Absolute path required (minimal service PATH). Apple Silicon Homebrew installs
|
||||
# live at /opt/homebrew/bin/flow — set that in ~/.config/streamdeck-go/.env:
|
||||
# FLOW_CMD=/opt/homebrew/bin/flow
|
||||
#
|
||||
# Control verbs (start/pause/resume/toggle/skip/stop/reset/gui) run on key press.
|
||||
# `status` prints one line like `state=running phase=work remaining=24:12` for
|
||||
# icon-swap poll blocks (match: "state=running").
|
||||
#
|
||||
# The LIVE countdown label uses a key's `text_command` field directly (not a
|
||||
# module), e.g. text_command: "/usr/local/bin/flow status --short" which prints
|
||||
# a two-line label like WORK\n24:12 (an actual newline between the lines).
|
||||
flow:
|
||||
start: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} start' }
|
||||
pause: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} pause' }
|
||||
resume: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} resume' }
|
||||
toggle: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} toggle' }
|
||||
skip: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} skip' }
|
||||
stop: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} stop' }
|
||||
reset: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} reset' }
|
||||
gui: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} gui' }
|
||||
status: { exec: '{{envDefault "FLOW_CMD" "/usr/local/bin/flow"}} status' }
|
||||
|
||||
# OBS Studio — media player, streaming, and scene/transition control via obs-cmd
|
||||
#
|
||||
# Requires: obs-cmd (https://github.com/grigio/obs-cmd)
|
||||
@@ -182,3 +206,67 @@ modules:
|
||||
{{envDefault "OBS_CMD" "/usr/local/bin/obs-cmd"}} --websocket obsws://{{envDefault "OBS_HOST" "localhost"}}:{{envDefault "OBS_PORT" "4455"}}/{{env "OBS_WEBSOCKET_PASSWORD"}} scene transition-set "{{.transition}}" && \
|
||||
{{envDefault "OBS_CMD" "/usr/local/bin/obs-cmd"}} --websocket obsws://{{envDefault "OBS_HOST" "localhost"}}:{{envDefault "OBS_PORT" "4455"}}/{{env "OBS_WEBSOCKET_PASSWORD"}} scene transition-duration {{.duration}} && \
|
||||
{{envDefault "OBS_CMD" "/usr/local/bin/obs-cmd"}} --websocket obsws://{{envDefault "OBS_HOST" "localhost"}}:{{envDefault "OBS_PORT" "4455"}}/{{env "OBS_WEBSOCKET_PASSWORD"}} scene switch "{{.scene}}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Camera — cameractrls (https://github.com/soyersoyer/cameractrls), Linux only.
|
||||
#
|
||||
# Drives any UVC webcam's V4L2 controls (zoom, pan/tilt, focus, exposure, white
|
||||
# balance, brightness/contrast/...). Install: pacman -S cameractrls / pip.
|
||||
#
|
||||
# Device: set CAMERA_DEVICE in ~/.config/streamdeck-go/.env to the stable path, e.g.
|
||||
# CAMERA_DEVICE=/dev/v4l/by-id/usb-046d_Logitech_BRIO_XXXX-video-index0
|
||||
# (defaults to /dev/video0; any function also takes a per-key `device` param).
|
||||
#
|
||||
# Discover control names/ranges: cameractrls -d /dev/video0 -l
|
||||
# Note: cameractrls exits 0 even for unknown controls, so poll blocks must use
|
||||
# the `is` function (which greps `-l` output) rather than exit codes.
|
||||
camera:
|
||||
# Set one or more controls, comma-separated (eg. "zoom_absolute=150,contrast=140").
|
||||
# Buttons work too: "preset=save_1", "preset=load_1", "color_preset=vivid".
|
||||
set:
|
||||
params:
|
||||
device: ""
|
||||
controls: "zoom_absolute=100"
|
||||
exec: /usr/bin/cameractrls -d {{if .device}}{{.device}}{{else}}{{envDefault "CAMERA_DEVICE" "/dev/video0"}}{{end}} -c "{{.controls}}" 2>/dev/null
|
||||
|
||||
# Flip a control between two values (a <-> b). Works for 0/1 and menu controls.
|
||||
toggle:
|
||||
params:
|
||||
device: ""
|
||||
control: auto_exposure
|
||||
a: aperture_priority_mode
|
||||
b: manual_mode
|
||||
exec: |
|
||||
cur=$(/usr/bin/cameractrls -d {{if .device}}{{.device}}{{else}}{{envDefault "CAMERA_DEVICE" "/dev/video0"}}{{end}} -l 2>/dev/null | sed -n 's/^ {{.control}} = \([^[:space:]]*\).*/\1/p')
|
||||
if [ "$cur" = "{{.a}}" ]; then v="{{.b}}"; else v="{{.a}}"; fi
|
||||
/usr/bin/cameractrls -d {{if .device}}{{.device}}{{else}}{{envDefault "CAMERA_DEVICE" "/dev/video0"}}{{end}} -c "{{.control}}=$v" 2>/dev/null
|
||||
|
||||
# Step a numeric control by delta (negative to decrease), clamped to its min/max.
|
||||
# `extra` is applied first on the same call — eg. "auto_exposure=manual_mode"
|
||||
# so stepping exposure also takes the camera out of auto.
|
||||
adjust:
|
||||
params:
|
||||
device: ""
|
||||
control: contrast
|
||||
delta: "16"
|
||||
extra: ""
|
||||
exec: |
|
||||
line=$(/usr/bin/cameractrls -d {{if .device}}{{.device}}{{else}}{{envDefault "CAMERA_DEVICE" "/dev/video0"}}{{end}} -l 2>/dev/null | grep '^ {{.control}} = ')
|
||||
cur=$(printf '%s\n' "$line" | sed -n 's/^ [a-z0-9_]* = \([-0-9]*\).*/\1/p')
|
||||
min=$(printf '%s\n' "$line" | sed -n 's/.*min: \([-0-9]*\).*/\1/p')
|
||||
max=$(printf '%s\n' "$line" | sed -n 's/.*max: \([-0-9]*\).*/\1/p')
|
||||
[ -n "$cur" ] || exit 1
|
||||
v=$((cur + {{.delta}}))
|
||||
[ -n "$min" ] && [ "$v" -lt "$min" ] && v=$min
|
||||
[ -n "$max" ] && [ "$v" -gt "$max" ] && v=$max
|
||||
ctl="{{.control}}=$v"
|
||||
[ -n "{{.extra}}" ] && ctl="{{.extra}},$ctl"
|
||||
/usr/bin/cameractrls -d {{if .device}}{{.device}}{{else}}{{envDefault "CAMERA_DEVICE" "/dev/video0"}}{{end}} -c "$ctl" 2>/dev/null
|
||||
|
||||
# Poll helper for toggle keys: exit 0 when control == value.
|
||||
is:
|
||||
params:
|
||||
device: ""
|
||||
control: auto_exposure
|
||||
value: aperture_priority_mode
|
||||
exec: /usr/bin/cameractrls -d {{if .device}}{{.device}}{{else}}{{envDefault "CAMERA_DEVICE" "/dev/video0"}}{{end}} -l 2>/dev/null | grep -q '^ {{.control}} = {{.value}}[[:space:]]'
|
||||
|
||||
Reference in New Issue
Block a user