Die anderen Sektionen der Konfigurationsdatei (erkennbar an den eckigen Klammern) beziehen sich auf den jeweiligen Kamerastandort. Für jeden davon müssen Sie zumindest einen Namen vergeben (Zeile 11, 14 und 17), den unter anderem die Weboberfläche während der Live-Betrachtung anzeigt. Eine zweite Grundangabe besteht darin, dem RasPi-Standort eine IP-Adresse zuzuordnen (Zeile 12, 15 und 18).
Im Beispiel machen die beiden Beobachtungsposten [Haustür] (Zeile 11 und 12) und [Garten] (Zeile 14 und 15) von dieser Minimalkonfiguration Gebrauch. Da das Skript zu diesen beiden Standorten keine zusätzlichen Angaben enthält, greifen bei diesen die Einstellungen der Sektion Global. Die dritte Kamera mit dem Namen [1. Obergeschoss] (Zeile 17 bis 20) weicht davon hingegen bei zwei Werten ab (Zeile 19 und 20), die an diesem dunklen Standort zu besseren Bildern führen.
Der Parser des Konfigurationsskripts config_einlesen.php (Listing 2) lässt vieles durchgehen. So besteht er beispielsweise nicht auf korrekter Groß- und Kleinschreibung. Fehlen in der globalen Sektion der Konfigurationsdatei Angaben, dann setzt das Skript diese auf hartkodierte Werte, die im Durchschnittsfall Sinn ergeben. So führt Zeile 16 in Listing 2 dazu, dass die Software JPG-Bilder mit einem Qualitätsgrad von 75 Prozent (ein guter Kompromiss zwischen Qualität und Größe des Bilds) komprimiert, obwohl die config.txt-Datei in unserem Beispiel keine Angabe hierzu enthält. Wollten Sie stattdessen Platz auf den SD-Karten sparen, könnten Sie die Konfigurationsdatei etwa um den Eintrag Qualität = 50 ergänzen.
Die Zeilen 17 bis 19 treffen ebenfalls Entscheidungen, für die in der config.txt des Beispielfalls Angaben fehlen: Die Kamera soll Fotos mit der maximal möglichen Auflösung erstellen, ohne dabei den speicherintensiven RAW-Modus zu verwenden.
Listing 2
<?php
// Config-Datei auslesen, Ergebnis speichern in in den Arrays
// $globale_einstellungen und $lokale_einstellungen
if (isset($config_daten)) $config_array = parse_ini_string($config_daten, TRUE);
else $config_array = parse_ini_file('config.txt', TRUE);
// Einige Standard-Werte vordefinieren für den Fall, dass
// die [Global]-Gruppe der Config-Datei keine Werte angibt
$globale_einstellungen['SCHAERFE'] = 0;
$globale_einstellungen['KONTRAST'] = 0;
$globale_einstellungen['HELLIGKEIT'] = 50;
$globale_einstellungen['SAETTIGUNG'] = 0;
$globale_einstellungen['ISO'] = 400;
$globale_einstellungen['INTERVALL'] = 5;
$globale_einstellungen['QUALITAET'] = 75;
$globale_einstellungen['RAW'] = 0;
$globale_einstellungen['BREITEFOTOS'] = 2592;
$globale_einstellungen['HOEHEFOTOS'] = 1944;
// Werte der Sektion [Global] der Config-Datei einem Array zuweisen
foreach ($config_array as $kategorie => $einstellungen) {
if (strtoupper($kategorie)=='GLOBAL') {
foreach($einstellungen as $schluessel=>$wert) {
$globale_einstellungen[strtoupper($schluessel)] = $wert;
}
unset($config_array[$kategorie]);
}
}
// Lokale Einstellungen für jede Kamera einlesen. Optionen,
// für die nichts definiert wurde, auf den globalen Wert setzen
foreach ($config_array as $kamera_name => $einstellungen) {
$lokale_einstellungen[$kamera_name] = $globale_einstellungen;
foreach($einstellungen as $schluessel=>$wert) {
$lokale_einstellungen[$kamera_name][strtoupper($schluessel)] = $wert;
}
}
?>
Nach dem Fertigstellen der Konfigurationsdatei booten Sie alle RasPis, die daraufhin sofort mit dem Aufnehmen und Abspeichern der Überwachungsbilder beginnen. Um das Geschehen live mitzuverfolgen, rufen Sie im Webbrowser eines PCs die Adresse http://IP_des_Steuer-RasPis/cam/ auf. Die Seite aktualisiert sich nach Ablauf des konfigurierten Sekundenintervalls selbstständig.
Nachtaufnahmen
Seit Kurzem steht das für Nachtaufnahmen geeignete Pi-NoIR-Modul für den Raspberry Pi zum Kauf bereit [2]. Möchten Sie ein solches in Ihre Videoüberwachungslösung einbeziehen, müssen Sie den zu filmenden Ort zusätzlich mit unsichtbarem Infrarotlicht ausleuchten. Tagsüber sorgt der fehlende Infrarotfilter der Pi-NoIR-Kameravariante jedoch dafür, dass das Bild leichte Falschfarben aufweist.
Das Pi-NoIR-Modul ergibt im Rahmen einer Videoüberwachung nur dann Sinn, wenn die Kamera unentdeckt bleiben soll. In allen anderen Fällen setzen Sie besser die Standard-Variante ein, deren Bilder bei Tageslicht keine Falschfarben aufweisen. Und das Problem der nächtlichen Dunkelheit lässt sich hier dadurch lösen, dass Sie an den Aufstellungsorten einfach eine herkömmliche Lampe montieren und an einen Bewegungsmelder koppeln.
Anpassungen
Mit wenigen Handgriffen erweitern Sie die Überwachungskameralösung um zusätzliche Funktionen. Dabei stehen Ihnen, anders als bei einer gekauften Anlage, alle Möglichkeiten offen, die sich aus einem Netzwerk aus Linux-(Raspberry-Pi)-Rechnern ergeben. Soll beispielsweise regelmäßig ein Backup der neu aufgenommenen Bilder auf einem Server im Internet erfolgen, legen Sie einfach einen Cronjob an, der jeweils das Unterverzeichnis /var/www/cam/bilder/ über das Kommandozeilentool Rsync spiegelt.
Damit Sie unkompliziert weitere Anpassungen vornehmen können, haben wir das Projekt absichtlich mittels leicht lesbarer und ausführlich kommentierter PHP-Skripte umgesetzt. Im Folgenden schildern wir als Hilfe den Ablauf der Skripte.
Die Datei config_einlesen.php (Listing 2) parst die aktuelle Konfigurationsdatei und schreibt alle Ergebnisse in ein Array. Das Skript steuere_kamera.php (Listing 3), das auf jedem eingebundenen RasPi im Hintergrund läuft, realisiert in einer Endlosschleife den immer gleichen Ablauf: Die Datei config.txt wird per HTTP-Request vom zentralen Steuerungsrechner angefordert und anschließend durch das Einbinden von config_einlesen.php geparst. Dann nimmt das angeschlossene Kameramodul gemäß des Config-Arrays ein Foto auf und legt es im Unterverzeichnis /bilder/ ab. Nun friert der Ablauf für die im Intervallwert konfigurierte Sekundenanzahl ein, bevor die Schleife von vorne beginnt.
Listing 3
<?php
// IP-Adresse des Haupt-RasPis
$config_server = '192.168.2.50';
// Standard-Intervall von fünf Sekunden verwenden
$intervall = 5;
// Eigene IP feststellen
$eigene_ip = eigene_ip_herausfinden();
while (TRUE) {
// Vom Hauptserver die aktuelle Config holen
$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, "http://$config_server/cam/config.txt");
curl_setopt($handle, CURLOPT_HEADER, FALSE);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
$config_daten = curl_exec($handle);
$http_code = curl_getinfo($handle, CURLINFO_HTTP_CODE);
// Nur etwas unternehmen, wenn die aktuelle Konfiguration
// gelesen werden konnte, also der Haupt-Raspi online ist
if ( ($config_daten <> FALSE) AND ($http_code == 200) ) {
require('config_einlesen.php');
// Anhand der IP das richtige Config-Unterarray herausfinden
foreach ($lokale_einstellungen as $schluessel => $einzelne_kamera) {
if ($einzelne_kamera['IP'] == $eigene_ip) {
$diese_kamera = $lokale_einstellungen[$schluessel];
break;
}
}
// Raspistill aufrufen
$schaerfe = (int)$diese_kamera['SCHAERFE'];
$kontrast = (int)$diese_kamera['KONTRAST'];
$helligkeit = (int)$diese_kamera['HELLIGKEIT'];
$saettigung = (int)$diese_kamera['SAETTIGUNG'];
$iso = (int)$diese_kamera['ISO'];
$intervall = (int)$diese_kamera['INTERVALL'];
$qualitaet = (int)$diese_kamera['QUALITAET'];
$breitefotos = (int)$diese_kamera['BREITEFOTOS'];
$hoehefotos = (int)$diese_kamera['HOEHEFOTOS'];
$cmd = "raspistill -o ./bilder/neuestes_bild.jpg --timeout 0 --encoding jpg --nopreview --sharpness $schaerfe --contrast $kontrast --brightness $helligkeit --saturation $saettigung --ISO $iso --quality $qualitaet --width $breitefotos --height $hoehefotos";
if ( $diese_kamera['RAW'] == 1) $cmd .= ' --raw';
// Kopie von neuestes_bild.jpg anlegen, Dateinamen aus Datum und Uhrzeit bilden
// Zur besseren Sortierbarkeit stehen Jahr und Monat im Namen vorne
$dateiname = date('Y-m-d__H:i:s').".jpg";
exec($cmd);
copy('./bilder/neuestes_bild.jpg','./bilder/'.$dateiname);
}
else print "Konfigurationsdatei konnte nicht empfangen werden --> Haupt-RasPi ist offline?\n";
curl_close($handle);
// Für die Wartezeit eine Sekunde abziehen, die bereits für die Aufnahme verbraucht wurde
sleep($intervall-1);
}
function eigene_ip_herausfinden()
{
// ifconfig aufrufen
exec("/sbin/ifconfig eth0", $ausgabe);
// IP so ausfiltern, dass dies sowohl für EN als auch DE funktioniert
$eigene_ip = $ausgabe[1];
$eigene_ip = strstr($eigene_ip, 'inet ');
$eigene_ip = substr($eigene_ip, strpos($eigene_ip,':')+1);
$eigene_ip = substr($eigene_ip, 0, strpos($eigene_ip,' '));
return $eigene_ip;
}
?>
Um eine Erweiterung zu schreiben, die beispielsweise nach einiger Zeit ältere Bilder löscht, ist das Schema der Dateinamen von Bedeutung. Das Skript bildet sie nach dem Prinzip Jahr-Monat-Tag__Stunde:Minute:Sekunde.jpg. Diese Reihenfolge bietet den Vorteil, dass bei ein nach Zahlengröße sortiertes Directory-Listing den neuesten Eintrag zuerst und der ältesten als Letztes zurückgibt. Zusätzlich legt das Skript die aktuellste Aufnahme immer auch unter dem Dateinamen neuestes_foto.jpg ab.
Die über den Browser aufzurufende Datei index.php ist hier aus Platzgründen nicht abgedruckt, steht jedoch zusammen mit den anderen Dateien des Projekts auf der Heft-DVD zur Verfügung. Sie bezweckt nicht viel mehr, als zuerst unter Einbindung von config_einlesen.php die Konfiguration einzulesen und anschließend eine HTML-Seite auszugeben: Unter dem Namen jeder Kamera erscheint dabei jeweils deren zuletzt geschossenes Bild.
Die Fotos der an anderen Standorten aufgestellten Raspberrys, auf denen ja ebenfalls ein Apache2-Daemon läuft, bindet das Skript per HTTP-Request ein. Die ständige Aktualisierung der Darstellung erzwingt die HTML-Seite über eine Meta-Anweisung im <head>. Änderungen an der Datei index.php sollten für Sie nur dann von Interesse sein, wenn Sie das Layout der Weboberfläche verändern möchten.
Schlaue Einbrecher?
In Krimis oder auch im dystopischen Rollenspiel Shadowrun gilt ein Szenario als sehr beliebt: Einbrecher heuern einen Hacker an, der über das Internet die Videoüberwachungsanlage eines Objekts lahmlegt. Anschließend räumen die restlichen Täter das Haus in Ruhe leer. Alternativ ersetzt der Hacker angefertigte Aufnahmen durch ein älteres Standbild, auf dem nichts Verdächtiges passiert. Auf diese Weise fällt der Einbruch unter Umständen erst viel später auf.





