Introduction: Raspberry PI Camera and Light Control Death Star

About: Never stops thinking.

As always I looking to build devices which are useful, work robustly and often are even improvements compared to the current off the shelf solutions.


Here is yet another great project, originally named Shadow 0f Phoenix, a Raspberry PI shield in conjunction with Arduino based motion detection and light controls.

Step 1: The State of Commercial IP Cameras

Besides that building your own camera/surveillance system is more cool let's see why is this an improvement from an off the shelf solution.

I will compare it with the NEO COOLCAM Full HD 1080P Wireless IP Camera series since I have owned a lot of these various models of neo coolcams (ONVIF) cameras. They come in different shapes and sizes, outdoors and indoors, most of them have built in wifi support but let's see their caveats:

  • Chinese manufacturers who sell these cameras almost always lie about the built in image sensor resolution, when you buy a 5MP/8MP camera on Ebay you might end up with a cheap 2MP camera with bad picture (it works but the quality is garbage). When you buy the 8MP Raspberry PI v2 camera from the original retailer you will get what you paid for and actual 8MP sensor with the resolution 3280 × 2464 pixels => https://www.raspberrypi.org/documentation/hardwar...
  • From security standpoint these cameras (even the more expensive Dlink and other models) are terrible, they use default passwords such as 123456 or built in users such as admin/admin operator/operator what you might won't even be able to change or the change is gone after a reboot. Top it off with many of these cameras phone home (connect to their servers in china, some even streams back video/pictures without asking you just to make it easier in case you decide to install their Android/Iphone app one day to check on your home). Even if you put these devices behind a router it is just not good enough, the best is if you don't set a default gateway in them, firewall them out or put them into a VLAN to make it impossible for them to go out to the Internet or even better: don't use them at all.
  • Are they more reliable? nope, a lot of them even the more expensive DLINKs have the option to reboot the camera daily/weekly etc. That option is there for a reason, because after X days they often lose Wifi connectivity or misbehave on other ways. Just think of them as good old Win95 boxes which needed to be rebooted more often than not :) I don't say that the Raspi based hardware are so rock solid that you can build them into control nuclear power plants but with proper hardware/software configuration, heatsinks, automatic cooling fans and minimized RW operation on the SDCARD they can easily hit that 100+ days uptime without problem. At the time of writing my DeathStar runs since 34 days, been over 100 but sometimes I was hacking on the feed in power source which is powering some other of my circuits so had to shut it down :(
  • Targeted hardware: they are made for 1 specific purpose, often come with a small nvram area and busybox but some models make the access of this shell impossible as well so all you can use them for is what they meant to be used for while you can use your Raspi based camera to whatever other tasks: file server, tftp/dhcp server, web server, quake server... the options are unlimited.
  • Storage space: they either have none or they use microsd cards with FAT32 filesystem VS on the raspberry pis you can even attach a 2 TB hard drive if you like.
  • Controlling lights: some does have an ALARM output where you might be able to connect a small relay to have lights triggered. As I will show you in this tutorial using infrared cameras are complete waste of time since you will not be able to identify anyone on the IR pictures due to the bad quality. If you need to record a video in the dark the best way to do so is turn on some light first then record the video.

So you might ask are there any PROs of using an off the shelf camera? Yes for businesses where the work hours to set it up would be more expensive than tinkering around with Raspberry pis (not for me anyway :)) and yes there are top of the line cameras (500$+ with better resolution than the pi camera of course). As another advantage I could say that the cameras following the ONVIF standard made centralized provisioning easier. This provides a standard interface what can be used to send commands to the camera to set it's IP/Network mask/Gateway and other things. For this you could download the Onvif device manager from Sourceforge. A lot of these devices come with crappy broken web frontends where for example it does not allow you to set the ip or netmask correctly because the javascript which validates these fields is malfunctioning and your only way to set these parameters correctly is through ONVIF.

Step 2: Plans of the Death Star

