node-zoocam – IP-Kameras auf sicherem Weg öffentlich bereitstellen

Im Rahmen einer größeren Umgestaltung wurden in den Terrarien des Schulzoos des Collegium Josephinum einige IP-Kameras installiert. Diese sehr günstigen Kameras eines No-Name Herstellers mit Pan- und Tilt-Funktion (Rotation um zwei Achsen) stellten lediglich ein sehr rudimentäres Web-Interface zur Interaktion bereit, auf dem der Großteil der Einstellungsmöglichkeiten bereits garnicht funktionierte. Um den Kamera-Stream im Browser betrachten zu können, ist zudem ein Flash-Plugin notwendig, was moderne Browser überhaupt nicht mehr unterstützen. Ziel war es nun, die Bilder dieser Kameras irgendwie öffentlich bereitzustellen. Hierzu benötigt man also eine Möglichkeit die Bilddaten automatisiert abzugreifen um sie gebündelt darzustellen. Gleichzeitig wäre es für die späteren Nutzer sicherlich nett die Kameras auch selbst steuern zu können, um sich im Terrarium umzuschauen.

OnVIF-Schnittstelle

Mit etwas Recherche stellte sich heraus, dass die Kameras bereits von sich aus den OnVIF-Standard unterstützen. Der OnVIF-Standard dient der Spezifikation von Surveillance-Systemen. Neben IP-Kameras gehören dazu bspw. auch Sicherheitstüren, Sirenen oder Alarmleuchten. Durch Nutzung der OnVIF-Api-Schnittstellen ließ sich die Adresse eines RTSP-Streams (Real-Time Streaming Protocol) herausfinden, welchen die Kameras bereitstellen. Dieser Stream kann bspw. mit dem VLC-Player abgerufen werden. Leider gibt es aber bis heute keine Möglichkeit einen solchen Stream direkt im Browser darzustellen.

Die Schnittstelle bietet noch weitere Features an. So lassen sich hierüber auch die Pan- und Tilt-Funktionen der Kamera ansteuern. Der Standard sieht hierbei eigentlich eine genaue Definition von Richtung, Geschwindigkeit und Dauer vor. Die Programmierer eines der verwendeten Kameramodelle haben sich aber für eine sehr rudimentäre Umsetzung dieser Schnittstelle entschieden und unterscheiden lediglich zwischen positiven und negativen Werten für die Richtungsangabe und drehen dabei immer mit fester Dauer und Geschwindigkeit. Bestimmte Wertekombinationen für Geschwindigkeit und Dauer lassen die Kamera sogar einfach neustarten.

RTSP zu WebRTC

Mittels Einbindung des öffentlichen Projekts webrtc-streamer gelang es RTSP-Streams zu WebRTC-Streams zu wandeln. Die WebRTC-Schnittstelle dient normalerweise der Umsetzung von direkter Videotelefonie zwischen zwei Browsern, kann also direkt verwendet werden um Livebilder im Browser anzuzeigen.

Den RTSP-Stream wollte ich jedoch aufgrund der kleinen verbauten Chips nicht direkt von den Kameras beziehen, sondern schaltete einen Live555-RTSP-ProxyServer dazwischen. Diesen kann man auch öffentlich erreichbar schalten und so dem Benutzer weiterhin ein eigenständiges Abrufen des Kamerastreams im VLC-Player mit ausreichend Server-Ressourcen ermöglichen. Für beide Projekte erstellte ich angepasste Docker-Container und programmierte anhand des webrtc-streamer Projekts mein Frontend, sodass es die Streams direkt von dort einbinden konnte.

Da WebRTC auch teils komplexe Netzwerkarchitekturen unterstützen können muss, benötigt es zwei weitere Dienste, einen STUN- und einen TURN-Server, um einwandfrei zu funktionieren.

Ein STUN-Server wird benötigt, damit ein Browser mittels eines externen Dienstes seine tatsächliche öffentliche IP-Adresse und Portnummer herausfinden kann, was gerade im Fall von NATing notwendig sein kann. Er macht Client und Server untereinander bekannt. Anschließend kann mittels Hole Punching versucht werden, die bereits bestehende TCP-Verbindung weiter zu verwenden um so bspw. restriktive interne Firewalls zu umgehen und zwei eigentlich hinter Firewalls versteckte Dienste direkt miteinander zu verbinden.

Klappt das nicht, gibt es als Fallback-Möglichkeit noch die Nutzung von Relay-Servern (sog. TURN-Server). Diese müssen von Client und Server direkt erreichbar sein, empfangen den Datenverkehr beider Seiten und leiten ihn an die Gegenstelle als dritte Instanz weiter. Dadurch, dass sämtlicher Datenverkehr darüber laufen muss, müssen sie eine entsprechende Bandbreite vorhalten und selbst betrieben werden.

Fallback auf JPEG-Stream

Sollten alle Stricke reißen und eine WebRTC-Verbindung nicht möglich sein. Dies kann bspw. auch bei älteren Mobilbrowsern der Fall sein, welche schlicht kein WebRTC unterstützen, so kann mittels der OnVIF-Screenshot Schnittstelle regelmäßig ein aktuelles JPG des Kamerabildes abgerufen und weitergegeben werden. Der Server implementiert dies mit einer entsprechenden Proxyschnittstelle, um die Kameras im Falle vieler Anfragen nicht zu überlasten.

Webserver mit node.js

Der Webserver an sich basiert auf ExpressJS und implementiert eine REST-API, welche die wichtigen Funktionen und öffentlichen Adressen der Kameras bereitstellt. Er stellt außerdem ein Angular-Frontend bereit, welches die REST-API ansteuert und die Kamerastreams entsprechend visualisiert.

Docker Container-Orchestration und Deployment

Während der Entwicklung und auch im Produktivbetrieb kommt vor Allem docker-compose zum Einsatz. Hiermit lässt sich zur Entwicklungszeit schnell das gesamte Projekt bauen und unter Produktivbedingungen testen. Im Produktiveinsatz lassen sich dann recht einfach eine Versionierung und Aktualisierung durchführen. Jeder Commit auf den Master-Branch des Projekts löst den Bau einer neuen Version des Docker-Images aus, welches dann auf dem Produktivserver über die Docker Registry einfach bezogen und gestartet werden kann.

Zugriff auf das Projekt

Unter webcam.cojobo.net kann man das Projekt selber ausprobieren. Der Sourcecode ist unter auf meinen GitLab-Server einsehbar. Im Folgenden sind einige Screenshots des Projekts zu sehen.

Titelbild-Icon made by Eucalyp from www.flaticon.com

Kommentar verfassen