Monitor door open/close with HC-SR04

I want to know whenever the door is opened.
I want an email alert when the door open event is captured.
Capture an image from Panasonic IPCam BL-VP104W and attach it to the email so that I know who is entering the apartment.

I was thinking to buy a securifi door/window magnetic reed sensor. However I don’t have any zigbee hub yet. Some wired magnetic sensor also give better result but it need a long wired from the door to where the pi is located. I still prefer using HC-SR04 instead.

The panasonic IPCAM that I own also support motion detection. But it is not giving accurate alarm at all. Most were simply false alarm. A little bit change in lighting source can trigger a ‘movement’. It was not useable, at all.

I think the raspberry pi will actually do the same thing. And it is a success! The solution below doing a very good job.

This simple project took me a full day though.

  • Setup a new pi
  • Setup wifi on pi
  • Setup firewall
  • Looks for all the ingredient
  • Integrate the circuit
  • Write the scripts
  • Trial and error
  • Deploy!

Prerequisites

Setup HC-SR04 and the circuit.

Predefined variables

– script measuring distance with HC-SR04: /root/distance.py
– script looping the distance.py /root/monitor-door.py
– image downloaded from panasonic ipcam saved to /root/capture.jpg
– a temporary text file /tmp/distance.tmp used to prevent false alarm

Adjust the path for your own needed.

Add the distance.py script below to /root folder

update 2016-03-12

There is some false alarm being generated, about one or twice a hour. The sensor just got some wrong reading like this.

102.5 cm
103.6 cm
101.2 cm
41.9 cm
103.2 cm
101.7 cm

The 41.9 is probably a false alarm. The door is hardly opened like 3 seconds then being closed.
Only a ninja or ghost can do that.

If people get in or out, more than one alarm should be detected.

102.5 cm
103.6 cm
101.2 cm
41.9 cm
35.8 cm
22.1 cm
103.2 cm
101.7 cm

A text file is used to solve this. The distance.py is modified to write an integer to a text file. When reading larger than 60cm, write a zero. If value smaller than 60cm, increment the value of the file by 1.

sensor reading value of text file
102.5 cm 0
103.6 cm 0
101.2 cm 0
41.9 cm 1
35.8 cm 2
22.1 cm 3
103.2 cm 0
101.7 cm 0

So, alarm should be triggered only when the value of text file is larger than zero.

For the example above, two alarm were triggered when reading is 35.8 and 22.1. The first occurrence is always skipped to avoid a false alarm.

I’ve also read the current weather by calling forecast.io rest api. If it is raining, a recorded sound of my daughter will be play to remind the rain.

The byebye sound will also play to farewell.

A LED is also added to the circuit, flashing it when distance reading reached the threshold.

import RPi.GPIO as GPIO
import time
import os
import os.path
import base64
import smtplib
import urllib, json

from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

if os.path.isfile('/tmp/distance.tmp') :
        print ""
else :
        os.system('echo 0 > /tmp/distance.tmp')

infile = open('/tmp/distance.tmp','r')
data=infile.read()
infile.close()

outfile = open('/tmp/distance.tmp','w')

d=data.strip()
d=d.replace("\n","")
i=int(d)+1

url = "https://api.forecast.io/forecast/apikey/lat,long"
image='/root/capture.jpg'

to='myself@gmail.com
gmail_user='sender@gmail.com'
gmail_pwd='password'

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
TRIG = 23
ECHO = 24
LED = 16

GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
GPIO.setup(LED, GPIO.OUT)

GPIO.output(TRIG, False)
time.sleep(2)

GPIO.output(TRIG,True)
time.sleep(0.00001)
GPIO.output(TRIG,False)

while GPIO.input(ECHO) == 0:
        pulse_start = time.time()

while GPIO.input(ECHO) == 1:
        pulse_end = time.time()

pulse_duration = pulse_end - pulse_start

distance = pulse_duration * 17150

distance = round(distance , 2)

print  "Distance:",distance, " cm"

if distance < 60:
        if int(d) > 0:
                GPIO.output(LED,True)
                os.system("wget http://192.168.11.10:8080/cgi-bin/camera?resolution=qvga -O /root/capture.jpg")
                response = urllib.urlopen(url)
                data = json.loads(response.read())
                if data['currently']['summary'] == "Rain":
                        os.system("omxplayer /root/raining.mp3")
                os.system("omxplayer /root/byebye.mp3")
                msg = MIMEMultipart()
                msg['Subject']='Door trigger alarm ' + str(distance)
                msg['From'] = gmail_user
                msg['To']=to
                fp=open(image,'rb')
                img = MIMEImage(fp.read(), _subtype="jpg")
                fp.close()
                msg.attach(img)
                smtpserver=smtplib.SMTP('smtp.gmail.com',587)
                smtpserver.ehlo()
                smtpserver.starttls()
                smtpserver.ehlo
                smtpserver.login(gmail_user, gmail_pwd)
                smtpserver.sendmail(gmail_user, to, msg.as_string())
                smtpserver.close()
                GPIO.output(LED,False)
        outfile.write(str(i));
else:
        outfile.write("0");
GPIO.cleanup()
outfile.close()

Add the script monitor-door.py to /root folder.

import time
import os

time.sleep(10)
while (0 < 1):
        time.sleep(3)
        os.system("sudo python /root/distance.py")

The script monitor-door.py will measure the distance per 3 seconds. Adjust the value for your own needed.

To start the monitor-door.py when pi power up, add the line below to /etc/rc.local

python /root/monitor-door.py &

The script will wait 10 seconds for server boot up.

After 12 hours of testing, I find it very accurate. I was notified who and when is leaving/entering my apartment while I am busying working at office. Finally got a clear picture about my home without the need of staring the video feed of those IPCAM. No longer need to make a phone call to confirm with logistic guy whether there are any person in home to pick up their delivery.

Very useful for me.

Version 2, Pending

Sending email with attachment is a bit slow. In version 2 I'll write a simple web page to display the screen capture instead. Then send a push notification to my mobile phone with URL of the screen capture web page. And I don't have to publish the screen capture to third party server (gmail) and have it stored in the pi for privacy.



Leave a Reply

Your email address will not be published. Required fields are marked *