Modularize bridge and improve control GUI

This commit is contained in:
2026-08-03 00:55:12 +02:00
parent 73b302a965
commit f4ab49e0c8
26 changed files with 3104 additions and 1953 deletions
+90 -149
View File
@@ -1,72 +1,86 @@
# Frigate Camera Control Bridge
## PL
Generic sidecar for a single Frigate instance. The container reads Frigate
configuration from `/api/config`, discovers cameras from `go2rtc` and direct
`ffmpeg.inputs[].path` stream URLs, then exposes light and siren controls
through Home Assistant MQTT Discovery plus an emergency HTTP fallback GUI.
Ten projekt jest uniwersalnym sidecarem dla pojedynczej instancji Frigate.
Kontener pobiera konfiguracje Frigate przez `/api/config`, wykrywa kamery z
`go2rtc` oraz z bezposrednich URL-i `ffmpeg.inputs[].path`, a potem wystawia
sterowanie swiatlem/syrena przez MQTT Discovery dla Home Assistant i awaryjne
GUI HTTP.
## Design
Najwazniejsze zalozenia:
- Ten sam obraz obsluguje Podman dzisiaj i Kubernetes pozniej.
- Konfiguracja runtime jest przez zmienne srodowiskowe, bez montowania pliku
konfiguracyjnego Frigate.
- Sidecar czeka na Frigate przy starcie i ponawia odczyt `/api/config`.
- Jesli `ffmpeg.inputs[].path` wskazuje na `rtsp://127.0.0.1:8554/...`,
sidecar traktuje to jako brame go2rtc i szuka prawdziwego URL-a kamery w
- One image works for Podman now and Kubernetes later.
- Runtime configuration is environment-based; no Frigate config mount is needed.
- The sidecar waits for Frigate startup and retries `/api/config`.
- The sidecar periodically refreshes `/api/config`, so added or removed cameras
can update MQTT Discovery without a container restart.
- On startup it runs a safe `all-off` by default, sets switch entities to `OFF`,
and publishes retained MQTT state.
- Alarms and lights have default auto-off timers: siren 180s, red-blue/strobe
300s, white light 600s. The GUI timer is rendered from a backend timestamp,
so page refreshes do not reset it.
- Siren `ON` actions require a browser confirmation in the fallback GUI.
- If `ffmpeg.inputs[].path` points at `rtsp://127.0.0.1:8554/...`, the sidecar
treats it as a go2rtc gateway and resolves the real camera URL from
`go2rtc.streams`.
- Aktualny Podman uzywa pliku env per sidecar, np.
`/etc/frigate-camera-control-bridge/frigate-main.env`.
- Kubernetes powinien podawac `MQTT_HOST`, `MQTT_USER`, `MQTT_PASSWORD`,
`DEFAULT_CAMERA_USER`, `DEFAULT_CAMERA_PASSWORD` przez `Secret`/`ConfigMap`.
- W trybie env brak tych wartosci jest bledem startu; sidecar nie szuka
credentiali w Quadletach ani w konfiguracji Frigate.
- GUI fallback domyslnie slucha na `5011`, bo `5001` jest juz uzywany przez
czesc instancji Frigate.
- Jezyki GUI sa standardowym gettext: `locale/<lang>/LC_MESSAGES/*.po` i `.mo`.
- If Frigate uses a direct non-loopback stream URL in `ffmpeg.inputs[].path`,
the sidecar uses that direct URL and does not resolve go2rtc in parallel.
- In env mode, missing MQTT or camera credentials are startup errors; the
sidecar does not look up credentials in Quadlets or Frigate config.
- The fallback GUI listens on `5011` by default because `5001` may already be
used by Frigate.
- GUI languages use standard gettext files:
`locale/<lang>/LC_MESSAGES/*.po` and `.mo`.
Podstawowe zmienne:
## Environment
| Zmienna | Znaczenie |
| Variable | Meaning |
| --- | --- |
| `FRIGATE_NAME` | Nazwa tej instancji, np. `frigate-main`. |
| `FRIGATE_URL` | URL API Frigate, np. `http://frigate-main.example.test:5000`. |
| `MQTT_HOST`, `MQTT_PORT` | Broker MQTT. |
| `MQTT_USER`, `MQTT_PASSWORD` | Credentiale MQTT. |
| `DEFAULT_CAMERA_USER`, `DEFAULT_CAMERA_PASSWORD` | Domyslne credentiale kamer odkrytych z Frigate. |
| `BASE_TOPIC` | Bazowy topic MQTT, np. `frigate_camera_control/frigate-main`. |
| `DISCOVERY_PREFIX` | Prefix Home Assistant MQTT Discovery, zwykle `homeassistant`. |
| `UI_LANGUAGE` | Domyslny jezyk GUI i encji HA, domyslnie `en`. |
| `HTTP_PORT` | Port GUI fallback, domyslnie `5011`. |
| `HTTP_TOKEN` | Opcjonalny token dla GUI/API HTTP. |
| `SNAPSHOT_RETRY_SECONDS` | Co ile probowac ponownie, gdy migawki brakuja, domyslnie `600`. |
| `SNAPSHOT_REFRESH_SECONDS` | Co ile odswiezac poprawnie pobrane migawki, domyslnie `3600`. |
| `SNAPSHOT_LIVE_ON_GUI` | Czy pobierac swieza migawke z Frigate przy otwieraniu GUI, domyslnie `true`. |
| `FRIGATE_NAME` | Instance name, for example `frigate-main`. |
| `FRIGATE_URL` | Frigate API URL, for example `http://frigate-main.example.test:5000`. |
| `MQTT_HOST`, `MQTT_PORT` | MQTT broker. |
| `MQTT_USER`, `MQTT_PASSWORD` | MQTT credentials. |
| `DEFAULT_CAMERA_USER`, `DEFAULT_CAMERA_PASSWORD` | Default credentials for cameras discovered from Frigate. |
| `BASE_TOPIC` | MQTT base topic, for example `frigate_camera_control/frigate-main`. |
| `DISCOVERY_PREFIX` | Home Assistant MQTT Discovery prefix, usually `homeassistant`. |
| `UI_LANGUAGE` | Default GUI and HA entity language, defaults to `en`. |
| `HTTP_PORT` | Fallback GUI port, defaults to `5011`. |
| `HTTP_TOKEN` | Optional HTTP GUI/API token. |
| `FRIGATE_REFRESH_SECONDS` | Frigate config refresh interval, defaults to `300`; `0` disables it. |
| `SNAPSHOT_RETRY_SECONDS` | Retry interval while a snapshot is missing, defaults to `600`. |
| `SNAPSHOT_REFRESH_SECONDS` | Refresh interval after snapshots are available, defaults to `3600`. |
| `SNAPSHOT_LIVE_ON_GUI` | Fetch a fresh Frigate snapshot when the GUI loads, defaults to `true`. |
| `STARTUP_ALL_OFF` | Send safe OFF commands during startup, defaults to `true`. |
| `AUTO_OFF_SIREN_SECONDS` | Siren auto-off, defaults to `180`. |
| `AUTO_OFF_RED_BLUE_SECONDS` | Red-blue/strobe auto-off, defaults to `300`. |
| `AUTO_OFF_WHITE_LIGHT_SECONDS` | White-light auto-off, defaults to `600`. |
Przyklad `/etc/frigate-camera-control-bridge/frigate-main.env`:
```bash
MQTT_HOST=mqtt.example.test
MQTT_PORT=1883
MQTT_USER=...
MQTT_PASSWORD=...
DEFAULT_CAMERA_USER=admin
DEFAULT_CAMERA_PASSWORD=...
```
Budowanie:
## Build
```bash
docker build -t frigate-camera-control-bridge:1.0 .
docker build -f Dockerfile.dev -t frigate-camera-control-bridge:dev .
```
Przyklady uruchomienia:
- Podman Quadlet: `examples/podman-quadlet/`
- Kubernetes sidecar: `examples/kubernetes-sidecar.yaml`
## Run
Lokalny test kontenera:
Podman Quadlet example:
```text
examples/podman-quadlet/
```
Docker Compose example:
```text
examples/docker-compose/
```
Kubernetes sidecar example:
```text
examples/kubernetes/
```
Local check:
```bash
docker run --rm \
@@ -81,100 +95,7 @@ docker run --rm \
frigate-camera-control-bridge:1.0 --check
```
Jezyki:
1. Dodaj katalog `locale/de/LC_MESSAGES/`.
2. Skopiuj `frigate_camera_control_bridge.po` z `locale/en/LC_MESSAGES/`.
3. Przetlumacz `msgstr`.
4. Uruchom `python3 tools/compile_gettext.py locale`.
5. Po przebudowaniu obrazu GUI samo pokaze nowy jezyk.
Manualne komendy w kontenerze:
```bash
/app/frigate-camera-control-bridge.py --list
/app/frigate-camera-control-bridge.py --check
/app/frigate-camera-control-bridge.py --all-off
/app/frigate-camera-control-bridge.py --action frigate_main_camera_a_red_blue off
```
HTTP fallback:
```text
http://<ip-frigate>:5011/
http://<ip-frigate>:5011/?lang=pl
http://<ip-frigate>:5011/api/actions
http://<ip-frigate>:5011/snapshot/<action_id>.jpg
http://<ip-frigate>:5011/healthz
http://<ip-frigate>:5011/readyz
```
Jesli ustawiono `HTTP_TOKEN`, dodaj `?token=<token>` albo naglowek
`X-Bridge-Token: <token>`.
## EN
This project is a generic sidecar for one Frigate instance. The container reads
Frigate configuration from `/api/config`, discovers cameras from `go2rtc` and
direct `ffmpeg.inputs[].path` stream URLs, then exposes light/siren controls
through Home Assistant MQTT Discovery plus an emergency HTTP fallback GUI.
Main design points:
- One image works for Podman now and Kubernetes later.
- Runtime configuration is environment-based; no Frigate config mount is needed.
- The sidecar waits for Frigate startup and retries `/api/config`.
- If `ffmpeg.inputs[].path` points at `rtsp://127.0.0.1:8554/...`, the sidecar
treats it as a go2rtc gateway and resolves the real camera URL from
`go2rtc.streams`.
- Current Podman deployment uses one env file per sidecar, for example:
`/etc/frigate-camera-control-bridge/frigate-main.env`.
- Kubernetes should pass `MQTT_HOST`, `MQTT_USER`, `MQTT_PASSWORD`,
`DEFAULT_CAMERA_USER`, and `DEFAULT_CAMERA_PASSWORD` from a `Secret`/`ConfigMap`.
- In env mode, missing values are startup errors; the sidecar does not look up
credentials in Quadlets or Frigate config.
- The fallback GUI listens on `5011` by default because `5001` is already used
by some Frigate instances.
- GUI languages use standard gettext files:
`locale/<lang>/LC_MESSAGES/*.po` and `.mo`.
Core env vars:
| Variable | Meaning |
| --- | --- |
| `FRIGATE_NAME` | Instance name, for example `frigate-main`. |
| `FRIGATE_URL` | Frigate API URL, for example `http://frigate-main.example.test:5000`. |
| `MQTT_HOST`, `MQTT_PORT` | MQTT broker. |
| `MQTT_USER`, `MQTT_PASSWORD` | MQTT credentials. |
| `DEFAULT_CAMERA_USER`, `DEFAULT_CAMERA_PASSWORD` | Default credentials for cameras discovered from Frigate. |
| `BASE_TOPIC` | MQTT base topic, for example `frigate_camera_control/frigate-main`. |
| `DISCOVERY_PREFIX` | Home Assistant MQTT Discovery prefix, usually `homeassistant`. |
| `UI_LANGUAGE` | Default GUI and HA entity language, defaults to `en`. |
| `HTTP_PORT` | Fallback GUI port, defaults to `5011`. |
| `HTTP_TOKEN` | Optional HTTP GUI/API token. |
| `SNAPSHOT_RETRY_SECONDS` | Retry interval while a snapshot is missing, defaults to `600`. |
| `SNAPSHOT_REFRESH_SECONDS` | Refresh interval after snapshots are available, defaults to `3600`. |
| `SNAPSHOT_LIVE_ON_GUI` | Fetch a fresh Frigate snapshot when the GUI loads, defaults to `true`. |
Build:
```bash
docker build -t frigate-camera-control-bridge:1.0 .
docker build -f Dockerfile.dev -t frigate-camera-control-bridge:dev .
```
Run examples:
- Podman Quadlet: `examples/podman-quadlet/`
- Kubernetes sidecar: `examples/kubernetes-sidecar.yaml`
Development container:
```bash
docker run --rm -it \
-v "$PWD":/workspace \
frigate-camera-control-bridge:dev
```
HTTP fallback:
## HTTP GUI
```text
http://<frigate-ip>:5011/
@@ -185,10 +106,30 @@ http://<frigate-ip>:5011/healthz
http://<frigate-ip>:5011/readyz
```
Kubernetes sidecar notes:
If `HTTP_TOKEN` is set, pass `?token=<token>` or the `X-Bridge-Token` header.
## Manual Commands
```bash
/app/frigate-camera-control-bridge.py --list
/app/frigate-camera-control-bridge.py --check
/app/frigate-camera-control-bridge.py --all-off
/app/frigate-camera-control-bridge.py --action frigate_main_camera_a_red_blue off
```
## Languages
1. Add `locale/de/LC_MESSAGES/`.
2. Copy `frigate_camera_control_bridge.po` from `locale/en/LC_MESSAGES/`.
3. Translate `msgstr`.
4. Run `python3 tools/compile_gettext.py locale`.
5. Rebuild the image. The GUI will discover the new language automatically.
## Kubernetes Notes
- Put the bridge container in the same pod as Frigate, or point `FRIGATE_URL`
at the Frigate service.
- Use `readinessProbe` on `/readyz`.
- Pass secrets through env vars from `Secret`.
- Keep `/var/lib/frigate-camera-control-bridge` on a small persistent volume if
you want stale Home Assistant discovery cleanup to survive pod recreation.
stale Home Assistant discovery cleanup should survive pod recreation.