Pi Security

next steps: add sms notification option

Python-based motion detection and still/vid capture and delivery for Raspberry Pi 3

Hooked up two PIR motion sensors to a Pi 3. Now when either detects motion, the Pi’s camera will take a still shot and send it to an an email account, as well as take a slo-motion video and send that to a dropbox account.

Source code: pi-security (or see below)


# frankencode with ideas and snippets adapted from many sources including here:
# https://www.raspberrypi.org/forums/viewtopic.php?t=86441&f=32

import time
import RPi.GPIO as GPIO
from subprocess import call
import string
import smtplib
# For guessing MIME type
import mimetypes 
# Import the email modules we'll need
import email
import email.mime.application 
#Import sys to deal with command line arguments
import sys
from subprocess import call  

GPIO.setwarnings (False)
# using BCM not BOARD here, else pin 7 should be 26
GPIO.setmode(GPIO.BCM)
time_stamp = time.time() #for debouncing

#set pins
#pin 7 = motion sensor 1, pin 8 = motion sensor 2, pin 14 = dummy
GPIO.setup (7, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup (8, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup (14, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

counter = 1

def take_pic(sensor):	
	global counter
	call(["raspistill -vf -hf -o image" + sensor + str(counter) + ".jpg"], shell=True)
#	time.sleep(2) #wait 2 seconds before continuing
	call(["raspivid -w 1024 -h 576 -fps 60 -t 20000 -o vid" + sensor + str(counter) + ".h264"], shell=True)
#	time.sleep(35) #wait 35 seconds before continuing
	

def drop_box(sensor):	
	global counter
	photofile = "/path/to/dropbox_uploader.sh upload /path/to/vids" + sensor + str(counter) + ".h264 vid" + sensor + str(counter) + ".h264"
	call ([photofile], shell=True)
#	time.sleep(35) #wait 35 seconds before continuing


def send_text(details):
	# Create a text/plain message
	msg = email.mime.Multipart.MIMEMultipart()
	msg['Subject'] = 'Security Alert'
	msg['From'] = 'any@email.address'
	msg['To'] = 'to@email.address'

 
	# The main body is just another attachment
	body = email.mime.Text.MIMEText("""body text here""")
	msg.attach(body)
 
	# use jpg not pdf
 
	#directory=sys.argv[1]
	directory = 'imagemotion' + str(counter) + '.jpg'
 
	# Split directory into fields separated by / to subtract filename
 
	spl_dir=directory.split('/')
 
	# We attach the name of the file to filename by taking the last
	# position of the fragmented string, which is, indeed, the name
	# of the file we've selected
 
	filename=spl_dir[len(spl_dir)-1]
 
	# We'll do the same but this time to extract the file format (pdf, epub, docx...)
 
	spl_type=directory.split('.')
 
	type=spl_type[len(spl_type)-1]
 
	fp=open(directory,'rb')
	att = email.mime.application.MIMEApplication(fp.read(),_subtype=type)
	fp.close()
	att.add_header('Content-Disposition','attachment',filename=filename)
	msg.attach(att)
 
	# send via Gmail server
	s = smtplib.SMTP('smtp.gmail.com:587')
	s.starttls()
	s.login('to@email.address','password')
	s.sendmail('any.email.address','to@email.address', msg.as_string())
	s.quit()


def motion_callback(channel):
    global time_stamp
    global counter
    time_now = time.time()
    if (time_now - time_stamp) >= 0.3: #check for debouncing
	print "Motion detector detected GPIO 7 " + str(counter)
	take_pic("motion")
#	time.sleep(5) #wait 5 second for pic to show up in dir before trying to attach
	drop_box("motion")
	send_text("Motion detector")
	counter +=1   
	time_stamp = time_now
	
def motion_callback2(channel):
    global time_stamp
    global counter
    time_now = time.time()
    if (time_now - time_stamp) >= 0.3: #check for debouncing
	print "Motion detector detected GPIO 8 " + str(counter)
	take_pic("motion")
#	time.sleep(5) #wait 5 second for pic to show up in dir before trying to attach
	drop_box("motion")
	send_text("Motion detector")
	counter +=1   
	time_stamp = time_now

#main body
raw_input("Press enter to start program\n")

GPIO.add_event_detect(7, GPIO.RISING, callback=motion_callback)
GPIO.add_event_detect(8, GPIO.RISING, callback=motion_callback2)


# pressure switch ends the program
# you could easily add a unique callback for the pressure switch
# and add another switch just to turn off the network
try:
    print "Waiting for sensors..."
    GPIO.wait_for_edge(14, GPIO.RISING)
except KeyboardInterrupt:
    GPIO.cleanup()

GPIO.cleanup()