Raspberry PI Security Camera

To setup a Raspberry PI security camera.

I flash the SD with the latest [NOOBS] after formatting the SD card with the [SDCard Formatter].

Boot into the desktop and put the Raspberry PI on the wifi network.

Enable the [camera interface] and reboot.

Sudo edit the /boot/config.txt file. Disable the camera LED by adding the entry:

disable_camera_led=1

Install the [poster] module by running the command-line:

sudo pip install poster

Create the file: ~/superscript

cd ~/Documents/PythonScripts/Camera/
python capture_image.py

Add execute permissions to superscript.

chmod +x ~/superscript

Create a folder for the Camera Python scripts.

mkdir ~/Documents/PythonScripts
mkdir ~/Documents/PythonScripts/Camera/

Create the ~/Documents/PythonScripts/Camera/capture_image.py script. Rotate the camera as necessary.

#get access to the camera
from picamera import PiCamera

#import so we can invoke another script
import subprocess

#get access to the clock
import datetime

# get access to sunrise and sunset
from astral import Location

#sleep so we can wait on the camera
from time import sleep

from fractions import Fraction

# create a camera object
camera = PiCamera()

#set the image resolution
camera.resolution = (640, 480)

#rotate the camera if upside-down
camera.rotation = 180

#flip the camera on the horizontal
camera.hflip = True

i = 0;

#record defaults
framerate = camera.framerate
shutter_speed = camera.shutter_speed
exposure_mode = camera.exposure_mode
iso = camera.iso

while True:

  # Get sunrise and sunset for Monroe, WA
  l = Location()
  l.latitude = 47.887059
  l.longitude = -121.8792998
  l.timezone = 'US/Pacific'

  sunrise = l.sun()['dawn']
  sunriseHour = int(sunrise.strftime('%H'))
  sunriseMinute = int(sunrise.strftime('%M'))
  sunset = l.sun()['sunset']
  sunsetHour = int(sunset.strftime('%H'))
  sunsetMinute = int(sunset.strftime('%M'))

  hours = int(datetime.datetime.now().strftime('%H'))
  minutes = int(datetime.datetime.now().strftime('%M'))
  seconds = int(datetime.datetime.now().strftime('%S'))

  if (hours >= sunriseHour and hours <= sunsetHour):
    #print 'work in the light'
    camera.framerate = framerate
    camera.shutter_speed = shutter_speed
    camera.exposure_mode = exposure_mode
    camera.iso = iso
  else:
    #print 'work in the dark'
    camera.framerate = Fraction(1,6)
    camera.shutter_speed = 6000000
    camera.exposure_mode = 'off'
    camera.iso = 800

  #show preview with some transparency
  #camera.start_preview(alpha=200)

  #wait two seconds for camera lighting
  #sleep(2)

  filename = 'image'+str(i)+'.jpg'

  #save image locally
  camera.capture(filename)

  #invoke the script to upload the image
  subprocess.call('python save_image.py '+filename, shell=True)

  #stop the preview
  #camera.stop_preview()

  sleep(3)

  i = (i + 1) % 12

Create the save_image.py script. Alter the domain and path to ~/Documents/PythonScripts/Camera/save_image.py.

#!/usr/bin/env python

import urllib, urllib2, os, os.path, sys
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers

command = os.popen('ifconfig | grep -A1 wlan0')
client_ip = command.read()
#print client_ip

register_openers()

if (len(sys.argv) > 1):
  filename = sys.argv[1];
else:
  filename = 'image.jpg';

query = { 'filename' : filename, 'client_ip' : client_ip }
url = "http://domain/path/save_image.php?"+urllib.urlencode(query)

