Kamerainstellungen
Nach Aufruf des Web-Interfaces im Browser sollte zunächst die Kamerauflösung angepasst werden.
Für die Fisheye-Kamera habe ich die Auflösung 533 x 300 (entspricht 16:9) gewählt. Es macht aus meiner Sicht keinen großen Sinn, die Auflösung deutlich höher zu wählen, weil man dadurch nur die Übertragung der Bilder verlangsamt, ohne ein Mehr an Informationen zu erhalten (die Bilder sind dafür nicht scharf genug).
Unter "Annotation" kann man sich einen Einblendtext konfigurieren. Mit "%D.%M.%Y %h:%m:%s" lasse ich mir z.B. Datum und Uhrzeit anzeigen. Gerade die Sekunden sind oftmals sehr hilfreich, um die Synchronizität mit anderen Auslösern überprüfen zu können und um im Videobild leichter erkennen zu können, dass die Kamera funktioniert.
Mit %a kann man sich noch einen beliebigen Text einblenden lassen, der in der Datei "dev/shm/mjpeg/user_annotate.txt" enthalten ist. Wie man diese Datei z.B. über die CCU beschreiben kann, werde ich später noch beschreiben. Nur soviel; ich lasse mir da die Anzahl der Briefkasteneinwürfe, die bei mir per DoorPi und CCU gezählt werden, sowie die Leerung des Briefkastens einblenden. Über "Annotation size", "Custom text color" und "Custom background color" kann man sich noch die Schriftgröße sowie die Text- und die Hintergrundfarbe einstellen. Bei "Custom text color" und "Custom background color" nicht vergessen, das Auswahlmenü auf "Enabled" zu setzen; und immer, wenn vorhanden, mit "OK" zu bestätigen.
Da für das vorliegende Projekt keine Videoaufzeichnung des Briefkastens erforderlich ist, wir aber gerne ein Standbild per Telegram oder Pushover bei einer detektierten Bewegung erhalten möchten, setzen wir im Hauptbildschirm unter "
Camera Settings" den "Motion detect mode" auf "Monitor".
- RPi_Cam_Web_Interface_04.png (20.74 KiB) 10626 mal betrachtet
Sollte das Bild in einer ungünstigen Position angezeigt werden, so kann man es unter "Rotation" sehr einfach drehen.
Bewegungserkennung
Damit nun die Bewegungserkennung bei jedem Start des Raspi Zero automatisch neu gestartet wird , trägt man im
Scheduler nach Klick auf den Button "Edit schedule settings" in der Period "AllDay" unter "Period Start" "md 1" ein.
Die Bedeutung der einzelnen Befehle kann man unter "Command reference" nachlesen. Dabei lassen sich auch verschiedene Befehle durch getrennt durch jeweils ein Simikolon verknüpfen.
EDIT: Tests haben ergeben, dass der Befehl "im" in "Motion Start" nicht für das Triggern des Shellskripts notwendig ist. Da direkt in "motion_event.sh" ein Snapshot erzeugt wird, kann man "im" komplett weglassen.
Schließlich werden die Einstellungen mit Klick auf den Button "Save Settings" gespeichert. Mit Klick auf "< Back" in der schwarzen Statutsleiste kommt man wieder zurück zum
Hauptbildschirm.
Danach können unter "
Motion Settings" die Einstellungen für die eigentliche Bewegungserkennung vorgenommen werden. Jedes Mal, wenn nun eine Bewegung erkannt wird, wird automatisch das Shell-Skript "
motion_event.sh" im Verzeichnis "/var/www/macros" ausgeführt.
Hinweis: Wer es bei der Konfiguration unter "xCam" bei "html" belassen hat, der muss die Datei "
motion_event.sh" im Verzeichnis "/var/www/html/macros" ablegen.
Um den Einfluss der Bewegung besser erkennen zu können, empfiehlt sich, zumindest temporär in die Zeile "Annotation" unter "
Camera Settings" den Zusatz "f%fc%c" hinzuzufügen. %f zeigt dann die Frames an, die jeweils um eins hochgezählt werden, wenn die mit %c angezeigten Changes den unter "Threshold" angegeben Wert erreicht haben. Da muss man etwas spielen, um die für sich optimalen Werte zu finden. Bei mir haben sich bisher die folgenden Werte als recht praktikabel erwiesen:
Threshold: 300
Delay Frames to detect: 10
Change Frames to start: 20
Still Frames to stop: 200
Wenn nun die mit %f angezeigte Anzahl der "Change Frames" erreicht wurde, kommt es zur Auslösung der Datei "motion_event.sh". In dieser habe ich mir das Senden eines Snapshots per Telegram oder Pushover (je nachdem, was ich für das zPNP auf der CCU eingestellt habe) konfiguriert.
"/var/www/macros/motion_event.sh"
Code: Alles auswählen
#!/bin/bash
CCU_IP=192.xxx.xxx.xxx # IP-Adresse der CCU
LBoxPiZero_IP=192.xxx.xxx.xxx # IP-Adresse des LBoxPiZero
# Telegram Keys
TgHMinfo=xxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Telegram Bot Token "HomeMatic Info" Benutzer 1
TgChatId1=-xxxxxxxx # Telegram Chat-ID Benutzer 1
TgChatId2= # Telegram Chat-ID Benutzer 2
# Pushover Keys
PoHMinfo=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Token "HomeMatic Info"
PoUser1=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx # API-Key Benutzer 1
PoUser2= # API-Key Benutzer 2
# HomeMatic CCU ISE_IDs
HMiseid1=xxxx # "CCU SV Push Dienst" 0(aus) 1(alle) 2(Pushover) 3(Telegram)
# CCU-Systemvariable "CCU SV Push Dienst" auslesen
service=$(curl -s -k "http://${CCU_IP}:8181/rega.exe?x=dom.GetObject(${HMiseid1}).Value()")
service=${service##*<x>}
service=${service%%</x>*}
# echo $service
if [ $1 -eq 0 ] # Abfrage, ob Ende der Bewegungserkennung
then
# Snapshot in Datei speichern
wget -O /var/www/media/Briefkasteninhalt.jpg http://${LBoxPiZero_IP}:8181/cam.jpg
# Push-Nachricht senden
if [ $service -eq 3 -o $service -eq 1 ] # Telegram
then
if [ -n "$TgChatId1" ] # Benutzer 1
then
curl -s -k "https://api.telegram.org/bot${TgHMinfo}/sendPhoto" -F chat_id=$TgChatId1 -F disable_notification=1 -F photo="@/var/www/media/Briefkasteninhalt.jpg"
fi
if [ -n "$TgChatId2" ] # Benutzer 2
then
curl -s -k "https://api.telegram.org/bot${TgHMinfo}/sendPhoto" -F chat_id=$TgChatId2 -F disable_notification=1 -F photo="@/var/www/media/Briefkasteninhalt.jpg"
fi
elif [ $service -eq 2 -o $service -eq 1 ] # Pushover
then
if [ -n "$PoUser1" ] # Benutzer 1
then
curl -s -k -F token=$PoHMinfo -F user=$PoUser1 -F message="Briefkasteninhalt" -F attachment="@/var/www/media/Briefkasteninhalt.jpg" -F priority=-1 -F sound=none -F html=1 "https://api.pushover.net/1/messages.json"
fi
if [ -n "$PoUser2" ] # Benutzer 2
then
curl -s -k -F token=$PoHMinfo -F user=$PoUser2 -F message="Briefkasteninhalt" -F attachment="@/var/www/media/Briefkasteninhalt.jpg" -F priority=-1 -F sound=none -F html=1 "https://api.pushover.net/1/messages.json"
fi
fi
fi
exit 0
Der eigentliche Kern dieses Shell-Skripts sind die mit "curl" anfangenden Zeilen und der Befehl zum Speichern des Snapshots. Der Rest ist mehr oder weniger "nützliches Beiwerk". So schwer dürfte es aber nicht sein, das Skript an seine eigenen Anforderungen anzupassen. Ein weiteres Beispiel zum Senden von Snapshots per Telegram findet sich unter anderem auch
hier.
Das Makro "motion_event.sh" wird normalerweise bei jedem Start und bei jedem Ende einer erkannten Bewegung aufgerufen. Für die Meldung der Briefkasteneinwürfe ist das jedoch eher ungünstig. Da ist es aus meiner Sicht besser, wenn das Skript nur nach Beendigung der Bewegung ausgeführt wird. Dies erreicht man durch die folgende Abfrage im obigen Shell-Skript:
Hinweis: Nicht vergessen, die Datei "motion_event.sh" mit
ausführbar zu machen.
Erzeugen von Bemerkungen (Annotations) mittels CCU
Um von der CCU aus Dateien auf dem Raspi Zero schreiben und verändern zu können, sind zunächst folgende Schritte auf dem Raspi Zero und der CCU per PuTTY, Termius oder einem anderen Terminal-Programm auszuführen:
Raspi Zero (IPv4: 192.xxx.xxx.xxx)
Code: Alles auswählen
sudo mkdir /home/pi/.ssh
sudo chmod -R 777 /home/pi/.ssh
Die Schreibrechte müssen zunächst für alle eingeräumt werden, da ssh-copy-id sonst im nachfolgenden Schritt die Datei "authorized_keys" nicht anlegen kann.
CCU (IPv4: 192.xxx.xxx.xxx)
- Bemerkung: nicht für CCU3 erforderlich
-
- Enter file in which to save the key (/root/.ssh/id_rsa): Return-Taste drücken
- Enter passphrase (empty for no passphrase): Return-Taste drücken
- Enter same passphrase again: Return-Taste drücken
-
Achtung (
nur für CCU1 und 2 erforderlich): nach einem FW-Update der CCU gehen die rsa-Dateien im root-Verzeichnis der CCU in der Regel verloren (dies ist bei der Raspberrymatic nicht der Fall). Daher empfiehlt sich, das von uwe111 erzeugte WebUI-Addon
ssh-keygen auf der CCU zu installieren. Damit sind die Dateien dann sicher.
Raspi Zero (IPv4: 192.xxx.xxx.xxx)
Wichtig: Die Schreibrechte des Ordners ".ssh" müssen abschließend auf den Eigentümer beschränkt sein (755 oder 700). Ansonsten wird immer wieder eine Authentifizierung verlangt und das automatische Einwählen der CCU auf dem Raspi schlägt fehl.
Nun legt man mit
Code: Alles auswählen
sudo nano /home/pi/RPi_Cam_Web_Interface/user_annotate.txt
eine leere Datei im Verzeichnis "/home/pi/RPi_Cam_Web_Interface" an und beendet den Editor mit Ctrl-X und J zum Abspeichern. Anschließend vergibt man noch Lese- und Schreibreichte für alle:
Code: Alles auswählen
sudo chmod 666 /home/pi/RPi_Cam_Web_Interface/user_annotate.txt
Wichtig: Standardmäßig ist raspimjpeg so konfiguriert, dass es die Datei "user_annotate.txt" im Verzeichnis "/dev/shm/mjpeg" erwartet. Dies führt aber leider dazu, dass die Datei bei jedem Refresh des Verzeichnisses wieder gelöscht wird und die Annotations nur flüchtig sind. Daher muss "/etc/raspimjpeg" mit
so umkonfiguriert werden, dass der Eintrag
in
Code: Alles auswählen
user_annotate /home/pi/RPi_Cam_Web_Interface/user_annotate.txt
geändert wird. Danach den Raspi mit
zur Übernahme der Änderungen neu starten.
Mit dem nachfolgenden Skript-Schnipsel der CCU lassen sich nun bei jedem Aufruf die Einwürfe um eins hoch zählen und in die Datei "user_annotate.txt" schreiben.
Code: Alles auswählen
string svMailCount = "EG Briefkasten SV Einwürfe"; ! Systemvariablen-Name (Typ Zahl) für die Anzahl der Einwürfe
string login = "pi@192.xxx.xxx.xxx"; ! Einwahldaten des LBoxPiZero
integer inserts; ! Anzahl der Einwürfe
inserts = (dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount)).Value();
inserts = inserts + 1;
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount)).State(inserts);
(dom.GetObject(ID_DATAPOINTS).Get("CUxD.CUX2801001:1.CMD_EXEC")).State("echo -n "#inserts#" Einwurf | ssh "#login#" 'cat > /home/pi/RPi_Cam_Web_Interface/user_annotate.txt");
Hier nun ein Beispiel für ein WebUI-Programm samt zweier Skripte, die jeweils beim Öffnen der Briefkasten-Klappe (Post-Einwurf) und der -Tür (Post-Entnahme) aufgerufen werden. Als Trigger dienen virtuelle Tasten (VT), weil die eigentliche Auslösung durch den DoorPi erfolgt, der bekanntlich selbst keine HM-Komponente ist. Ich möchte an dieser Stelle jedoch nicht zu sehr ins Detail gehen, da das den Rahmen dieser Projektbeschreibung sprengen würde. Der geneigte Leser sei auf meine Signatur und das darin verlinkte DoorPi-Projekt verwiesen.
WebUI-Skript zum Zählen der Briefkasteneinwürfe
Code: Alles auswählen
! Briefkasten-Einwürfe um Eins erhöhen und Meldung Briefkasten leeren
! Version 3.0.5, Autor: dtp
! Namen der verwendeten Systemvariablen
string svPushText = "CCU SV Push Text"; ! gem. zPNS-xx, obligatorisch
string svPushPrio = "CCU SV Push Prio"; ! gem. zPNS-xx, obligatorisch
string svMailCount = "EG Briefkasten SV Einwürfe"; ! Anzahl der Einwürfe, obligatorisch
string svPushoverSound = "CCU SV Pushover Sound"; ! gem. zPNS-Po, optional
! Name des zentralen Push-Nachrichten-Programms
string zPNP = "CCU PRG Push-Nachrichten"; ! obligatorisch
! Einwahldaten des LBoxPiZero
string login = "pi@192.xxx.xxx.xxx";
! #####################################################################
! ##### ab hier bitte keine weiteren Einstellungen mehr vornehmen #####
! #####################################################################
! +++++ Variablendeklaration +++++
string message;
integer inserts;
object svObject; object svObjectList;
! +++++ Systemvariablen erzeugen bzw. falls vorhanden, auslesen +++++
if(!svMailCount){svMailCount = "EG Briefkasten SV Einwürfe";}
svObject = dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount);
if(!svObject){
svObjectList = dom.GetObject(ID_SYSTEM_VARIABLES); svObject = dom.CreateObject(OT_VARDP); svObjectList.Add(svObject.ID());
svObject.Name(svMailCount); svObject.DPInfo("Anzahl der Briefkasteneinwürfe"); svObject.Internal(false); svObject.Visible(true);
svObject.ValueType(ivtFloat); svObject.ValueSubType(istGeneric); svObject.ValueUnit(""); svObject.ValueMin(0); svObject.ValueMax(65000); dom.RTUpdate(true);
}
! +++++ Setzen der Priorität für die Push-Nachricht +++++
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushPrio)).State("0");
! +++++ Sound für Pushover-Nachricht +++++
if(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushoverSound)){(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushoverSound)).State("intermission");}
! +++++ Anzahl Einwürfe hochzählen +++++
inserts = (dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount)).Value().ToInteger();
inserts = inserts + 1;
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount)).State(inserts);
! +++++ Erzeugen der Nachricht und Einwürfe in Datei auf LBoxPiZero schreiben +++++
message = "<font color=royalblue>Briefkasten leeren!\n</font> ";
if(inserts == 1){
message = message#"1 Einwurf.";
(dom.GetObject(ID_DATAPOINTS).Get("CUxD.CUX2801001:1.CMD_EXEC")).State("echo -n "#inserts#" Einwurf | ssh "#login#" 'cat > /home/pi/RPi_Cam_Web_Interface/user_annotate.txt'");
}
elseif(inserts > 1){
message = message#inserts#" Einwürfe.";
(dom.GetObject(ID_DATAPOINTS).Get("CUxD.CUX2801001:1.CMD_EXEC")).State("echo -n "#inserts#" Einwuerfe | ssh "#login#" 'cat > /home/pi/RPi_Cam_Web_Interface/user_annotate.txt'");
}
! +++++ zPNP ausführen +++++
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushText)).State(message);
(dom.GetObject(ID_PROGRAMS).Get(zPNP)).ProgramExecute();
WebUI-Skript für das Leeren des Briefkastens
Code: Alles auswählen
! Meldung Briefkasten geleert
! Version 3.0.3, Autor: dtp
! Namen der verwendeten Systemvariablen
string svPushText = "CCU SV Push Text"; ! gem. zPNS-xx, obligatorisch
string svPushPrio = "CCU SV Push Prio"; ! gem. zPNS-xx, obligatorisch
string svPushoverSound = "CCU SV Pushover Sound"; ! gem. zPNS-Po, optional
! Name des zentralen Push-Nachrichten-Programms
string zPNP = "CCU PRG Push-Nachrichten"; ! obligatorisch
! Einwahldaten des LBoxPiZero
string login = "pi@192.xxx.xxx.xxx";
! #####################################################################
! ##### ab hier bitte keine weiteren Einstellungen mehr vornehmen #####
! #####################################################################
! +++++ Variablendeklaration +++++
string message;
! +++++ Setzen der Priorität für die Push-Nachricht +++++
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushPrio)).State("-2");
! +++++ Sound für Pushover-Nachricht +++++
if(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushoverSound)){(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushoverSound)).State("gamelan");}
! ++++ Anzeigetext für Kamera LBoxPiZero auf "geleert" setzen +++++
(dom.GetObject(ID_DATAPOINTS).Get("CUxD.CUX2801001:1.CMD_EXEC")).State("echo -n geleert | ssh "#login#" 'cat > /home/pi/RPi_Cam_Web_Interface/user_annotate.txt'");
! +++++ Erzeugen der Nachricht +++++
message = "<font color=yellowgreen>Briefkasten geleert.</font>";
! +++++ zPNP ausführen +++++
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushText)).State(message);
(dom.GetObject(ID_PROGRAMS).Get(zPNP)).ProgramExecute();
Und schließlich das dritte Skript, das beim Nachhausekommen daran erinnern soll, den Briefkasten zu leeren, wenn sich Post darin befindet.
Code: Alles auswählen
! Meldung Briefkasten leeren
! Version 1.0, Autor: dtp
! Namen der verwendeten Systemvariablen
string svPushText = "CCU SV Push Text"; ! gem. zPNS-xx, obligatorisch
string svPushPrio = "CCU SV Push Prio"; ! gem. zPNS-xx, obligatorisch
string svMailCount = "EG Briefkasten SV Einwürfe"; ! Anzahl der Einwürfe, obligatorisch
string svPushoverSound = "CCU SV Pushover Sound"; ! gem. zPNS-Po, optional
! Name des zentralen Push-Nachrichten-Programms
string zPNP = "CCU PRG Push-Nachrichten"; ! obligatorisch
! #####################################################################
! ##### ab hier bitte keine weiteren Einstellungen mehr vornehmen #####
! #####################################################################
! +++++ Variablendeklaration +++++
string message;
integer inserts;
object svObject; object svObjectList;
! +++++ Systemvariablen erzeugen bzw. falls vorhanden, auslesen +++++
if(!svMailCount){svMailCount = "EG Briefkasten SV Einwürfe";}
svObject = dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount);
if(!svObject){
svObjectList = dom.GetObject(ID_SYSTEM_VARIABLES); svObject = dom.CreateObject(OT_VARDP); svObjectList.Add(svObject.ID());
svObject.Name(svMailCount); svObject.DPInfo("Anzahl der Briefkasteneinwürfe"); svObject.Internal(false); svObject.Visible(true);
svObject.ValueType(ivtFloat); svObject.ValueSubType(istGeneric); svObject.ValueUnit(""); svObject.ValueMin(0); svObject.ValueMax(65000); dom.RTUpdate(true);
}
! +++++ Setzen der Priorität für die Push-Nachricht +++++
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushPrio)).State("0");
! +++++ Sound für Pushover-Nachricht +++++
if(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushoverSound)){(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushoverSound)).State("intermission");}
! +++++ Anzahl Einwürfe +++++
inserts = (dom.GetObject(ID_SYSTEM_VARIABLES).Get(svMailCount)).Value().ToInteger();
! +++++ Erzeugen der Nachricht und Einwürfe in Datei auf LBoxPiZero schreiben +++++
message = "<font color=royalblue>Briefkasten leeren!\n</font> ";
if(inserts == 1){message = message#"1 Einwurf.";}
elseif(inserts > 1){message = message#inserts#" Einwürfe.";}
! +++++ zPNP ausführen +++++
(dom.GetObject(ID_SYSTEM_VARIABLES).Get(svPushText)).State(message);
(dom.GetObject(ID_PROGRAMS).Get(zPNP)).ProgramExecute();
Empfang der Push-Nachrichten
Die per Pushover gesendeten und auf dem iPhone empfangenen Nachrichten sehen dann so aus:
Mit Telegram geht es aber genau so. Hier mal ein Screenshot der Telegram App unter Windows 10:
Update des RPi_Cam_Web_Interfaces
Zum Updaten des RPi_Cam_Web_Interfaces zunächst einfach die folgenden Schritte durchführen und die dann erscheinenden Fenster jeweils mit OK bestätigten.
Im Anschluss daran muss die Datei "user_annotate.txt" im Verzeichnis "/dev/shm/mjpeg" mit
noch wieder so umkonfiguriert werden, dass der Eintrag
in
Code: Alles auswählen
user_annotate /home/pi/RPi_Cam_Web_Interface/user_annotate.txt
geändert wird. Dies ist leider nach jedem Update notwendig, da "user_annotate.txt" immer mit den Standardwerten überschrieben wird. Danach den Raspi mit
zur Übernahme der Änderungen neu starten.
Bis dann,
Thorsten