You can build this device with any of the Raspberry PIs starting from 1 to 3B+. Even the zero has camera ports, but since there are so many different second hand raspis are on the market you might be wondering which is the most ideal for this build.


The answer depends on where do you want to process the video stream at.

There are two choices:

1, Process the videos locally with motion and forward a video stream when there is motion detected (note: motion forwards a slow constant stream to the server no matter what, this can be depending on the resolution and frame rates you use going from couple of hundred megabytes to multiple gigabytes a day, just a reminder if you want to do a setup on a metered connection). Here the CPU matters and unfortunately motion (at the time of writing) does not take advantage of multiple cores, however the OS will try to balance the load slightly. You will always have one of the cores on 100% usage.

2, Process the videos on a central server: here you just forward the raw video stream from the camera to an external streaming sever (like iSpy running on an x86 computer or MotionEyeOS running on another dedicated minicomputer). Since there is no processing locally the model of PI you use does not matter, a PI1 will send the same stream as a PI3B+.

In this tutorial I will go with the first choice.


The rule of thumb here is that the faster CPU you throw at motion the better results you will get. For example my Raspi 2 based camera looking at a corridor sometimes did not pick it up when somebody went by fast and when it was recording the recording was sluggish, dropping a lot of frames compared to the model 3. The model 3 also have the 802.11 abgn wifi which comes handy to be able to stream higher quality video, it works out of the box and it is quite reliable. At the time of writing that the model 3B+ is out I would just recommend that you get that with 1.4 Ghz Quad Core cpu.

List of materials

  • 30 cm plastic DeathStar :)
  • Raspberry Pi 3 B+
  • PiCam v2 (8MP)
  • Arduino Pro Micro 5.5v
  • 2x SIP-1A05 Reed Switch Relay
  • 1x PCS HC-SR501 IR Pyroelectric Infrared IR PIR Motion Sensor Detector Module
  • 1x 10kohm resistor for LDR
  • 1x LDR
  • 1x12V 4A DC adapter
  • 1xWarm White LED 5050 SMD Flexible Light Lamp Strip 12V DC
  • 1xBuck voltage regulator

As you can see it on the schematics this project was originally designed to control one single light with one relay because I did not plan on adding internal lighting (which is quite cool) so I just hardwired a second relay to the Arduino. The great thing about the SIP-1A05 is that it has internal flyback diode and the consumption in mA is way under the Arduino's per pin power limitation.


The reason why the PIR is on the shield on the pictures because at the beginning S0P was planned to be put into a simple IP plastic box instead of a DeathStar. As you might guessed the camera is directly in the laser gun the PIR and LDR needed another drilled holes and they are glue-gunned since I not planning to remove them.

A hole was drilled at the bottom of the DeathStar where I glued in a large bolt with a strong 2 component glue. This can be screwed into the original Neo Coolcams stand (it was good for something after all :)). For an additional support I using hard copper wires to have a hold on the top of the star.

Important note about the power supply: since the same supply will power both the PI, Arduino and the LED strip it has to be beefy enough to be able to handle them all so it will be based on the LED strip you choose for the project. A commerical 5050 12v 3meter LED strip drains around 2A, that's a lot. For the PI and Arduino you have to calculate in +2A (although this is oversizing it will not hurt). Using LED strip over standard halogen bulbs, neon or other high power lighting is that you can put this whole circuit on a nice 12V@10Ah lead acid battery as backup so it will even work in case of a power outage.

The buck will step down the voltage from 12->5V for powering the Arduino and the PI while the direct 12V feed is wired on the relay to turn the LED strip on.

Step 3: Software Arduino

You can find the full source code down below which is well commented but here is a brief explanation how it works:
At the beginning of each loop the usual xcomm() function is called to see if there is a command come from the Raspberry PI which can be LIGHT_ON/OFF to turn the corridor lights ON of or DS_ON/OFF to turn the DeathStar backlight ON/OFF, I have implemented these just for the sake of over perfection since if somebody passes by the PIR should pick it up and turn on the lights but maybe you want to look at the place for some reason even when no one is there.

