ops: appliance boot — wait for cameras/LiveKit, power button powers off

This commit is contained in:
Hermes
2026-08-28 05:45:11 +00:00
parent b5a2fe6440
commit abeea6256c
7 changed files with 103 additions and 10 deletions
+3 -1
View File
@@ -1,5 +1,7 @@
# LiveKit server connection # LiveKit server connection
LIVEKIT_URL=ws://localhost:7880 # Local TEST server (autostarted). Switch this URL to the remote
# LiveKit later; then: systemctl disable --now livekit-server
LIVEKIT_URL=ws://127.0.0.1:7880
LIVEKIT_API_KEY=APIKey_xxx LIVEKIT_API_KEY=APIKey_xxx
LIVEKIT_API_SECRET=APIsecret_xxx LIVEKIT_API_SECRET=APIsecret_xxx
+21 -4
View File
@@ -82,12 +82,29 @@ lightweight high-pass + soft-clip DSP path so streams still work.
Until the 1 s window is full, hops use the DSP fallback so LiveKit is Until the 1 s window is full, hops use the DSP fallback so LiveKit is
not silent on startup. not silent on startup.
## systemd (enabled, 24/7) ## Appliance boot / power button
Two units, enabled for multi-user.target: This box is meant to behave like an appliance:
- `livekit-server.service` — `/usr/local/bin/livekit-server` + `deploy/livekit-server.yaml` (:7880) - Power button while **off** → BIOS/OS boot → `livekit-cameras` waits for
- `livekit-cameras.service` — `run.py` (Requires livekit-server) USB cameras + LiveKit, then publishes.
- Power button while **on** → full `poweroff` (not sleep). Suspend/hibernate
targets are masked. Drop-in:
`/etc/systemd/logind.conf.d/50-power-button.conf`
## systemd (enabled)
- `livekit-server.service` — **local TEST** LiveKit on :7880 (autostart for now)
- `livekit-cameras.service` — publishers. `Wants=` the test server, does not
`Require` it. Destination is `LIVEKIT_URL` in `.env` (currently
`ws://127.0.0.1:7880`).
When the real/remote LiveKit exists, change `.env` `LIVEKIT_URL` and:
```bash
systemctl disable --now livekit-server
systemctl restart livekit-cameras
```
```bash ```bash
systemctl status livekit-cameras livekit-server systemctl status livekit-cameras livekit-server
+9
View File
@@ -0,0 +1,9 @@
[Login]
HandlePowerKey=poweroff
HandlePowerKeyLongPress=poweroff
HandleSuspendKey=ignore
HandleHibernateKey=ignore
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
IdleAction=ignore
+12 -4
View File
@@ -1,20 +1,28 @@
[Unit] [Unit]
Description=Publish C920 cameras (speechbrain audio) to LiveKit Description=Publish C920 cameras (speechbrain audio) to LiveKit
Documentation=file:///home/fdenkena/livekit-cameras/README.md
After=network-online.target sound.target livekit-server.service After=network-online.target sound.target livekit-server.service
Wants=network-online.target Wants=network-online.target
Requires=livekit-server.service # Wants, not Requires: local livekit-server is a test stand-in.
# Point LIVEKIT_URL at a remote server later and you can disable this unit.
Wants=livekit-server.service
[Service] [Service]
Type=simple Type=simple
WorkingDirectory=/home/fdenkena/livekit-cameras WorkingDirectory=/home/fdenkena/livekit-cameras
EnvironmentFile=-/home/fdenkena/livekit-cameras/.env
Environment=PYTHONUNBUFFERED=1
Environment=ENHANCE_MODE=force
ExecStartPre=/home/fdenkena/livekit-cameras/deploy/wait-for-cameras.sh
ExecStartPre=/home/fdenkena/livekit-cameras/deploy/wait-for-livekit.sh
ExecStart=/home/fdenkena/livekit-cameras/.venv/bin/python /home/fdenkena/livekit-cameras/run.py ExecStart=/home/fdenkena/livekit-cameras/.venv/bin/python /home/fdenkena/livekit-cameras/run.py
ExecStop=/bin/kill -TERM $MAINPID
Restart=always Restart=always
RestartSec=5 RestartSec=5
TimeoutStartSec=90
TimeoutStopSec=30 TimeoutStopSec=30
KillMode=control-group KillMode=control-group
Environment=PYTHONUNBUFFERED=1 KillSignal=SIGTERM
Environment=LIVEKIT_URL=ws://127.0.0.1:7880
Environment=ENHANCE_MODE=force
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
+2 -1
View File
@@ -1,5 +1,6 @@
[Unit] [Unit]
Description=LiveKit server for the C920 camera fleet Description=LiveKit TEST server for the C920 camera fleet (local only)
Documentation=file:///home/fdenkena/livekit-cameras/README.md
After=network-online.target After=network-online.target
Wants=network-online.target Wants=network-online.target
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
# Wait for udev to pin C920 nodes after boot. Never fail the unit:
# discovery can still run with whatever is present.
set -u
udevadm settle -t 20 || true
udevadm trigger --subsystem-match=video4linux --action=add || true
udevadm trigger --subsystem-match=sound --action=add || true
for _ in $(seq 1 45); do
n=$(ls -1 /dev/cam[0-9][0-9] 2>/dev/null | wc -l)
if [ "$n" -ge 1 ]; then
echo "wait-for-cameras: $n pinned /dev/camNN nodes"
exit 0
fi
sleep 1
done
echo "wait-for-cameras: none yet; starting anyway" >&2
exit 0
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
# Wait until LIVEKIT_URL (from .env) accepts TCP. Used so publishers do not
# race the local test livekit-server on boot. When LIVEKIT_URL points at a
# remote host this waits on that host instead.
set -u
ENV_FILE=/home/fdenkena/livekit-cameras/.env
if [ -f "$ENV_FILE" ]; then
set -a
# shellcheck disable=SC1090
. "$ENV_FILE"
set +a
fi
URL="${LIVEKIT_URL:-ws://127.0.0.1:7880}"
rest="${URL#*://}"
hostport="${rest%%/*}"
host="${hostport%%:*}"
port="${hostport##*:}"
case "$hostport" in
*:*) ;;
*)
case "$URL" in
wss://*) port=443 ;;
*) port=80 ;;
esac
;;
esac
if [ "$host" = "localhost" ]; then
host=127.0.0.1
fi
echo "wait-for-livekit: $host:$port"
for _ in $(seq 1 30); do
if (echo >/dev/tcp/"$host"/"$port") 2>/dev/null; then
echo "wait-for-livekit: ready"
exit 0
fi
sleep 1
done
echo "wait-for-livekit: $host:$port not reachable after 30s" >&2
exit 1