Project Description
This is my interpretation and approach to the Catch Santa project for the Catch Santa & Pi NoIR RoadTest (http://www.element14.com/community/roadTests/1220?CMP=SOM-ROADT-PINOIR-CATCHSANTA).
I divided the project in different parts:
- Installation: get everything up and running
- Detection: detect movement and log it
- Activation: Ensure the system can be (de-)activated
- Notification: notify me when movement is detected
- Visibility: the security system should be subtle and not easily noticeable
All of the above wrapped in a Christmas theme ...
Installation
First off, I started with the assembly and installation of the components provided for the RoadTest.
The kit contained following components:
- Raspberry Pi Model B + SD card with NOOBS pre-installedRaspberry Pi Model B + SD card with NOOBS pre-installed
- Pi NoIR cameraPi NoIR camera
- PiFace Control + DisplayPiFace Control + Display
- Enclosures for Pi with PiFace CADEnclosures for Pi with PiFace CAD and cameracamera
- WiPi wifi dongleWiPi wifi dongle
Hardware
The SD card, WiPi dongle and PiFace were straightforward to connect to the Raspberry Pi. The enclosure was a different story though.
There were no instructions provided on how to assemble the case for the Raspberry Pi with PiFace C&D and Camera. Even though the case consists only of two pieces, it was slightly more tricky than expected. After fiddling with the case for some minutes, I searched for instructions and found the following guide:
http://cpc.farnell.com/images/en_CC/PiFacecontrol&displayinstructions.pdf
Making use of those instructions, assembling the case went smoother.
I also had the pleasure to work with a lovely assistant: my 3,5 year old daughter.
She helped me put the different bits together. A fun introduction to electronics!
The result: a very good looking Pi!
Software
With the hardware connected, it was time to move on to the software portion of the project.
Raspbian
Using the preinstalled NOOBS SD card, getting the Pi up and running was a piece of cake:
- boot the pi with the provided NOOBS SD card
- select the desired distribution to be installed >> I chose Raspbian
- installing Raspbian took approximately 10 minutes
- after installation, the pi was rebooted and the freshly installed OS started
Once installed, Raspbian presented me with the "Raspberry Pi Software Configuration Tool". This allows to configure certain settings or perform certain actions more easily.
I have used this tool for several things:
- expand filesystem, in order to use the full size of the SD card: this is already covered automatically by the NOOBS installation
- enable the camera module
- enable SSH access
- upgrade the software to the latest version
- enable SPI (required for PiFace, option was only available after upgrading to latest version)
WiPi
Installing the WiPi to allow wireless connectivity was easy: plugged in the stick, configured the network interface and I was good to go.
I edited my /etc/network/interfaces file over the wired network via SSH as follows:
pi@santaCatcher ~ $ sudo nano /etc/network/interfaces iface wlan0 inet static address 192.168.0.150 netmask 255.255.255.0 gateway 192.168.0.1 dns-nameservers 195.130.130.2,195.130.131.130 wpa-ssid “ssid" wpa-psk “password”
I chose a fixed IP address in order to always know on exactly which IP I can reach the Pi.
Pi Camera
After enabling camera support via the "Raspberry Pi Software Configuration Tool", the camera was ready to be used.
You can find more information and detailed instructions in my Pi NoIR RoadTest review: http://www.element14.com/community/roadTestReviews/1638
PiFace CAD
I installed the necessary software dependencies and modified the appropriate configuration files to get the PiFace CAD up and running by following the instructions provided.
User guide can be found here: http://www.element14.com/community/community/raspberry-pi/raspberry-pi-accessories/controlanddesign
Implementation
This part covers my "development" done on top of the standard installation as performed in previous steps.
I have split it in the different areas involved in the project, in an attempt to keep everything clear.
Detection
In order to detect and capture Santa on film, I used the Pi NoIR in combination with the “motion” application.
This application makes use of the camera to detect movement. When movement is detected, it starts recording until all motion stopped and generates a still image of the moving object/person.
The camera stream can also be visualised remotely as a live stream, using the pi's wireless connectivity with WiPi.
There was a post on raspberrypi.org not so long ago where someone used the Pi, in combination with the camera and motion to create an affordable security system.
Instructions were clearly documented and easy to follow and can be found here: http://www.codeproject.com/Articles/665518/Raspberry-Pi-as-low-cost-HD-surveillance-camera
Using those instructions, I managed to set up motion properly. The installation and configuration were tested by accessing the live stream via http://<ip_of_pi>:8081.
Activation
Enable/Disable motion picture and movie generation
Since for this challenge the system was going to be used indoors (in the living room more precisely) and I didn't want it to keep recording and logging all day, I came up with a way of enabling/disabling the image and video output of the motion application.
Motion offers a web interface to modify the running configuration of the application. Unfortunately this didn't seem to rewrite the configuration file, meaning a restart of the application would lose the changes made.
In order to have my config changes persisted, I decided to use the "sed" command to find and replace certain patterns in the motion config file and restart the application to apply.
There are two parameters I was interested in persisting:
- output_pictures: generate a still image of the object/person moving
- ffmpeg_output_movies: generate a movie as long as there is movement
Initial config file state for relevant parameters:
pi@santaCatcher ~ $ cat /etc/motion.conf | grep -e output_pictures -e ffmpeg_output_movies output_pictures best ffmpeg_output_movies on
Then, using "sed" I search for those parameters (and respective value) and replaced them with the new value. In this case, turn off picture and movie generation:
pi@santaCatcher ~ $ sudo sed -i -e 's/output_pictures.*/output_pictures off/g' -e 's/ffmpeg_output_movies.*/ffmpeg_output_movies off/g' /etc/motion.conf
Verifying the changes have been applied:
pi@santaCatcher ~ $ cat /etc/motion.conf | grep -e output_pictures -e ffmpeg_output_movies output_pictures off ffmpeg_output_movies off
Finally, to change from off to on:
pi@santaCatcher ~ $ sudo sed -i -e 's/output_pictures.*/output_pictures best/g' -e 's/ffmpeg_output_movies.*/ffmpeg_output_movies on/g' /etc/motion.conf
Verifying the changes have been applied:
pi@santaCatcher ~ $ cat /etc/motion.conf | grep -e output_pictures -e ffmpeg_output_movies output_pictures best ffmpeg_output_movies on
LCD message
As a visual indication of the system being (de-)activated, I wanted to display a message on the PiFace's LCD screen.
I started off by using an existing example (sysinfo.py) and edited it. Following parts of the example script were most relevant to my project:
import pifacecad #piface cad library cad = pifacecad.PiFaceCAD() #create piface cad object cad.lcd.clear() #clear all text cad.lcd.write("") #write something
Script
Next, I combined the "sed" and the LCD display commands into a single script which could be called with one parameter: "on" or "off"
I'm a Python novice, so I'm not familiar with best practices and so on. There are however many tutorials to be found on the web. This is the script I came up with:
import os import sys import pifacecad from time import sleep status = sys.argv[1] cad = pifacecad.PiFaceCAD() cad.lcd.blink_off() cad.lcd.cursor_off() cad.lcd.clear() def activate(cad): cmd = "sudo sed -i -e 's/output_pictures.*/output_pictures best/g' -e 's/ffmpeg_output_movies.*/ffmpeg_output_movies on/g' /etc/motion.conf && sudo /etc/init.d/motion restart" execute(cmd) writeLcd(cad,"System\n activated !") sleep(10) clearLcd(cad) def deactivate(cad): cmd = "sudo sed -i -e 's/output_pictures.*/output_pictures off/g' -e 's/ffmpeg_output_movies.*/ffmpeg_output_movies off/g' /etc/motion.conf && sudo /etc/init.d/motion restart" execute(cmd) writeLcd(cad,"System\n deactivated !") sleep(10) clearLcd(cad) def execute(cmd): os.system(cmd) def writeLcd(cad,msg): cad.lcd.backlight_on() cad.lcd.write(msg) def clearLcd(cad): cad.lcd.clear() cad.lcd.backlight_off() if status == "on": print "Activating" activate(cad) elif status == "off": print "Deactivating" deactivate(cad) else: print "Invalid value"
Remote (de-)activation
As I planned on hiding the setup somewhere subtle and perhaps not easily accessible, the (de-)activation should be possible remotely (without the need for a computer).
The IR receiver of the PiFace came in handy for that purpose: using the TV's remote control I wanted to trigger the script above by entering a specific key combination.
The documentation of the PiFace CAD provides instructions on how to setup a remote to interface with it.
Using the link provided in the instructions, I was able to find a configuration file for the remote I was planning to use.
I downloaded the config, renamed and moved it to the correct location:
pi@santaCatcher ~ $ wget http://lirc.sourceforge.net/remotes/telenet/DB-AD110 pi@santaCatcher ~ $ sudo cp DB-AD110 /etc/lirc/lircd.conf
By running the “irw” application, I tested the numeric buttons to verify the mapping.
The button presses were properly detected, but sometimes resulted in repeated values (pressing KEY_1 once would trigger two events):
000000000000001b 00 KEY_1 Telenet_DB-AD110 000000000000001c 00 KEY_2 Telenet_DB-AD110 000000000000001c 01 KEY_2 Telenet_DB-AD110 000000000000001d 00 KEY_3 Telenet_DB-AD110 000000000000001e 00 KEY_4 Telenet_DB-AD110 000000000000001f 00 KEY_5 Telenet_DB-AD110 000000000000001f 01 KEY_5 Telenet_DB-AD110 0000000000000020 00 KEY_6 Telenet_DB-AD110 0000000000000020 01 KEY_6 Telenet_DB-AD110 0000000000000021 00 KEY_7 Telenet_DB-AD110 0000000000000022 00 KEY_8 Telenet_DB-AD110 0000000000000023 00 KEY_9 Telenet_DB-AD110 0000000000000023 01 KEY_9 Telenet_DB-AD110 0000000000000024 00 KEY_0 Telenet_DB-AD110
I then created a lircrc config file meant to listen for specific keys or key combinations and trigger an action depending on the combination.
My config is as follows:
pi@santaCatcher ~ $ nano ~/.lircrc begin prog = irexec button = KEY_1 button = KEY_2 button = KEY_3 button = KEY_5 button = KEY_6 config = sudo python /home/pi/santaCatcher.py on repeat = 0 end begin prog = irexec button = KEY_1 button = KEY_2 button = KEY_3 button = KEY_6 button = KEY_5 config = sudo python /home/pi/santaCatcher.py off repeat = 0 end
Specifying the "button" parameter multiple times allows to check for combinations. In above config it checks for following combinations: "12356" and "12365"
Sometimes key presses result in duplicate values (pressing the "1" button could result in a "11" being received. To ignore duplicates, the "repeat = 0" is used.
To be able to listen, the "irexec" application should be running. To ensure this is done at startup, I added an entry to "/etc/rc.local" to do just that:
pi@santaCatcher ~ $ sudo nano /etc/rc.local #!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. sudo -u pi irexec -d exit 0
After these changes, I was able to remotely configure the "motion" application to generate pictures and movies or not.
Demo
The different elements of the "activation" part of the project can be witnessed below:
Santa Catcher - Remote activation
Santa Catcher - Remote deactivation
Notification
I split the notification into following parts:
- offer content via webserver
- periodic checks for new content
- send email (via gmail) with links to new content
Webserver
Offering the media files generated by "motion" via a webserver is straightforward.
I started by installing apache webserver:
pi@santaCatcher ~ $ sudo apt-get install apache2
Once installed, I linked the media folder where "motion" stores the media files to the a folder on the webserver by using a symbolic link:
pi@santaCatcher ~ $ sudo ln -s /path_to_media_files/ /var/www/media
The files were then accessible by browsing to http://<ip_of_pi>/media
Check new media
In order to notify me of new content generated by motion and available on the webserver, I had to check for new content first.
pi@santaCatcher ~ $ find /path_to_media_files -type f -mmin -5 | grep -e "avi" -e “jpg"
Above command returns a list of “jpg" and/or “avi" files which have been modified in the last 5 minutes.
Script
To allow easy execution of the different checks and the email notification, I created another Python script which:
- check for new media content
- if new content is available, generate an email with links to media on webserver.
The script:
pi@santaCatcher ~ $ sudo nano santaCatcherNotifier.py import subprocess import re import smtplib from email.MIMEText import MIMEText def sendMail(): gmail_user = "sender@gmail.com" gmail_pwd = "password" FROM = 'sender@gmail.com' TO = ['recipient@mailprovider.com'] SUBJECT = "SantaCatcher: Movement detected" TEXT = "SantaCatcher detected movement. Evidence below:\n\n" + content # Prepare actual message message = """\From: %s\nTo: %s\nSubject: %s\n\n%s""" % (FROM, ", ".join(TO), SUBJECT, TEXT) try: #server = smtplib.SMTP(SERVER) server = smtplib.SMTP("smtp.gmail.com", 587) server.ehlo() server.starttls() server.login(gmail_user, gmail_pwd) server.sendmail(FROM, TO, message) #server.quit() server.close() print 'successfully sent the mail' except: print "failed to send mail" content = "" cmd = subprocess.Popen('find /tmp -type f -mmin -5 | grep -e avi -e jpg', shell=True, stdout=subprocess.PIPE) for line in cmd.stdout: line = re.sub('/tmp/','http://192.168.0.150/media/',line) content = content + line if content != "": sendMail()
The code to send an email via gmail in Python was found here: http://stackoverflow.com/a/12424439
Periodic check
Above script needs to be executed to trigger the new media check and possible mail notification.
This was tackled with a cron job which executes the script at regular intervals. In my case I aligned the new media check and the cron job to a 5 minute interval.
pi@santaCatcher ~ $ crontab -e # m h dom mon dow command */5 * * * * python /home/pi/santaCatcherNotifier.py
The expression can easily be modified to check at different intervals.
Demo
Having all notification elements in place, a small test was in order. The output mail looks like this:
Visibility
The best place to hide my Santa Catcher was the Christmas tree itself, as that is the place Santa is heading for.
As I cannot just throw the Pi and camera in the tree, I created some ornaments and had my daughter decorate them. This was a fun and creative way of involving her in the project.
Drew the shape on some pieces of wood.
Cut out the shapes, ready for painting and decoration.
Artist at work.
Painting: done.
Massacred the wood when cutting and drilling ...
The decorated result.
End result with Pi installed at the back.
Can you spot the Pi ?
With everything ready, it was just a matter of patience and not forgetting to activate the system before going to bed on Christmas eve.
Caught ... something
The system worked, and it triggered a notification. The only thing is, we didn't seem to have gotten Santa on film.
Instead, all we got is what appears to be one of Santa's little helpers sneaking in our living room, heading towards the Christmas tree.
This is the evidence (captured using Pi NoIR & motion):
The curtain is opening, triggering "motion" to start recording
Santa Catcher - Little helper caught on film
Top Comments