After this the photocell value read in and the motion pin is checked for motion. If there is motion the code checks if it's dark enough then it checks if we are not on hold. If all this passes then it simply turns the corridor light on and sends back PHOENIX_MOTION_DETECTED to the Raspberry PI, if it is not dark enough it still signals back to the computer but does not turn the light on. Once a motion is detected a 5 minute hold timer is started.

Right after this the next code section will check to see if we are on hold (which should be the case if there was just a motion event, so let's assume the 5 minutes passed so this check can confirm). The code checks to see if there is motion again, if not then turn the lights off. As you can see if there is no motion this function will repeat itself over and over again keep trying to turn the lights off so there is no feedback to the PC.

We have another hold timer for the DeathStar's internal lighting which purely depends on photocellReading < dark_limit.

Although the 2 routines don't know about each other, they will work perfectly together since when the corridor light goes on it provides so much light that the LDR will think it's daytime again and it turns off the internal lighting. However there were some caveats about this process which is explained in the code if you are interested, if not then take the Nvidia answer that "it just works!".

Step 4: Software Raspberry PI

The latest Raspbian works for me:

Raspbian GNU/Linux 9.4 (stretch)
Linux Phoenix 4.9.35-v7+ #1014 SMP Fri Jun 30 14:47:43 BST 2017 armv7l GNU/Linux
ii  motion                          4.0-1                             armhf        V4L capture program supporting motion detection

While you can use other distros, if you run into any issues with the camera you will only get support from the team if you are using their official OS. Removing undesirable bloatware such as systemd is also highly recommended.

Motion can also be built from source easily:

 apt-get -y install autoconf automake pkgconf libtool libjpeg8-dev build-essential libzip-dev apt-get install libavformat-dev libavcodec-dev libavutil-dev libswscale-dev libavdevice-dev
 apt-get -y install libavformat-dev libavcodec-dev libavutil-dev libswscale-dev libavdevice-dev
 apt-get -y install git
 git clone https://github.com/Motion-Project/motion

 cd motion/
 autoreconf -fiv
 ./configure --prefix=/usr/motion
 make && make install
 /usr/motion/bin/motion -v

I recommend iSpy as video recorder/collector server. Unfortunately at the time of writing there are no good alternatives for Linux. The camera can be added with an MJPEG url http://CAMERA_IP:8081 the default port.

The motion processing can be useful for example you don't have to keep looking at the your iSpy server all day long, you can receive an email in case of motion. Although iSpy has this functionality to alert in email in case of motion, it does turn on recording once in a while for miscellaneous events like some light is reflected to the area. With the PIR motion detection I never had one single false alarm. The alerts can be processed locally:

Pir motion event detected on sensor > Arduino alert > Raspberry pi receives on console > C processing program > External mail application

I however prefer processing both the logs and videos remotely so in this case I have added a section to the C control program to while it logs the logs locally into a plain text file, also logs it to syslog and that is forwarded into a SIEM for further processing.

void logger(char *text) {

 FILE *f = fopen("phoenix.log", "a");

 if (f == NULL)
  {
    printf("Error opening log file!\n");
    return;
  }
 fprintf(f, "%s => %s\n", cur_time(0), text);
 fclose(f);

#ifdef SYSLOG
 char loggy[500];
 sprintf(loggy,"%s => %s\n", cur_time(0), text);
 setlogmask (LOG_UPTO (LOG_NOTICE));
 openlog ("DeathStar", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
 //syslog (LOG_NOTICE, "Program started by User %d", getuid ());
 syslog (LOG_NOTICE, loggy);
 closelog ();
#endif

 return;
}

On the receiving end syslog-ng can demux these events from the main log stream:

filter f_phx{
        match("DeathStar");
};
destination d_phx { file("/var/log/phoenix/deathstar.log"); };
log { source(s_net); filter(f_phx); destination(d_phx); };

and it can be passed to another tool (motion.php see attached) for analysis and alerting.

In this script you can simply set the usual time during the week when you are not at home:

$opt['alert_after']='09:00:00';  // Mornings<br>$opt['alert_before']='17:00:00'; // Evenings

The php program utilizes the excellent logtail utility to parse the logs.

$cmd = "logtail -o".$offsetfile.' '.$logfile.'>'.$logfile2;

Logtail tracks the position in an offset file so the main program don't have to know about from which time to start looking at the logs at, it will be provided with the latest unprocessed data.

Motion.php can be run from crontab with a small trick for the weekends, when it will go through the logs, but do no further processing.

*/5 * * * 1-5 /usr/local/bin/php ~/motion.php &>/dev/null<br>*/5 * * * 6-7 /usr/local/bin/php ~/motion.php weekend &>/dev/null

Step 5: Issues and ToDo List

If you are using Raspberry pi 3 or newer you can skip this section, you will most likely not run into these problems anymore.


During the years I had some issues with Raspberry pi 2 based boards what might run the same software stack but were purchased at different times from different places. After a certain period of time which could be 2 days or 20 days when SSHing in on the device the SSH would just hang, so both the motion daemon and local C code which talked to the Arduino was loaded up into ram therefore the device was functioning but it was impossible to do anything else with it anymore in this state.

After a lot of troubleshooting I have come up with a solution:

homesync.sh

#!/bin/sh -e
### BEGIN INIT INFO
# Provides:          homesync
# Required-Start:    mountkernfs $local_fs 
# Required-Stop:     camera phoenix
# Default-Start:     S
# Default-Stop:      0 6
# Short-Description: Home synchronizer
# Description:       Home synchronizer by NLD
### END INIT INFO

NAME=home
DESC="Ramdisk Home Synchronizer"
RAM="/home/"
DISK="/realhome/"

set -e

case "$1" in
  start|forth)
    echo -n "Starting $DESC: "
    rsync -az --numeric-ids --delete $DISK $RAM &> /dev/null 
    echo "$NAME."
    ;;
  stop|back)
    echo -n "Stopping $DESC: "
        rsync -az --numeric-ids --delete $RAM $DISK &> /dev/null
    echo "$NAME."
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac

