Es ist mal wieder Zeit für ein kleines Urlaubsprojekt.
Hier lag seit 3 Jahren, neben einem RaspberryPi und nem alten 17″ Eizo-Screen, so ein Wandhalter für TFT-Screens herum. Da kann man doch was raus machen.
Also fix den Wandhalter an die Wand gedübelt und den Pi mit NFS-Root (siehe Eintrag hier) aufgesetzt.
Der Pi selbst ist mit dem Cam-Modul ausgestattet, und hängt per HDMI 2 DVI an dem o.g. Eizo.
Folgende Ziele habe ich verfolgt (und umgesetzt):
– Autologin nach reboot, sowie automatisches einloggen auf nem Server und attachen an tmux
– Sobald sich was vor der Cam bewegt, soll der Monitor “aufwachen”, nach 60s. wieder ausgehen.
Ist an sich recht einfach. Fangen wir mal mit dem Autologin an:
via /etc/inittab sagen wir dem Pi, dass er sich – anstelle des logins – auf dem tty1 als “pi” einloggen soll:
#1:2345:respawn:/sbin/getty --noclear 38400 tty1
1:2345:respawn:/bin/login -f pi tty1 /dev/tty1 2>&1
Dazu die obere Zeile auskommentieren, und die untere einfügen.
Nach einem reboot sollte der pi nun direkt auf der Shell als User “pi” landen.
Alles weitere (ssh-login) und Co. machen wir in der ~pi/.bashrc (letzte Zeile einfach anfügen)
ssh -t [user]@[machine wo tmux rennt] "tmux att"
Nun sollte nach dem Reboot (ssh-keys und laufender tmux auf “machine” vorrausgesetzt) direkt der tmux erscheinen. Den kann man dann vom “normalen” Rechner aus mit content bestücken (top, iftop, tail aufs log, etc.)
Wer noch Hintergrundbild und höhere Auflösung auf dem pi haben möchte, dem seit fbterm ans Herz gelegt.
Weiter gehts mit der “Motiondetection”. Dazu habe ich mir erstmal ein kleines Shellscript gebaut, welches den Monitor an/ausschalten kann, und dieses unter /usr/bin/screen.sh abgelegt:
#!/bin/bash
tvstat=$(tvservice -s |grep off)
if [[ $tvstat == *off* ]]; then
TV=OFF
else
TV=ON
fi
if [ "$1" == 'on' ] && [ "$TV" == "OFF" ]; then
/usr/bin/tvservice -p;
#fbset -depth 8;
#fbset -depth 16;
chvt 2;
sleep 1
chvt 1;
chvt 2;
chvt 1;
#echo 'Switched Screen ON!'
fi
if [ "$1" == 'off' ] && [ "$TV" == "ON" ]; then
/usr/bin/tvservice -o
echo 'Switched Screen OFF!'
fi
Nicht von den chvt verwirren lassen. mit tvservice wird der Monitor an/ausgeschaltet, mit chvt auf das entsprechende (Virtuelle) Terminal umgeschaltet. Quasi das Shell-pendant zu “ALT-F1 bis ALT-F10” zum Console wechseln. Ohne das hin- und herschalten via chvt geht der Moni zwar an, aber es wird nichts angezeigt.
Die eigentlich Motiondetection ist in Python gebastelt (wie üblich: Kurz und schmutzig):
#!/usr/bin/python
import StringIO
import subprocess
import os
import time
from datetime import datetime
from PIL import Image
threshold = 10
sensitivity = 180
monitor='on'
# Capture a small test image (for motion detection)
def captureTestImage():
command = "raspistill -n -w %s -h %s -t 1 -e bmp -o -" % (100, 75)
imageData = StringIO.StringIO()
imageData.write(subprocess.check_output(command, shell=True))
imageData.seek(0)
im = Image.open(imageData)
buffer = im.load()
imageData.close()
return im, buffer
def turnMonitorOn():
global monitor
monitor='on'
subprocess.call("/usr/bin/screen.sh on", shell=True)
def turnMonitorOff():
global monitor
monitor='off'
subprocess.call("/usr/bin/screen.sh off", shell=True)
# Get first image
image1, buffer1 = captureTestImage()
# Reset last capture time
lastCapture = time.time()
# added this to give visual feedback of camera motion capture activity. Can be removed as required
while (True):
# Get comparison image
image2, buffer2 = captureTestImage()
# Count changed pixels
changedPixels = 0
for x in xrange(0, 100):
# Scan one line of image then check sensitivity for movement
for y in xrange(0, 75):
# Just check green channel as it's the highest quality channel
pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
if pixdiff > threshold:
changedPixels += 1
# Changed logic - If movement sensitivity exceeded then
# Save image and Exit before full image scan complete
if changedPixels > sensitivity:
print "change "+monitor
lastCapture = time.time()
if (monitor == 'off'):
turnMonitorOn()
break
continue
if (time.time()-lastCapture > 60):
if (monitor == 'on'):
turnMonitorOff()
# Swap comparison buffers
image1 = image2
buffer1 = buffer2
Wenn man das Ding nun laufen lässt, macht es im dauerloop ein Bild in niedriger Auflösung von der Cam, und vergleicht die Helligkeitswerte mit denen des vorherigen Pics. Ist der Unterschied grösser als “threshold”, dann macht das Script den Monitor an. Nach 60s ohne Bewegung wird er wieder ausgeschaltet.
Jetzt nur noch das Script mit “start-daemon” in ein init.d Script packen und beim booten automatisch starten, und fertig.
Wie immer gibt es zig Wege dahin, dies ist nur einer von vielen. Das ganze kann man sicher noch immens optimieren. Für hier ist es mehr als in Ordnung.