Webcam mit Bewegungserkennung am Raspberry mit „motion“

Das motion paket nutzt eine USB Webcam am raspberry und schreibt geänderte Bilder in ein Verzeichnis. Später sollen die Bilder per PHP Script über den Webserver einsehbar sein.

Motion installieren

Paket motion installieren und Backup des Config-Files:

[sourcecode language=“plain“]sudo apt-get install motion
sudo cp /etc/motion/motion.conf /etc/motion/motion.conf.bak[/sourcecode]

Verzeichnis erstellen, wo die Bilder abgelegt werden (wenn nicht Standard). Das Verzeichnis sollte beim Raspberry auf einen USB-Stick ausgelagert werden wg. vieler Schreibzugriffe (Siehe USB Stick mit Raspberry)

[sourcecode language=“plain“]sudo mkdir /var/www/motion
sudo mkdir /var/www/motion/cams
sudo mkdir /var/www/motion/cam1
sudo mkdir /var/www/motion/cam1/tmb[/sourcecode]

Gemeinsame Berechtigungen für motion und den webserver

Möchten wir auf die Bilddatein vom PHP Script oder anderweitig vom Webserver zugreifen, müssen die korrekten Berechtigungen gesetzt werden und die Gruppenmitgliedschaft angepasst werden:

[sourcecode language=“plain“]sudo groupadd www
sudo usermod -a -G www www-data
sudo usermod -a -G www motion
[/sourcecode]

PHP Script für Webcam Bilder anzeige

Das Script gibt es hier für Euch kostenlos zum Download.

Die Dateien nach /var/www/motion kopieren (zb. mit WinSCP kopieren oder mit wget direkt runterladen und entzipppen).

Evlt noch Berechtigungen setzen:

