README
¶
Bridge für Steinel CAM Leuchten auf ONVIF (RTSP), 2-Way Audio & Home Assistant
Die Bridge ist eine hochperformanter, 100 % autarker Go-Daemon der in Docker (Compose) oder als HomeAssistant App betrieben werden kann. Sie verwandelt Steinel CAM Außenleuchten (L 625 CAM SC, L 620 CAM, XLED CAM 1/2, Spot CAM) in standardkonforme ONVIF Profile S/T/G Kamera mit RTSP-Streaming, 2-Wege-Audio (Gegensprechen), lokalem MicroSD-Speicherabruf und vollständiger MQTT Home Assistant Auto-Discovery. Damit ist eine nahtlosen Integration in Home Assistant, Synology Surveillance Station, Scrypted, Frigate und weitere möglich. Mit Hilfe von Scrypted ist dann z.B. eine Integration in Apple HomeKit Secure Video (HKSV) möglich.
Da ich nicht alle Modelle selbst besitze kann ich nicht alles selbst direkt vertesten. Über Rückmeldungen würde ich mich freuen.
[!WARNING] Trotz sorgfältiger Entwicklung und Verwendung der Schnittstellen der offiziellen (Nabto) SDKs und APIs die von der Kamera bereitgestellt werden kann nicht garantiert werden das es zu keinen Komplikationen mit der Hardware der Kamera/Leuchte kommt. Das Projekt oder meine Personen übernehmen keine Gewährleistung oder Sachmängelhaftung für eventuell eintretende Schäden an der Hardware.
✨ Features & Home Assistant Integration
-
Standardisierter ONVIF Profile S, T & G Server:
- Profile G (Edge Storage): Bereitstellung standardisierter Search-, Replay- und Recording-Dienste zur Wiedergabe und Synchronisation von MicroSD-Aufnahmen in NVRs (z. B. Synology Surveillance Station).
- WS-Discovery (UDP 3702): Automatische Erkennung im lokalen Netzwerk.
- Native Live-Snapshots: NVRs und Clients (z. B. Scrypted Prebuffer, Home Assistant) generieren hochauflösende Live-Standbilder direkt aus dem H.264-Videostream ohne Dummy-Platzhalter.
-
🔊 Volles 2-Way Audio (Gegensprechen) & Natives AAC-Audio:
- Natives AAC-Audio (Standard): Automatisches Realtime-Transcoding des Kamera-Mikrofons (G.711u 8 kHz $\rightarrow$ AAC-LC 16 kHz). Keine extra Konfiguration für Transcoding des Audiosignals erforderlich.
- RTSP Audio Backchannel: Durchleitung von HomeKit/Scrypted-Sprachdaten direkt an den Lautsprecher der Steinel-Leuchte (PCMU / G.711u 8000 Hz).
-
🏠 Home Assistant MQTT Auto-Discovery (Strukturierte Gerätesteuerung):
- 🎮 Steuerung:
- Betriebsmodus (
select.mode): Umschalten zwischenSensor (Automatik),DauerlichtundAus. - Alarmsirene (
siren.siren): Sofortiges Auslösen und Stoppen des akustischen Alarms der Außenleuchte mit Live-Zustandsrückmeldung (ON/OFF).
- Betriebsmodus (
- 🎬 Ereignisse & Aufnahmen:
- Letzte SD-Aufnahme (
event.letzte_sd_aufnahme): Übermittlung des neuesten MicroSD-Aufnahmeereignisses mit Metadaten (Zeitstempel, Dauer – standardmäßig 30 s, Dateigröße) und direkter URL für das MP4-Video (video_url). Sofern vom Kameramodell unterstützt, wird zusätzlichthumbnail_urlbereitgestellt (Kameras wie die L 625 CAM SC speichern reine MP4-Videodateien ohne separate Standbilder).
- Letzte SD-Aufnahme (
- ⚙️ Konfiguration (Einstellungsbereich):
- Dämmerungsschwelle (
number.lux_threshold): Schaltschwelle in Lux (2–1000 lx), ab welcher Umgebungsdunkelheit das Licht bei Bewegung schaltet. - Hauptlicht Helligkeit (
number.highlight): Maximale Leuchtstärke des Flutlichts (10–100 %). - Grundlicht Helligkeit (
number.lowlight): Dauerhafte Nachtlicht-Helligkeit (0–50 %). - Nachlaufzeit (
number.duration): Einschaltdauer des Hauptlichts nach Bewegung (5–900 s). - PIR-Empfindlichkeit (
number.pir_sensitivity): Reichweite / Sensitivität des Bewegungsmelders (0–100 %). - Videoauflösung (
select.resolution): Live-Umschaltung der Kameraauflösung (1080p,720p,360p).
- Dämmerungsschwelle (
- 🩺 Diagnose:
- PIR-Status (
binary_sensor.pir_status): Zeigt den Betriebszustand des PIR-Sensors an (running).
- PIR-Status (
- 🎮 Steuerung:
-
💡 Hinweise zu Hardware-Grenzen & Bewegungserkennung:
- Kein kontinuierlicher Luxmeter-Sensor (
sensor.lux): Die Steinel-Kamera besitzt keinen digitalen Helligkeitsmesser (wie eine Wetterstation), sondern einen analogen Photowiderstand (LDR), der lediglich mit der eingestellten Dämmerungsschwelle abgeglichen wird. - Kein lokaler Hardware-PIR-Push (
binary_sensor.motion): Die Kamera-Firmware meldet Bewegungsevents ab Werk ausschließlich über das Cloud-Gateway des Herstellers an die Steinel-Smartphone-App. Auf der lokalen Schnittstelle wird der 1080p-Live-Stream bereitgestellt. - Bewegungserkennung & Apple HomeKit Secure Video (HKSV): Die Bewegungserkennung wird in Smart-Home-Umgebungen
standardmäßig per Video-Bildanalyse realisiert:
- In Home Assistant: Über Frigate oder MotionEye für präzise KI-Objekterkennung (Personen, Fahrzeuge, Tiere).
- In Scrypted: Über das offizielle Plugin
OpenCV Motion Detector(@scrypted/opencv) für latenzfreie HomeKit-Mitteilungen und HKSV-Cloud-Aufzeichnungen.
- Kein kontinuierlicher Luxmeter-Sensor (
-
Autarkes Single-Binary: Kein Python, kein Node.js und kein separater MediaMTX-Server erforderlich.
- Im Betrieb als HomeAssistant AddOn Image mit minimalsten Abhängigkeiten.
-
24/7 Resilienz & Watchdog: RTP-Silence Watchdog, 30s Cooldown, mDNS-Wakeup.
🐳 Bereitstellung (Home Assistant Add-on & Docker)
Option A: Home Assistant Add-on (Empfohlen für Home Assistant Nutzer)
- Klicken Sie auf das "Open in Home Assistant" Badge oben oder fügen Sie in Home Assistant unter Einstellungen ➔ Add-ons ➔ Add-on Store ➔ Repositories (Drei-Punkte-Menü) folgende URL hinzu:
https://github.com/Afrouper/steinel-cam-bridge - Wählen Sie "Steinel CAM Bridge" aus und klicken Sie auf Installieren.
- Tragen Sie im Reiter Konfiguration Ihre
camera_ipund denqr_codeein und klicken Sie auf Starten!
Option B: Standalone Docker Compose (Empfohlen für Server / NAS mit Security Hardening)
Eine fertige Vorlage finden Sie unter examples/docker-compose.yml.
Starten mit:
docker compose up -d
Option C: Standalone Docker Run (Gehärtet)
docker run -d \
--name steinel-cam-bridge \
--restart unless-stopped \
--net=host \
--user "1000:1000" \
--security-opt no-new-privileges:true \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=64M \
--memory=256m \
--cpus=0.5 \
--pids-limit=100 \
-e CAMERA_IP="IP-ADDESS" \
-e QR_CODE="did=de-xxxxxxx,pid=pr-xxxxx,sct=xxxx,pairPwd=xxxx" \
-e AUDIO_CODEC="aac" \
-e MQTT_BROKER="tcp://<IP-ADDESS>:1883" \
-e MQTT_USER="homeassistant" \
-e MQTT_PASSWORD="secretpassword" \
-v ./data:/data \
ghcr.io/afrouper/steinel-cam-bridge:latest
📱 Einbindung in Home Assistant & Scrypted
1. Home Assistant (MQTT)
Wird kein separater MQTT Broker konfiguriert wird automatisch der in HomeAssistant integrierte Standard Broker verwendet. In Home Assistant unter Einstellungen ➔ Geräte & Dienste ➔ MQTT erscheint automatisch das Gerät "Steinel L 625 CAM SC" mit allen Licht-, Sensor- und Steuerungsentitäten:
2. Scrypted (Home Assistant Add-on oder Standalone)
Egal ob Scrypted als Home Assistant Add-on oder als eigenständige Instanz läuft:
- Im Scrypted ONVIF Plugin auf Add Camera klicken (IP-Adresse des Bridge-Servers, Port
8000). - Scrypted erkennt automatisch 1080p Video, natives AAC-Mikrofon und Gegensprechanlage.
- Natives Audio: Die Bridge liefert standardmäßig natives AAC-Audio (16 kHz). In Scrypted ist kein manuelles Audio-Transcoding im HomeKit-DEBUG-Reiter erforderlich.
- Bewegungserkennung für HKSV aktivieren:
- In Scrypted unter Plugins das Plugin
OpenCV Motion Detector(@scrypted/opencv) installieren. - Auf der Steinel-Kamera im Reiter Extensions das Plugin OpenCV Motion Detector aktivieren.
- In Scrypted unter Plugins das Plugin
- Im HomeKit Plugin die Kamera aktivieren ➔ Live-Streaming & HKSV-Aufnahmen in Apple Home laufen vollautomatisch!
🗄️ SD-Karten REST API (Ereignisse, Snapshots & Video-Download)
Die Bridge stellt auf Port 8000 eine direkte 1:1 REST-API bereit, um Aufnahmen der internen SD-Karte abzufragen und ohne Umwege per HTTP-Stream herunterzuladen (Zero-Disk I/O).
| Endpunkt | Methode | Beschreibung |
|---|---|---|
/api/sdcard/events |
GET |
Liefert die JSON-Liste aller Video-Ereignisse (Query-Parameter: start, end, page, limit) |
/api/sdcard/events/{id}/thumbnail.jpg |
GET |
Liefert das JPEG-Vorschaubild der Aufnahme direkt aus dem Kameraspeicher (sofern vom Modell unterstützt, sonst HTTP 501 Not Implemented) |
/api/sdcard/events/{id}/video.mp4 |
GET |
Streamt die vollständige MP4-Aufnahme (2560x1440 HEVC / AAC) als Binärstream (inkl. Hardware-Überlastungsschutz) |
[!NOTE] SD-Karten Snapshots vs. Video-Downloads: Manche Kameramodelle (u. a. Steinel L 625 CAM SC) legen auf der internen MicroSD-Karte ausschließlich vollständige Video-Clips (
event_<timestamp>.mp4) und keine separaten JPEG-Dateien ab. Um Wartezeiten und Schnittstellen-Blockaden zu vermeiden, quittiert/api/sdcard/events/{id}/thumbnail.jpgbei solchen Modellen Anfragen sofort mitHTTP 501 Not Implemented. Das MP4-Video steht unter/api/sdcard/events/{id}/video.mp4uneingeschränkt zum Download und zur Wiedergabe bereit.
[!TIP] Eingebauter Hardware-Schutz (Concurrency = 1): Um die kleine Embedded-CPU der Steinel-Kamera vor Überlastung zu schützen, erlaubt die Bridge immer nur genau einen aktiven Download gleichzeitig. Parallele Abfragen werden mit
HTTP 429 Too Many Requestsbeantwortet. Bricht ein Client den Download vorzeitig ab, stoppt die Bridge den Kamera-Transfer sofort.
💻 Lokale Entwicklung (macOS & Linux)
Die Bridge kann vollständig nativ auf einem Entwickler-Rechner (macOS / Linux) ohne Docker gebaut, getestet und ausgeführt werden:
1. Nabto SDK vorbereiten
Laden Sie die passende native Nabto Client SDK-Bibliothek (libnabto_client.dylib bzw. .so) einmalig in das lokale .sdk/-Verzeichnis herunter:
./scripts/setup-sdk.sh
2. Lokale Tests ausführen
# macOS:
DYLD_LIBRARY_PATH="$(pwd)/.sdk/lib" go test -v ./...
# Linux:
LD_LIBRARY_PATH="$(pwd)/.sdk/lib" go test -v ./...
3. Natives Binary kompilieren
# macOS:
CGO_LDFLAGS="-L$(pwd)/.sdk/lib -lnabto_client" CGO_CFLAGS="-I$(pwd)/.sdk/include" go build -o steinel-bridge ./cmd/steinel-bridge
# Linux:
CGO_LDFLAGS="-L$(pwd)/.sdk/lib -lnabto_client" CGO_CFLAGS="-I$(pwd)/.sdk/include" go build -o steinel-bridge ./cmd/steinel-bridge
4. Bridge lokal starten
# macOS (Steinel L 625 CAM SC via Nabto Edge CGo):
DYLD_LIBRARY_PATH="$(pwd)/.sdk/lib" ./steinel-bridge \
-ip 192.168.1.100 \
-qr "did=de-xxxxxxx,pid=pr-xxxxx,sct=xxxx,pairPwd=xxxx" \
-key ./data/local_client.key \
-debug
# Linux (Steinel L 625 CAM SC via Nabto Edge CGo):
LD_LIBRARY_PATH="$(pwd)/.sdk/lib" ./steinel-bridge \
-ip 192.168.1.100 \
-qr "did=de-xxxxxxx,pid=pr-xxxxx,sct=xxxx,pairPwd=xxxx" \
-key ./data/local_client.key \
-debug
# Steinel L 620 CAM / XLED CAM 1 (kein CGo / Nabto SDK erforderlich):
./steinel-bridge \
-ip 192.168.1.100 \
-type l620 \
-user admin \
-pass "meinpasswort" \
-debug
⚙️ Konfiguration & Umgebungsvariablen
Die Konfiguration erfolgt nach den Grundsätzen einer 12-Factor App in folgender Prioritätsreihenfolge:
- Explizite CLI-Flags (höchste Priorität)
- Umgebungsvariablen
- Konfigurationsdatei (
/data/options.jsonim Home Assistant Add-on) - Interne Defaults
Kameraverbindung & Authentifizierung
| Umgebungsvariable | CLI-Flag | Standard | Beschreibung |
|---|---|---|---|
CAMERA_IP |
-ip |
"" |
Lokale IP-Adresse der Steinel-Kamera im Heimnetz (Pflicht) |
CAMERA_TYPE |
-type |
auto |
Kameramodell: auto (automatische Erkennung), l625 (L 625 CAM SC), l620 (L 620 CAM / XLED CAM 1) |
CAMERA_USER |
-user |
admin |
Benutzername für L 620 CAM (Standard: admin) |
CAMERA_PASSWORD / CAMERA_PASS |
-pass (oder -password) |
"" |
Geräte-Passwort für L 620 CAM (in der Steinel-App vergeben) |
QR_CODE |
-qr |
"" |
QR-Code Payload aus der Steinel App ("Kamera teilen") für automatisches Pairing der L 625 CAM SC |
KEY_PATH |
-key |
data/client.key |
Speicherpfad für den persistenten ECC-Schlüssel (L 625 CAM SC) |
RESET_PAIRING |
-reset-pairing |
false |
Löscht den gespeicherten Private Key und erzwingt ein erneutes Pairing mit dem angegebenen QR-Code |
Streaming & Server-Ports
| Umgebungsvariable | CLI-Flag | Standard | Beschreibung |
|---|---|---|---|
RESOLUTION |
-res |
1080p |
Videoauflösung: 1080p, 720p, 360p |
AUDIO_CODEC |
-audio-codec |
aac |
Audio-Codec des RTSP/ONVIF Streams: aac (nativ transkodiert, empfohlen) oder pcmu (Raw Passthrough) |
RTSP_PORT |
-port |
8554 |
Port des integrierten RTSP-Servers |
RTSP_PATH |
-path |
steinel |
Stream-Pfad des RTSP-Servers (rtsp://<host>:<port>/<path>) |
ONVIF_PORT |
-onvif |
8000 |
Port des integrierten ONVIF HTTP- und SD-Karten REST API-Servers |
SDCARD_SYNC_INTERVAL / SYNC_INTERVAL |
-sync-interval (oder -sdcard-sync-interval) |
60 |
Intervall in Sekunden für die Hintergrundabfrage neuer MicroSD-Aufnahmen (5–300 s) |
Nabto Edge Treiber & Diagnose (L 625 CAM SC)
| Umgebungsvariable | CLI-Flag | Standard | Beschreibung |
|---|---|---|---|
NABTO_DRIVER |
-nabto-driver |
cgo |
Nabto-Treiber-Engine: cgo (offizielles C-SDK, empfohlen & Standard) oder pure (nativer Go-Stack, experimentell) |
USE_CGO_NABTO |
-use-cgo |
true |
Boolean-Schalter für CGo-Treiber (true = cgo, false = pure) |
DEBUG |
-debug |
false |
Ausführliches Debug-Logging für RTSP, WebRTC, Signaling & MCU |
IS_BETA / BETA |
-beta |
false |
Kennzeichnet die Instanz bei der IAM-Registrierung auf der Kamera als Beta (steinel-bridge-beta-...) |
MQTT & Home Assistant Integration
| Umgebungsvariable | CLI-Flag | Standard | Beschreibung |
|---|---|---|---|
MQTT_BROKER |
-mqtt-broker |
"" |
MQTT Broker URL (z. B. tcp://192.168.1.100:1883). Leer lassen für automatische Supervisor-Erkennung im Home Assistant Add-on |
MQTT_USER |
-mqtt-user |
"" |
MQTT Benutzername |
MQTT_PASSWORD |
-mqtt-pass |
"" |
MQTT Passwort |
MQTT_TOPIC_PREFIX |
-mqtt-topic |
steinel |
MQTT Basis-Topic (Geräte-ID wird automatisch angehängt: <prefix>/<did>/...) |
MQTT_DISCOVERY_PREFIX |
-mqtt-disc |
homeassistant |
Home Assistant MQTT Auto-Discovery Prefix |
📄 Lizenz & Disclaimer
- Projektlizenz: Dieses Projekt ist unter der MIT License lizenziert.
- Third-Party Lizenzen: Siehe THIRD_PARTY_LICENSES.md für Hinweise zum Nabto Edge Client SDK und zu den Go-Bibliotheken.
[!NOTE] Das bereitgestellte Docker-Image enthält keinerlei proprietäre Fremdbibliotheken. Da die Nabto Lizenz keine Distribution zulässt, wird beim allerersten Start des Containers die benötigte
libnabto_client.sovollautomatisch direkt von Nabtos offiziellem GitHub-Repository auf das System des Nutzers geladen und persistent im Cache (/data/lib/) gespeichert.
[!NOTE] Dies ist ein unabhängiges Open-Source-Community-Projekt. Es steht in keiner geschäftlichen Verbindung zur STEINEL GmbH, Nabto ApS oder Apple Inc. Alle Markennamen sind Eigentum der jeweiligen Rechteinhaber.