exit 0

The script goes together with an fstab modification:

  tmpfs           /home            tmpfs   rw,size=80%,nosuid,nodev                  0       0

The home partition is mounted as ramdisk which would yield approx 600MB free space on the Raspberry pi 2 which is more than enough to store some binaries and small log files:

  tmpfs           690M  8.6M  682M   2% /home

It turned out that the PI hang was attributed to the write operations on the SDcard, although I have tried different cards (Samsung EVO, Sandisk) which were scanned for errors multiple times before and after and they had no problem in other laptops this was just coming up. I did not have the same issue (yet) with Raspberry PI 3s and higher hardware so that is also why I recommend them in this tutorial.

Although the current motion on a Raspberry PI 3 is just good enough for me, here are some ideas worth exploring:

  1. Do not use motion, but use a raspivid stream over the network and let a powerful server do the motion detection and video encoding (e.g iSpy). -> Problem: constant network bandwidth hogging.
  2. Use motion and let ffmpeg do the video encoding. -> Problem: CPU can't handle the higher resolutions
  3. Use motion, record raw video and let a powerful server do the encoding. -> CPU usage on RPi is low and network bandwith is limited to when there is actual motion. For this scenario we could write to an SD-card/ramdisk for max throughput and then crontab a copy the video to another server.

I would also note that building this project is possible to build without an Arduino. All the components (relays, LDR, PIR) could be connected to the raspberry pi some way but I prefer real time microcontrollers to interact with sensors and output devices. In the cases where my raspberry pi was hanging for example or crashed, the light control run by the Arduino worked just fine.

If you liked this instructable stayed tuned as I will continue the series with my 360 degree outdoor raspberry pi zero dome camera next year.