YouTube player

The purpose is clear. You don’t want your kids to steal your food from the cupboard, or from the fridge, or someone to open your locker. Or maybe you want to take pictures of your pet stealing food. Or maybe you are Dwight Schrute and you want to finally unmask the coworker that puts your stuff into jelly. So what can you do about it? You can hide a device in the cupboard/fridge/locker that will take a picture and email it to you when movement is detected. And if you use IFTTT, then you can automatically post the picture of the thief to Facebook or Twitter and show the thief’s face to the entire world!

This project consists of a motion sensor (PIR), a camera, and a wifi connected device. Arduino Yún was my choice, because it is easy to use and to configure the wifi settings, but it can be easily substituted with a RaspberryPi. Configuring the wifi settings may be difficult with the Raspberry Pi without connecting it to a computer, but anyone can configure the wifi settings on the Yún. The project is very simple. It doesn’t require any soldering/electronics skills and it can be assembled in minutes.

totalone

Project Steps

Step 1

Arduino basic configuration

First of all, you need to configure your Arduino Yún network settings. This should be pretty easy following this guide.

Test the connection to your Arduino. In your browser, type: http://arduino.local. You will see the Arduino web interface.

If it works, open SSH session

$ssh root@arduino.local

the default password is “arduino”

Then let’s install some useful packages

$opkg update
$opkg install openssh-sftp-server

Why the openssh-sftp-server? Because it will be easier for you to upload and download files to and from the Arduino. Now you can use a generic SFTP client (filezilla, transmit or cyberduck) instead of SCP command

Then, we have have to install the SSL support package for Python (thanks sbkirby!) because it’s not included in the default packages

$opkg update
$opkg install python-openssl

If you have one, I highly recommend that you put a micro SD card into the Arduino Yún. It will be automatically mounted in /mnt/sda1

Then, we will install the USB Camera and USB Soundcard onto the Yún

Step 2

Installing and testing the USB Camera

The UVC package is already available for Linino via opkg, so installing the Camera is a very easy step. Just connect to your Yún via ssh and type:

$ opkg update
$ opkg install kmod-video-uvc

We also need a software for taking pictures, I used fswebcam that is super small and very easy to use.

$ opkg install fswebcam

Step 3

Take your first picture

Be sure to use an SD card for storage or you will quickly fill the Arduino internal storage. If you are using an SD card, you should see it mounted in /mnt/sda1. If it’s not, put a FAT32 formatted micro SD card into the SD Card Slot, and reboot your Arduino

Now plug the camera to the USB host port, and type

$ cd /mnt/sda1
$ fswebcam test.png

If everything is ok, you took your first picture! Take a look to your SD card contents :)

This means that now we can take pictures from our Arduino sketch, via the Yún’s Bridge library, in this way

Process.runShellCommand("fswebcam /mnt/sda1/test.png");

Step 4

Install the sound card

Open an ssh session to the yun, and type:

$opkg install kmod-usb-audio
$opkg install madplay

End of the story. Now you have sound support on the Arduino Yún. I only tried MP3 playback, I didn’t try to record some audio yet, but I’ll try soon!

To test it just copy an mp3 audio file to the SD card, and type:

$cd /mnt/sda1
$madplay yoursound.mp3  

This means that now we can take play sounds from our Arduino sketch, via the Yún’s Bridge library, in this way:

Process.runShellCommand("madplay /mnt/sda1/test.mp3");

Step 5

The Email script

Now we can take pictures and play sounds… But we want more from our Arduino! We want to send them via email.

So, what can we do? The answer is very easy… python script! Even if the Arduino Yún integrates the Temboo library, I wanted this project to be as portable as possible, so we will use a very simple python script to encode the image file and send it to our email.

I’m assuming that you are using GMail, but the script can be easily adapted to any SMTP server

Create a new file, call it “sendemail.py” and paste this code into it

# coding=utf-8

# Copyright (C) 2014  Stefano Guglielmetti

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import smtplib, os, sys
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders

#From address, to address, subject and message body
from_address    = 'FROM_ADDRESS@EMAIL.COM'
to_address      = ['YOUR_ADDRESS@EMAIL.COM']
email_subject   = 'Alert!!! Zombies!!! Ahead!!!'
email_body      = 'A non dead intruder has been detected and needs to be eliminated!'

# Credentials (if needed)
username = 'EMAIL_LOGIN'
password = 'EMAIL_PASSWORD'

# The actual mail send
server = 'smtp.gmail.com:587'