print 'Saved: '+filename;
if (os.path.isfile(filename)) :
  values = {'image':open(filename)}
  data, headers = multipart_encode(values)
  headers['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
  headers['filename'] = filename
  req = urllib2.Request(url, data, headers)
  req.unverifiable = True
  content = urllib2.urlopen(req).read()
  #print (content)
else:
  print 'No image file found to upload\r\n';

On your PHP server somewhere, make a new folder and create the page save_image.php.

<?php

$filename = "image.jpg";
if ($_GET['filename'] != null) {
   $filename = $_GET['filename'];
}

if ($_GET['client_ip'] != null) {
   $clientip = $_GET['client_ip'];
   file_put_contents('client_ip.txt', $clientip);
}

$image = $_FILES["image"];

if ($image == null) {
   echo "Missing image to save as: ";
   echo $filename;
} else {
   echo "Saved image!";
   $tmp_name = $_FILES["image"]["tmp_name"];
   move_uploaded_file($tmp_name, $filename);
}

?>

On your PHP server somewhere, save the page images.php near your server image paths.

<html>
<?php
function displayFirstImage($path) {
   $files = glob($path);
   usort($files, function($a, $b) {
      return filemtime($a) < filemtime($b);
   });
   foreach($files as $file){
      printf('<img src="%1$s"/>', $file);
      break;
   }
}
displayFirstImage('path/to/camera1/*.jpg');
displayFirstImage('path/to/camera2/*.jpg');
displayFirstImage('path/to/camera3/*.jpg');
displayFirstImage('path/to/camera4/*.jpg');
?>
<script>
setTimeout("window.location.reload()", 30000);
</script>
</html>

Edit ~/.bashrc and add the following to the end of the file.

~/superscript &

Reboot the Raspberry PI and the security camera is ready to go!

Lightweight python motion detection

Brian Flakes posted an example script in the RPI forums for how to do [lightweight python motion detection] which is useful when taking pictures with the RPI camera module.

Converted the example to work with PiCamera.

#get access to the camera
from picamera import PiCamera

import picamera.array #want to do it in memory

from PIL import Image
import requests

#import so we can invoke another script
import subprocess

#sleep so we can wait on the camera
from time import sleep

token = 'YOUR_SECURITY_TOKEN'
selector = 'group_id:SEE_THE_SELECTOR_DOCS'
threshold = 40
sensitivity = 20
firstRun = True
lastPixels = []
detected = False
showPreview = False
hidePreview = False
waitRedlight = 600
i = 0
headers = {
    "Authorization": "Bearer %s" % token,
}

# create a camera object
camera = PiCamera()

#set the image resolution
camera.resolution = (640, 480)

#rotate the camera if upside-down
#camera.rotation = 180

def Greenlight():
  payload = {
    "power": "off",
    "color": "green saturation:0.9",
    "brightness": 1.0,
    "duration": 1
  }
  try:
    response = requests.put('https://api.lifx.com/v1/lights/'+selector+'/state', data=payload, headers=headers)
  except:
    pass

def Redlight():
  payload = {
    "power": "on",
    "color": "white",
    "brightness": 1.0,
    "duration": 1
  }
  try:
    response = requests.put('https://api.lifx.com/v1/lights/'+selector+'/state', data=payload, headers=headers)
  except:
    pass

Greenlight();

while True:

  if (showPreview):
    showPreview = False
    #show preview with some transparency
    camera.start_preview(alpha=200)
    hidePreview = True

  filename = 'image'+str(i)+'.jpg'

  #save image locally
  camera.capture(filename)

  image = Image.open(filename)
  pixels = image.load()

  width, height = image.size
  #print ('width='+str(width)+' height='+str(height)+"\n");

  if (firstRun):
    firstRun = False
    lastPixels = pixels

  # Count changed pixels
  changedPixels = 0
  for x in range(width):
    for y in range(height):
      # Just check green channel as it's the highest quality channel
      pixdiff = abs(pixels[x,y][1] - lastPixels[x,y][1])
      if pixdiff > threshold:
        changedPixels += 1

  print ('changedPixels='+str(changedPixels))
  lastPixels = pixels

  if (changedPixels < 100):
    if (detected):
      detected = False
      Greenlight();
      firstRun = True
  else:
    if (detected == False):
      detected = True
      Redlight();
      sleep(waitRedlight)
      firstRun = True
      showPreview = True

  if (hidePreview):
    hidePreview = False
    #stop the preview
    camera.stop_preview()
    firstRun = True

  sleep(1)

  i = (i + 1) % 12
  

RASPBIAN

The Raspberry PI organization hosts [RASPBIAN] which comes pre-installed with plenty of software for education, programming and general use. It has Python, Scratch, Sonic Pi, Java, Mathematica and more. [Noobs] is a tool that can flash an SD card to install Raspbian. The SD card organization has a [SD Card Formatter] tool to format the SD card.

Reminder: On RPI2 with Raspbian, the default user is pi with the password raspberry.

Python Multipart Posts

To use a camera with the Raspberry PI, first [configure the Raspberry PI] to enable the camera.

In order to send large images from the Raspberry PI camera to a web server, the image has to be sent in parts. This requires the Python `poster` module. https://pypi.python.org/pypi/poster/

To be able to install a python module, `pip` has to be installed.

sudo pip install poster

This is the server PHP page that saves the image.

save_image.php


<?php

$image = $_FILES["image"];

if ($image == null) {
   echo "Missing image to save!";
} else {
   echo "Saved image!";
   $tmp_name = $_FILES["image"]["tmp_name"];
   move_uploaded_file($tmp_name, "image.jpg");
}

?>

This Python script sends the image to the server.

save_image.py


#!/usr/bin/env python

import urllib, urllib2
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers

register_openers()

url = "http://domain.com/path/save_image.php"
print "url="+url

filename = 'image.jpg';
if (os.path.isfile(filename)) :
  values = {'image':open(filename)}
  data, headers = multipart_encode(values)
  headers['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
  req = urllib2.Request(url, data, headers)
  req.unverifiable = True
  content = urllib2.urlopen(req).read()
  print (content)
else:
  print 'No image file found to upload';

print '\r\nProgam complete.'

This script will capture from the camera and then call the above script to upload the image.

capture_image.py


#get access to the camera
from picamera import PiCamera

#import so we can invoke another script
import subprocess

#sleep so we can wait on the camera
from time import sleep

# create a camera object
camera = PiCamera()

#set the image resolution
camera.resolution = (320, 240)

#rotate the camera if upside-down
camera.rotation = 180

#show preview with some transparency
camera.start_preview(alpha=225)

#wait two seconds for camera lighting
sleep(2)

#save image locally
camera.capture('image.jpg')

#stop the preview
camera.stop_preview()

#invoke the script to upload the image
subprocess.call('python save_image.py', shell=True)

Servo Rotation

The servo can be turned clockwise, counter clockwise, and to the 90 degree position, but it lacks a way to query the current rotation. The rotation needs to be calculated manually and this script is a first attempt.

#!/usr/bin/env python

import RPi.GPIO as GPIO
import datetime
import time

servo_pin = 22
servo_pin2 = 18

# 60 degrees / 0.1seconds
servo_speed = 0.1

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

GPIO.setup(servo_pin, GPIO.OUT)
GPIO.setup(servo_pin2, GPIO.OUT)

last_time = datetime.datetime.now()
current_time = datetime.datetime.now()
sumTime = datetime.timedelta(0, 0)

accuracy = 0.01
targetRotation = 0
currentRotation = 90

pulse1 = GPIO.PWM(servo_pin, 50)
pulse2 = GPIO.PWM(servo_pin2, 50)

logTime = datetime.datetime.now()

def log(msg):
 global deltaTime
 global logTime
 if (logTime < datetime.datetime.now()):
  logTime = datetime.datetime.now() + datetime.timedelta(0, 0.5)
  print msg
 return

def reset(pulse):
 pulse.start(7.5);
 pulse.ChangeDutyCycle(7.5)
 return

def update(pulse, targetRotation):
 global deltaTime
 global sumTime
 global servo_speed
 global accuracy
 global currentRotation
 log ("TargetRotation: " + str(targetRotation) + " CurrentRotation: "+str(currentRotation))
 if (targetRotation == 90):
  pulse.ChangeDutyCycle(7.5)
  if ((currentRotation - targetRotation) < -accuracy):
   currentRotation += servo_speed
  elif ((currentRotation - targetRotation) > accuracy):
   currentRotation -= servo_speed
  else:
   pulse.ChangeDutyCycle(0)
 elif ((currentRotation - targetRotation) < -accuracy):
  pulse.ChangeDutyCycle(12.5)
  currentRotation += servo_speed
 elif ((currentRotation - targetRotation) > accuracy):
  pulse.ChangeDutyCycle(2.5)
  currentRotation -= servo_speed
 else:
  pulse.ChangeDutyCycle(0)
 return

try:
 reset(pulse1)
 reset(pulse2)
 time.sleep(1)
 print "setup complete"

 while True:
 
  last_time = current_time
  current_time = datetime.datetime.now()
  deltaTime = current_time - last_time;
  sumTime += deltaTime;

  if (sumTime.total_seconds() > 3.0):
   #print (sumTime)
   sumTime -= datetime.timedelta(0, 3)
   targetRotation = (targetRotation + 45) % 180

  update(pulse1, targetRotation);
  update(pulse2, targetRotation);

  time.sleep(0);

except KeyboardInterrupt:

 print '\r\nProgam complete.'
 GPIO.cleanup();

Raspberry PI 2 – Servo Control

Using pulse modulation, the Raspberry PI can adjust a servo.
https://www.youtube.com/watch?v=ddlDgUymbxc

2015-04-22+12.06.15[1]

Here I combined the LED blinking example with the servo example.

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
led_pin = 15
led_pin2 = 16
led_pin3 = 36
led_pin4 = 37

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

GPIO.setup(led_pin, GPIO.OUT)
GPIO.setup(led_pin2, GPIO.OUT)
GPIO.setup(led_pin3, GPIO.OUT)
GPIO.setup(led_pin4, GPIO.OUT)

GPIO.setup(22, GPIO.OUT)

p = GPIO.PWM(22, 50)
p.start(7.5);

try:
 while True:

  GPIO.output(led_pin, GPIO.HIGH)
  GPIO.output(led_pin2, GPIO.HIGH)
  GPIO.output(led_pin3, GPIO.HIGH)
  GPIO.output(led_pin4, GPIO.HIGH)
  p.ChangeDutyCycle(7.5)
  time.sleep(1)

  GPIO.output(led_pin, GPIO.LOW)
  GPIO.output(led_pin2, GPIO.LOW)
  GPIO.output(led_pin3, GPIO.HIGH)
  GPIO.output(led_pin4, GPIO.HIGH)
  p.ChangeDutyCycle(12.5)
  time.sleep(1)

  GPIO.output(led_pin, GPIO.HIGH)
  GPIO.output(led_pin2, GPIO.HIGH)
  GPIO.output(led_pin3, GPIO.HIGH)
  GPIO.output(led_pin4, GPIO.HIGH)
  p.ChangeDutyCycle(7.5)
  time.sleep(1)

  GPIO.output(led_pin, GPIO.HIGH)
  GPIO.output(led_pin2, GPIO.HIGH)
  GPIO.output(led_pin3, GPIO.LOW)
  GPIO.output(led_pin4, GPIO.LOW)
  p.ChangeDutyCycle(2.5)
  time.sleep(1)

except KeyboardInterrupt:

 print '\r\nBack to neutral...'
 p.ChangeDutyCycle(7.5)
 time.sleep(1)

 print '\r\nProgam complete.'
 GPIO.cleanup();

Raspberry PI 2 – Alternating LEDs

The following Python alternates between two LEDs and then goes dark before repeating.

20150418_211943[1]

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
led_pin = 15
led_pin2 = 37
blinkSpeed = 5/2.0 #blink x times per second

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)

GPIO.setup(led_pin, GPIO.OUT)
GPIO.setup(led_pin2, GPIO.OUT)

try:
 while True:

  GPIO.output(led_pin, GPIO.HIGH)
  GPIO.output(led_pin2, GPIO.LOW)
  time.sleep(blinkSpeed / 3.0)

  GPIO.output(led_pin, GPIO.LOW)
  GPIO.output(led_pin2, GPIO.HIGH)
  time.sleep(blinkSpeed / 3.0)

  GPIO.output(led_pin, GPIO.LOW)
  GPIO.output(led_pin2, GPIO.LOW)
  time.sleep(blinkSpeed / 3.0)

finally:
 print 'finally'

Raspberry PI 2 – Blinking LED

Here’s a short Python script to toggle an LED using GPIO.

20150418_173116[1]

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
pin = 15
blinkSpeed = 1/5.0 #blink x times per second
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pin, GPIO.OUT)
try:
 while True:
  print('PIN {} is going HIGH'.format(pin))
  GPIO.output(pin, GPIO.HIGH)
  time.sleep(blinkSpeed / 2.0)
  print('PIN {} is going LOW'.format(pin))
  GPIO.output(pin, GPIO.LOW)
  time.sleep(blinkSpeed / 2.0)
finally:
 print 'finally'

Raspberry PI 2 – Sails.js

Installing Sails.js required building and installing Node.js from source.

I let the source build overnight and then moments later ‘sails lift’ was functional.
https://github.com/tgraupmann/TAGENIGMA-Docs/blob/master/Sails.md

Also the reference guide is super helpful.
http://sailsjs.org/#!/documentation/reference/

Here is also a useful C# client:
https://github.com/Quobject/SocketIoClientDotNet

Raspberry PI 2 – VNC

I picked up a Raspberry PI 2 and it’s working super speedy. Quad-core 900 MHz, ARM, 4-usb, HDMI/audio out.
http://www.amazon.com/CanaKit-Raspberry-Ultimate-Starter-Components/dp/B00G1PNG54/

After settting up WIFI, installing VNC made connecting the display, mouse, and keyboard no longer necessary. The boot process can be altered to start VNC server automatically.
https://www.raspberrypi.org/documentation/remote-access/vnc/