[sourcecode language=“plain“]sudo chown -R www-data:www /var/www/motion/*[/sourcecode]

Dann noch das Wartungs-Script ausführbar machen

[sourcecode language=“plain“]sudo chmod +x /var/www/motion/jobdo.php
sudo chown www-data:www /var/www/motion/jobdo.php[/sourcecode]

Default ACL und Berechtigungen für neue Bilder müssen gesetzt werden. Dies geschieht mit den erweiterten Berechtigungen an den Ordnern:

[sourcecode language=“plain“]
sudo chmod g+s /var/www/motion/cams/cam1
sudo setfacl -d -m g:www:rw /var/www/motion/cams/cam1
sudo chown motion:www /var/www/motion/cams/cam1/*
sudo chmod www-data:www /var/www/motion/cams/cam1/*
sudo chmod u+w,g+rw,o+r /var/www/motion/cams/cam1/*
[/sourcecode]

motion.conf anpassen

[sourcecode language=“plain“]sudo nano /etc/motion/motion.conf[/sourcecode]

Geänderte Werte:

[sourcecode language=“plain“]daemon on
framerate 2
minimum _frame_time 2
threshold 1500
ffmpeg_cap_new off
target_dir /var/www/motion/cams/cam1
webcam_quality 50
on_event_start /var/www/motion/jobdo.php "%v-%Y%m%d%H%M%S"
on_event_end /var/www/motion/jobdo.php[/sourcecode]

nun nur noch motion und den apache neu starten:

[sourcecode language=“plain“]sudo /etc/init.d/motion restart
sudo /etc/init.d/apache2 restart[/sourcecode]

Raspberry mit USB Surfstick (3G / 2G) dauerhaft ins Internet

Um den Raspberry dauerhaft (nicht im LAN ) mit dem Internet zu verbinden konnte ich mit dem Huawei E303 Stick ein gutes Ergebnis erzielen:

Huawei E303 brauchte bei mir nicht mit usb_modeswitch in den richtigen Modus versetzt werden. Wurde sofort korrekt erkannt!

USB Geräte anzeigen mit lsusb:

[sourcecode language=“plain“]lsusb[/sourcecode]

Dieser klinkt sich als eth1 ein und kann mit ifconfig geprüft werden:

[sourcecode language=“plain“]ifconfig[/sourcecode]

Dieses Netzwerinterface sollte noch konfiguriert werden

[sourcecode language=“plain“]sudo nano /etc/network/interfaces[/sourcecode]

Folgende Einträge hinzufügen:

[sourcecode language=“plain“]
allow-hotplug eth1
auto eth1
iface eth1 inet dhcp
[/sourcecode]

Es macht Sinn den Stick noch vorher an einem Windows PC oder auch über X über die Internetadresse: http://192.168.1.1 zu konfigurieren zb. Autoverbinden PIN eingeben etc.

Danach steht die Internetverbindung eigentlich problemlos zur Verfügung und funktioniert auch zuverlässig nach einem Stromausfall und reboot.

Raspberry USB-Stick als Speicher verwenden

Für wiederkehrende und häufige Schreibzugriffe ist die SD-Karte des PI nicht ideal.
Deshalb sollten Programme und ggf. Dinge, die wiederholt auf Platte geschrieben werden ausgelagert werden. ZBsp. Auf einen USB-Stick.

Mountpoint erstellen

[sourcecode language=“plain“]sudo mkdir /media/usb1[/sourcecode]

Mit dmesg rausfinden welches device dem USB Stick zugeorndet wurde – in der Regel sda.

USB Stick vorbereiten

[sourcecode language=“plain“]sudo fdisk /dev/sda[/sourcecode]

p eingeben für Anzeige der Partitionen. Danach löschen und neue Partition erstellen:

[sourcecode language=“plain“]
Command (m for help): d
Selected partition 1

Command (m for help): n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-7866367, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-7866367, default 7866367):
Using default value 7866367

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
[/sourcecode]

Partition formatieren

[sourcecode language=“plain“]sudo mkfs.ext4 /dev/sda1[/sourcecode]

Mounten

[sourcecode language=“plain“]sudo mount /dev/sda1 /media/usb1[/sourcecode]

Dauerhaft mounten in der fstab

[sourcecode language=“plain“]sudo /etc/fstab[/sourcecode]

Inhalt einfügen:

[sourcecode language=“plain“]/dev/sda1 /media/usb1 ext4 defaults 0 2[/sourcecode]

Dateien verschieben oder kopieren

Bsp. www
Kopieren des alten Verzeichnisses auf SD-Karte

[sourcecode language=“plain“]sudo cp -pvr /var/www/* ./media/usb1/www/[/sourcecode]

Umbenennen des alten www Verzeichnisses und symbolischen Link erstellen

[sourcecode language=“plain“]sudo mv /var/www /var/www_old
sudo ln -s /media/usb1/www /var/www[/sourcecode]

 

Eine Raspberry Grundinstallation mit PHP und Apache

Raspbian installieren auf SD-Karte 

Downloads

Image schreiben mit http://sourceforge.net/projects/win32diskimager/ (Achtung unter Admin Ausführen!)

Pakete Aktualisieren

Auf den Raspberry connecten und dann erstmal Pakete aktualisieren:

[sourcecode language=“plain“]sudo apt-get update
sudo apt-get upgrade[/sourcecode]

Pakete Nachinstallieren

 

[sourcecode language=“plain“]
sudo apt-get install php5 acl[/sourcecode]

Bei Dauerbetrieb Zugriffe auf SD-Karte reduzieren

Log und Temp Dateien in den Memory auslagern:

[sourcecode language=“plain“]
sudo nano /etc/fstab[/sourcecode]

Folgendes in der fstab ändern bzw. hinzufügen:

[sourcecode language=“plain“]
none /var/run tmpfs size=5M,noatime 00
none /var/log tmpfs size=5M,noatime 00[/sourcecode]

Evtl Swapping deaktivieren, aber nur wenn genügend Speicher zur Verfügung steht:

[sourcecode language=“plain“]sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove[/sourcecode]

Freien Speicher kann man auch so anzeigen:

[sourcecode language=“plain“]free -m
[/sourcecode]

-m zeigt die Daten in Megabyte an -k in Kilobyte

Apache2 anpassen

Achtung: Apache läuft nicht, wenn das Log-Directory temporär ist, da apache den Ordner /var/log/apache2 erwartet. Dieser ist beim Start mit dieser Variante nicht mehr vorhanden.
Umgehen kann man das indem man den Ordner beim Starten anlegt.

Die schnellste aber auch nicht ganz saubere Methode ist das apache2 startupscript zu modifizieren:

[sourcecode language=“plain“]sudo nano /etc/init.d/apache2
[/sourcecode]

Direkt nach den Header Kommentaren folgende Zeile einfügen:

[sourcecode language=“plain“]mkdir /var/log/apache2
[/sourcecode]

 

Raspberry Watchdog

Der Raspberry verfügt über einen internen Watchdog um ggf. bei Überlast etc. zu rebooten.

Installation

Prüfen ob modul vorhanden, dann automatisch laden und watchdog installieren:

[sourcecode language=“plain“]sudo modprobe bcm2708_wdog
echo "bcm2708_wdog" | sudo tee -a /etc/modules
sudo apt-get install watchdog[/sourcecode]

Configurationsfile anpassen

[sourcecode language=“plain“]sudo nano /etc/watchdog.conf[/sourcecode]

folgendes anpassen:

[sourcecode language=“plain“]watchdog-device = /dev/watchdog

max-load-1 = 24[/sourcecode]

Watchdog nun noch starten

[sourcecode language=“plain“]sudo /etc/init.d/watchdog start[/sourcecode]

Dieser Daemon sendet nun in regelmäßigen Abständen ein Signal an den verbauten Watchdog-Chip. Sollte dieser für eine gewisse Zeit kein Signal mehr vom Software Wachhund bekommen, rebootet er automatisch das System.

Weitere Möglichkeiten sind im man beschrieben und können nach Bedarf erweitert und angepasst werden.

mehr hier:

http://www.gieseke-buch.de/raspberrypi/eingebauten-hardware-watchdog-zur-ueberwachung-nutzen

 

Raspberry Reverse SSH Tunnel

Wird der Raspberry zum Beispiel mit einem Surfstick oder hinter einer Firewall betrieben und möchte man remote auf diesen per SSH oder mit anderen Diensten zugreifen gibt es die Möglichkeit vom Raspberry sich mit einem anderen SSH Server zu verbinden und bestimmte Ports zu tunneln.

Für den SSH Server kann man entweder einen eigenen Raspberry nutzen oder auch zb. Windows Home Server mit BITVISE SSH Server.

AutoSSH

Autossh wird dazu verwendet, die SSH Verbindung immer wieder automatisch herzustellen, wenn sie unterbrochen wurde.

[sourcecode language=“plain“]sudo apt-get install autossh[/sourcecode]

Keypairs erstellen

Auf dem Remote RPI Keys generieren (angemeldeter user : pi)

[sourcecode language=“plain“]cd ~
ssh-keygen -t rsa[/sourcecode]

Public Key auf den Server kopieren und dort installieren bei Windows BitVise SSH Server mit WINSCP übertragen. Ansonsten kann man das auch mit linux mitteln druchführen. (Vorher muss natürlich auf dem Server ein entsprechender User eingerichtet werden)

[sourcecode language=“plain“]ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote-system[/sourcecode]

SSH Test-Verbindung testen

Port (-p) ggf anpassen oder bei Defaultbetrieb weglassen.

[sourcecode language=“plain“]ssh -p443 user@remote-system[/sourcecode]

Login sollte nun automatisch funktionieren.
SSH mit Remote Port forwarding testen:

[sourcecode language=“plain“]ssh -p443 -fNC -R 10022:localhost:22 user@remote-system[/sourcecode]

Komplexe Variante mit folgenden Ports:

[sourcecode language=“plain“]ssh -p443 -fNC -R 11022:localhost:22 -R 11080:localhost:80 -L 18080:localhost:8080 user@remote-system[/sourcecode]

Erklärung:

  • Remote Port 11022 wird zu lokal Raspberry 22 (SSH) geforwardet
  • Remote Port 11080 wird zu lokal Raspberry 80 (HTTP) geforwardet
  • Und vom Raspberry möchten wir Daten an den Server schicken
    Lokaler Port 18080 wird an den Remote Port 8080 geforwardet (HTTP IPS)

Auto SSH Setup

autoSSH baut die verbindungen automatisch wieder auf (Achtung Traffic)

[sourcecode language=“plain“]autossh -p443 -fNC -R 11022:localhost:22 -R 11080:localhost:80 -L 18080:localhost:8080 user@remote-system[/sourcecode]

autoSSH muss aber bei jedem Start geladen werden – hinzu kommt, dass die Key – Dateien beim PI User liegen.

Einfache Lösung wie folgt mit der Crontab des PI Users, dazu ein Startscript schreiben und das in die crontab des pi users eintragen:

[sourcecode language=“plain“]nano ~/autossh_start[/sourcecode]

Folgender Inhalt in autossh_start

[sourcecode language=“plain“]#!/bin/bash
killall ssh
autossh -p443 -fNC -R 11022:localhost:22 -R 11080:localhost:80 -L 18080:localhost:8080 user@remote-system[/sourcecode]

Das Script noch ausführbar machen:

[sourcecode language=“plain“]chmod u+x ~/autossh_start[/sourcecode]

Crontab schreiben:

[sourcecode language=“plain“]crontab -e -u pi[/sourcecode]

Am Ende eintragen:

[sourcecode language=“plain“]@reboot ~/autossh_start[/sourcecode]

Test ob auch in ctrontab drin:

[sourcecode language=“plain“]crontab -l -u pi[/sourcecode]


 

AvisCam / Mikrokopter / CHDK USB Auslöseskript

Mittels CHDK kann man die Canon Kameras gut programmieren. Für AvisCam und USB Auslösung benutze ich folgendes Script mit automatischer Berechnungsfunktion.
Die Verschlusszeit wird vorgegeben und die ISO-Werte werden entsprechend berechnet.

@title AvisCam USB Shutter
@param q Shutter 1st Shot
 @default q 1
 @values q 1/100 1/200 1/400 1/640 1/800 1/1000

@param p Shutter 2nd Shot
 @default p 1
 @values p 1/100 1/200 1/400 1/640 1/800 1/1000

@param f AutofocusLock
 @default f 1
 @values f off on
 
@param w Pic Delay (sec)
 @default w 2
 
@param r Raw Mode
 @default r 0
 @values r off on

rem Defaults - Kameraabhängig - Tabelle benutzen
rem Minium ISO = 80
n = 371
rem Maximum ISO = 3200
x = 891

print "Set focus unendlich"
set_focus 65535
sleep 500
print "Set AF lock"
set_aflock f
sleep 500

rem ND Filter ausschalten
print "ND Filter ausschalten"
set_nd_filter 2
sleep 200

rem Raw mode setzen
print "Set Raw Mode"
set_raw r

sleep 1000 
w = w * 1000
print "Start!"

:eval
c = 0
while 1
 p = get_usb_power 1
 if p > 0 then
 c = c + 1
 rem Shoot Foto now
 rem 1. Messen
 gosub "meter"
 
 rem 2. Verschlusszeit festlegen
 v = q
 gosub "gettv96"
 rem 3. Belichtung ausrechnen
 gosub "exposure"
 rem 4. Knipsen
 
 click "shoot_full"
 print "Shot TV1 #", c, S , T 
 rem 2. Foto wenn untersch. Bel. Zeiten
 if q <> p then
 sleep 1000
 rem 2. Verschlusszeit festlegen
 v = p
 gosub "gettv96"
 rem 3. Belichtung ausrechnen
 gosub "exposure"
 rem 4. Knipsen
 print "Shot TV2 #", c, S, T
 click "shoot_full"
 endif
 rem Zwangspause lt. Parameter
 sleep w
 endif
wend

rem Bild messen
:meter
 press "shoot_half"
 while get_shooting = false
 sleep 10
 wend
 A = get_av96
 B = get_bv96
 return


rem Belichtung (ISO berechnen) 
:exposure
 S = t + A - B
 rem Limit minimum Sv
 if S<n then let S=n
 rem Limit maximum Sv
 if S>x then let S=x
 
 rem Tv anpassen falls außerhalb der limits
 if S <> A + t - B then let T = B + S - A else let T = t
 set_tv96_direct T
 set_sv96 S
 sleep 200
 return
 
rem Umwandlung verschlusszeit in werte
:gettv96
 if v = 0 then let t=640
 if v = 1 then let t=736
 if v = 2 then let t=832
 if v = 3 then let t=896 
 if v = 4 then let t=928
 if v = 5 then let t=960
return

Raspberry GPIOs mit PHP schalten

Die einfachste Methode ist die, dass wir dem www-data User (unter welchem der Apache und auch die PHP Skripte laufen in die GPIO gruppe aufnehmen. Dabei ist zu beachten, dass dies ggf. ein Sicherheitsrisiko darstellt.

[sourcecode language=“plain“]sudo usermod -aG gpio www-data
sudo usermod -aG gpio pi
sudo /etc/init.d/apache2 restart[/sourcecode]

PHP Beispiel für REST mit Json response

[sourcecode language=“php“]<?php
// Valid GPIOS
$C["GPIOS"] = Array(17,22);

$mode = @$_GET["mode"];
switch($mode){
case "SWGPIO": $on = intval(@$_GET["on"]);
$id = intval(@$_GET["id"]);
SwitchGPIO($id, $on);
break;

case "GETGPIO": $id = intval(@$_GET["id"]);
GetGPIO($id);
break;
}

function GetGPIO($id){
global $C;
if(!in_array($id, $C["GPIOS"])){
Status(false, "GPIO $id not allowed.");
}
if(!is_dir("/sys/class/gpio/gpio$id/")){
Status(false,"GPIO $id not active.");
}
$fn = "/sys/class/gpio/gpio$id/value";
if(!file_exists($fn)){
Status(false, "GPIO $id Valuefile does not exist.");
}
$val = trim(file_get_contents($fn));
Status(true,$val);
}
function SwitchGPIO($id, $on){
// Vorher beim Booten Berechtigungen setzen!
// sudo usermod -aG sudo usermod -aG gpio www-data

global $C;
if(!in_array($id, $C["GPIOS"])){
Status(false, "GPIO $id not allowed.");
}
if(!in_array($on, Array(0,1))){
Status(false, "GPIO status $on not allowed.");
}
// check if GPIO is open
if(!is_dir("/sys/class/gpio/gpio$id/")){
file_put_contents("/sys/class/gpio/export",$id);
sleep(1);
file_put_contents("/sys/class/gpio/gpio$id/direction","out");
}
if(!is_dir("/sys/class/gpio/gpio$id/")){
Status(false,"Cannot access GPIO $id");
}

// Set correct status
$fn = ‚/sys/class/gpio/gpio‘.$id.’/value‘;
$val = file_get_contents($fn);
if($val == $on){
Status(true, "Switch status already $on");
}
file_put_contents($fn,$on);
usleep(250000);
// Check status
$val = file_get_contents($fn);
if($val == $on){
Status(true, "Switch status now: $on");
} else {
Status(false, "Switch status wrong");
}
}

Status(false,"Wrong Parameters");

function Status($stat, $txt){
$ret["STATUS"] = ($stat)? "OK" : "ERROR";
$ret["MSG"] = $txt;
echo json_encode ($ret);
die;
}

function warning_handler($errno, $errstr) {
echo $errno;
return false;
}
?>
[/sourcecode]

GPIOs sollten jedoch bereits beim Neustart des Raspberry initialisiert werden
dazu ein Script anlegen und ggf. anpassen: im pi home:

[sourcecode language=“plain“]nano ~/init_gpio[/sourcecode]

Inhalt:

[sourcecode language=“plain“]#!/bin/bash

#Init GPIOS on Startup with Script
#Ohne SUDO gehen die Befehle nur wenn pi Mitglied der Gruppe gpio ist.
echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction
echo "0" > /sys/class/gpio/gpio17/value[/sourcecode]

Script Berechtigungen:

[sourcecode language=“plain“]sudo chmod u+x ~/init_gpio[/sourcecode]

Autostart mit der crontab des pi

[sourcecode language=“plain“]crontab -e -u pi[/sourcecode]

letzte Zeile anfügen:

[sourcecode language=“plain“]@reboot ~/init_gpio[/sourcecode]

Prüfen ob alles OK:

[sourcecode language=“plain“]crontab -l -u pi[/sourcecode]