PiDoorCam updated
This is the amended, latest version of my Raspberry Pi program to watch the street outside, detect change, and send a picture to another computer for storage, and to my phone. I’m often in the back garden, and can’t hear the doorbell; missing deliveries is rather annoying!
It no longer tries to take pictures when it’s dark, not just because I don’t have an infra-red camera and infra-red floodlights, but mainly because the street light outside flashes on and off all night, and I don’t want hundreds of pictures of that!
You’ll need to set up a Pushover account, which is free provided you don’t send too many notifications, and a Ramdisk with a directory called /var/tmp on the Pi.
Program listing
# Program for PiDoorCam
# Detects motion, and when it spots some, takes a high resolution
# picture, and sends the picture to another computer, also
# a notification via Pushover, to my phone.
import io
import os
import picamera
import ftplib
import time
import datetime
from PIL import Image
import requests
import json
import schedule
camera = picamera.PiCamera()
picamera.PiCamera.CAPTURE_TIMEOUT = 30
# If we detect 100 pixels that changed by 30, we have seen movement.
pixels = 100
difference = 30
# Use the maximum resolution of the camera.
# This is for V1. V2 is 3280 x 2464.
# It’s also correct for the ZeroCam.
width = 2592
height = 1944
# Internet lookup of sunrise and sunset at our location
def sunrise_sunset():
global sunrise, sunset
# Location of greenhouse is lat = yyyyy lon = xxxxx
url = ‘https://api.sunrise-sunset.org/json?lat=yyyyy&lng=xxxxx’
response = requests.get(url)
dict = response.json()
res = dict.get(‘results’)
curtim = datetime.datetime.now()
hm = res.get(‘sunrise’).split(“:”)
sunrise = curtim.replace(hour=int(hm[0])-1, minute=int(hm[1]))
print(“An hour before sunrise “,sunrise)
hm = res.get(‘sunset’).split(“:”)
sunset = curtim.replace(hour=int(hm[0])+13, minute=int(hm[1]))
print(“An hour after sunset “,sunset)
# I copied this voodoo motion detection from somewhere. Changed the timeout
# setting above to prevent the occasional failures to complete captures.
# Only alter this if you know what you are doing!
def compare():
camera.resolution = (100, 75)
stream = io.BytesIO()
format = ‘bmp’
camera.capture(stream, format)
stream.seek(0)
im = Image.open(stream)
buffer = im.load()
stream.close()
return im, buffer
# Function to take a new high resolution picture, send it to another computer,
# send it to my phone, and then delete it.
def newimage(width, height):
when = datetime.datetime.now()
filename = “door-%04d%02d%02d-%02d%02d%02d.jpg”
% (when.year, when.month, when.day, when.hour, when.minute, when.second)
camera.resolution = (width, height)
camera.capture(“/var/tmp/”+filename)
connected = True
ftp = ftplib.FTP()
ftp.connect(“computer-name”)
try:
ftp.login(“user-name”,”password”)
except ftplib.all_errors:
connected = False
print (“Failed to login to server.”)
ftp.quit()
if connected:
ftp.storbinary(‘STOR ‘+filename, open(“/var/tmp/”+filename, “rb”))
print (“Sent to server “, filename)
ftp.quit()
# Code to send the Pushover message. Make picture smaller first.
# Note this uses a Ramdisk you must set up elsewhere.
im = Image.open(“/var/tmp/”+filename)
im.resize((324,243),Image.ANTIALIAS)
im.save(“/var/tmp/”+filename)
r = requests.post(“https://api.pushover.net/1/messages.json”, data = {
“token”: “you-need-to-get-a-token-from-pushover”,
“user”: “you-need-to-get-a-user-name-from-pushover”,
“device”: “your-device”,
“sound”: “intermission”,
“message”: filename
},
files = {
“attachment”: (filename, open(“/var/tmp/”+filename, “rb”), “image/jpeg”)
})
# Check r for problems – maybe put a delay here?
if r.status_code != 200:
print(“Pushover message failed.”)
else:
print(“Pushover accepted the message.”)
# Now delete the file.
os.remove(“/var/tmp/”+filename)
# Delay to avoid being nasty to Pushover server.
time.sleep(5)
# Main program.
camera.rotation = 0
print(“Running door.py”)
image1, buffer1 = compare()
# Find sunrise and sunset times at two in the morning, and once
# at startup.
schedule.every().day.at(“02:00”).do(sunrise_sunset)
sunrise_sunset()
while (True):
# See if it’s time to get sunrise and sunset.
schedule.run_pending()
image2, buffer2 = compare()
changedpixels = 0
for x in range(0, 100):
for y in range(0, 75):
pixdiff = abs(buffer1[x,y][1] – buffer2[x,y][1])
if pixdiff > difference:
changedpixels += 1
# See if we think something moved.
if changedpixels > pixels:
# See if it’s light enough to take a picture.
now = datetime.datetime.now()
if now > sunrise and now < sunset:
newimage(width, height)
else:
print(“A bit dark at “,now)
image1 = image2
buffer1 = buffer2