def send_mail(send_from, send_to, subject, text, files=[], server="localhost"):
    assert type(send_to)==list
    assert type(files)==list

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach( MIMEText(text) )

    for f in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload( open(f,"rb").read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
        msg.attach(part)

    smtp = smtplib.SMTP(server)
    smtp.starttls()
    smtp.login(username,password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()

send_mail(from_address, to_address, email_subject, email_body, [sys.argv[1]], server) #the first command line argument will be used as the image file name

now you have to customise the email settings

#From address, to address, subject and message body
from_address    = 'FROM_ADDRESS@EMAIL.COM'
to_address      = ['YOUR_ADDRESS@EMAIL.COM']
email_subject   = 'Alert!!! Zombies!!! Ahead!!!'
email_body      = 'An undead intruder has been detected and needs to be eliminated!'

# Credentials (if needed)
username = 'EMAIL_LOGIN'
password = 'EMAIL_PASSWORD'

# The actual mail send
server = 'smtp.gmail.com:587'

Now you can upload the script to the Arduino Yún SD card via SFTP (or SCP, if you prefer), then open an SSH session to the Yún and test it typing

$cd /mnt/sda1
$python sendemail.py test.png

And in a few seconds you will receive an email with the picture attachment… amazing!

Step 6

Let’s build the circuit!

Don’t worry, this is super easy. There is nothing to solder, just assemble few parts

I used this PIR sensor, because it’s reliable and easy to use.

Just follow this scheme

image

We’ve connected the PIR sensor. An LED will turn on when the device detects some movement

 

Step 7

Now it’s time to add the Arduino Sketch

Copy this code to the Arduino IDE and upload it to your Yún

/* 
 * Switches a LED, takes a picture and sends it via email
 * according to the state of the sensors output pin.
 * Determines the beginning and end of continuous motion sequences.
 *
 * @author: Stefano Guglielmetti / stefano (at) mikamai (dot) com / http://jeko.net
 * @date:   feb 5, 2014  
 *
 * based on the example by Kristian Gohlke / krigoo (_) gmail (_) com / http://krx.at
 * http://playground.arduino.cc/Code/PIRsense
 *
 * stefano guglielmetti (cleft) 2014 
 *
 * released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
 * http://creativecommons.org/licenses/by-nc-sa/2.0/de/
 *
 *
 * The Parallax PIR Sensor is an easy to use digital infrared motion sensor module. 
 * (http://www.parallax.com/detail.asp?product_id=555-28027)
 *
 * The sensor's output pin goes to HIGH if motion is present.
 * However, even if motion is present it goes to LOW from time to time, 
 * which might give the impression no motion is present. 
 * This program deals with this issue by ignoring LOW-phases shorter than a given time, 
 * assuming continuous motion is present during these phases.
 *  
 */

#include <Bridge.h>

/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 10;        

//the time when the sensor outputs a low impulse
long unsigned int lowIn;         

//the amount of milliseconds the sensor has to be low 
//before we assume all motion has stopped
long unsigned int pause = 5000;  

boolean lockLow = true;
boolean takeLowTime;  

int pirPin = 6;    //the digital pin connected to the PIR sensor's output
int ledPin = 13;

Process p;
String imageName;

/////////////////////////////
//SETUP
void setup(){
  Bridge.begin();
  Serial.begin(9600);
  pinMode(pirPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(pirPin, LOW);

  //give the sensor some time to calibrate
  Serial.print("calibrating sensor ");
  for(int i = 0; i < calibrationTime; i++){
    Serial.print(".");
    delay(1000);
  }
  Serial.println(" done");
  Serial.println("SENSOR ACTIVE");
  delay(50);
}

////////////////////////////
//LOOP
void loop(){

  if(digitalRead(pirPin) == HIGH){
    digitalWrite(ledPin, HIGH);   //the led visualizes the sensors output pin state
    if(lockLow){  
      //makes sure we wait for a transition to LOW before any further output is made:
      lockLow = false;            
      Serial.println("---");
      Serial.print("motion detected at ");
      Serial.print(millis()/1000);
      Serial.println(" sec"); 

      imageName = uniqueFileName("png"); //generate a new, uniqe file name

      p.runShellCommand("fswebcam /mnt/sda1/" + imageName); //takes the picture
      while(p.running()); //wait till the process ends
      p.runShellCommand("madplay /mnt/sda1/sounds/sirena.mp3"); //play the siren sound
      while(p.running()); //wait till the process ends
      p.runShellCommand("python /mnt/sda1/sendemail.py /mnt/sda1/" + imageName); //sends the picture via email
      while(p.running()); //wait till the process ends

      delay(50);
    }         
    takeLowTime = true;
  }

  if(digitalRead(pirPin) == LOW){       
    digitalWrite(ledPin, LOW);  //the led visualizes the sensors output pin state

    if(takeLowTime){
      lowIn = millis();          //save the time of the transition from high to LOW
      takeLowTime = false;       //make sure this is only done at the start of a LOW phase
    }
    //if the sensor is low for more than the given pause, 
    //we assume that no more motion is going to happen
    if(!lockLow && millis() - lowIn > pause){  
      //makes sure this block of code is only executed again after 
      //a new motion sequence has been detected
      lockLow = true;                        
      Serial.print("motion ended at ");      //output
      Serial.print((millis() - pause)/1000);
      Serial.println(" sec");
      delay(50);
    }
  }
}


/* A simple function to generate unique timestamp based filenames */

String uniqueFileName(String ext){
  String filename = "";
  p.runShellCommand("date +%s");
  while(p.running()); 

  while (p.available()>0) {
    char c = p.read();
    filename += c;
  } 

  filename.trim();
  filename += "." + ext;

  return filename;
}  

After 10 seconds (calibration time) it will start working and making pictures!!!

This is the assembled project

assembled

All the files of this project are available in my GitHub account.