Monday 11 November 2019

House Alarm with a Pi: The Smart Door


Following on from my previous post, I decided that for my next Smarthome project it would be a good idea to build a sensor for the front door, that way I would be able to detect whether the door is open or closed.
Now I could have brought a full alarm system but I find it more enjoyable to build my own, I even get to learn something new in the process.

Setting the scene

It was a cold dark evening in late December 2018, it was warm inside and I was slouching on the sofa watching the light dancing around on the living room floor, shining through the slats in the window blind I could just make out the red and blue christmas lights from next door as they gently swayed in the wind…. If only! What really happened was definitely not as interesting.

And so I now present my next post in the series, I should mention here that everything is my own work and also my own opinions, if you don't like it stop reading. On the other hand though if you have ways I could improve then let me know.

The Smart door

I have always wanted a house alarm for when we are out but due to not owning my own home, getting an alarm fitted professionally has never been a viable option, though I still wanted to be notified if the house was broken into when I'm out or on holiday. Thus I only really had two options buy a wireless system or build a system and as I normally do I decided that it would be more fun to build, so I set about researching alarm systems, how they work and design considerations. After a heavy research session that left my head fuzzy and spinning, I finally had enough information to start planning how the design would work in practice.

Alarm Sensors

The basic door and window sensors use a reed switch and act just like a light switch, except these switches use magnets to control whether they are on or off rather than using a human finger. Two types exist on the market "normally open" (NO) and "normally closed" (NC), now "normally closed" sensors allow current to travel when the magnet is within a centimeter of them (just like turning on a light switch) and if you then move the magnet more than a couple of centimetres away they open (turn off the light), on the other hand "normally open" sensors work in the opposite way.

For my system I decided that a normally closed sensor would be the better choice, with the main reason being that the circuit is considered complete and will report an "on" state when the door is closed, then when the door is later opened the circuit will be broken and report an "off" state, additionally to this if the wires are cut it also acts like the door has been opened, due to the circuit being broken.

Now that sounds like a "two birds with one stone" problem to me, except…. As I'm sure anyone with an electrical background would be able to see, this doesn't take into account that the wires could be striped and joined together to create a new unbroken circuit which is unable to report any other state, being bypassed like this means the door would never be reported as opened and we would have effectively disabled the door sensor.
Good for criminals but not so good for us.
The common approach seems to be that the circuit is monitored for a particular voltage by the alarm system, to help with this a resistor is placed either "next to" or "in line with" the door sensor and then when the door sensor is bypassed the alarm system sees the difference due to the resistor being cut out of the loop setting off the alarm.
Which would be really helpful if I had brought an alarm system.

Circuit design

I'm not an electrical engineer and neither am I a circuit designer, so what happened next was lots and lots of trial and error, over the course of about 3 months I designed at least 9 circuits with lots of failures and tested 4 circuits on a breadboard, all of them had issues or problems preventing them from working properly. Most of the issues were related to correctly detecting the voltage difference both with and without the resistor being part of the door sensor and as I'm sure you'll see my electronics knowledge leaves a lot to be desired.

The goal (I had chosen to accept) was simple I had to be able to detect when the circuit was open and closed (this was a door sensor after all), and as previously mentioned the added bonus of using a door sensor was that the open circuit would also trigger when the door was open. I also had to be able to detect when the sensor had been bypassed by placing a resistor in line with the sensor which could be used to detect the voltage difference and this is where my problems started.

Also I didn't have a proper door alarm sensor to hand, so I improvised and pulled apart an old "wirefree door alarm" I had from when the children were little. I tore it apart keeping just the reed switch and the magnet, then I fixed the magnet to the door and the reed switch to the frame with blu tac, after attaching the wires I ended up with something that looked like this.

Yes I know, blu tac! But it works and it's only for testing, I will replace this with something better once I get a proper door sensor.

Design 1

The first design was simple and with very few components it would have been cheap to produce in large numbers it also worked perfectly in the circuit simulator, but unfortunately that's where the benefits end. The design suffered from random radio and people interference (possibly mobile phone related) and was too temperamental to be of any actual use, it had numerous false positives and the fault pin never triggered in any real world testing.


So with my broken circuit, lack of electrical knowledge and a slightly better understanding of what not to do I set to work on the next design.

Design 2

Still not really sure what I was doing I started work on circuit 2. Now design number 2 was another failed attempt to use resistors but after further research I decided that with this attempt I wanted a large voltage difference between the "on" (2V or more) and the "off" (under 1V) states. After testing in two different circuit simulators I decided that this also wouldn't work as I expected in the real world and promptly dropped this attempt.


Designs 3, 4 and 5

With a successful design in the circuit simulators I wired these attempts up on a breadboard and tested them whilst connected to the door sensor. Unfortunately these also suffered from interference and never proved stable enough that they would be of any use.


By this point in time I had started researching voltage dividers and op amps to work around this problem, I had also found something called a zener diode.
Note: A zener diode acts a bit like digital children that push against each other with the strongest winning except in the real world the children are replaced with electric current that changes direction once the voltage goes above a set value.
The problem with this approach was that I didn't have a zener diode and didn't really want to spend money on something that I might give up on, so I persevered reading and designing more circuits as I went.

Further research led me to believe that I could be picking up radio interference on the wire between the sensor and the Pi due to it being made from thin strands, so to combat this I cut the ends off a 5 meter network (cat5) cable and wired it up to the door sensor.
Once I am happy the sensor works as expected I plan on replacing this cable with proper alarm cable.

Design 6, 7, 8

These designs never made it past the circuit simulator as I was never able to get the voltage sent to the GPIO pin to be less than 1 volt in an "off" state and more than 2 volts during an "on" state. After more failed circuits I decided that the only way to get this working as desired was to use transistors (after all they are used in computers with great success). I had previously added transistors to some of the circuits but without truly appreciating their abilities I mistakenly dismissed them as not being useful to my goals, which brings me onto the last circuit.


Design 9

Design number 9 was a bit of an "ah ha" moment, as the flow of electrons and how they reacted in the presence of resistors and transistors finally started to make some kind of sense, lighting up the cobwebs in my head. I tested again in two separate circuit simulators before attempting to build this on a breadboard, once built I also checked for the voltage difference at both the door state and fault pins using a voltmeter.


Happy that things looked good in the real world, I set about connecting the breadboard circuit to both the reed switch on the door and the Pi that had previously been setup for my smart doorbell project.

Now that I had the door sensor wired in, I fired up my laptop and used SSH to connect to the Raspberry Pi, once the connection had been established I checked that I could read both GPIO pins using the command line as follows.
Note: If your not used to using the Linux terminal and bash, the { } brackets in the below command might seem confusing. Put simply they force bash to expand the arguments once for each number, just remember to add commas to separate them.

$ echo "27" > /sys/class/gpio/export
$ echo "22" > /sys/class/gpio/export

$ echo "in" > /sys/class/gpio/gpio27/direction
$ echo "in" > /sys/class/gpio/gpio22/direction

$ cat /sys/class/gpio/gpio{27,22}/value

The commands listed above enable the pins so that they can be accessed as if they were a standard file (making terminal access eaiser), next we set the direction for both pins to "in" as we want to read their state and then we perform the actual read of the current pin state using the cat command.

Having verified that the door pin correctly reads a "1" when the door was closed and "0" when open, I set about testing the fault pin. The fault pin is actually supposed to read "0" when the resistor is in place and a "1" when the wires have been shorted (resistor removed), I was therefore very pleased that testing also confirmed this. With the initial testing completed I setup the following quick and dirty monitor to watch the pin state over a few days, with the intention of detecting false triggers. To make this easier I added a timestamp to the loop, this caused the time to be sent to the log file along with the pin number and of course, I included the pin state also.

#!/bin/bash

echo “27” > /sys/class/gpio/export
echo “in” > /sys/class/gpio/gpio27/direction

echo “22” > /sys/class/gpio/export
echo “in” > /sys/class/gpio/gpio22/direction

while [ 1 ]; do
    date;
    echo -n "pin 27: ";
    cat /sys/class/gpio/gpio27/value;
    echo -n "pin 22: "
    cat /sys/class/gpio/gpio22/value;
done > ./logfile.txt
I saved the script as ./gpio-check and made the script active before starting it in the background with:

#make script executable
$ chmod +x ./gpio-check

#and run in background
$ sudo nohup ./gpio-check &

After a few days I logged back into the Pi to check the times of the triggered pins, first I stopped the script with

$ sudo kill $(pidof sudo)
Then using grep I filtered down the results to a single pin number at a time by adding "-C1" to the grep below command allowed me to view the line above and the line below the matching pin number, this way I could see the date/time that the pin changed as well as the state of both pins, using the following few lines I checked that the fault pin didn't false trigger and also that the door never opened when everyone was in bed asleep.

#default pin should always show "0", we search for "1" to make sure it didn’t happen
$ grep -C1 "pin 22: 1" logfile.txt

#sensor pin should show "1" when the door is closed and "0" when open, 
# so we search for "0" as the door should never open when the house is asleep
$ grep -C1 "pin 27: 0" logfile.txt
With the logs looking clean of phantom triggers I copied my doorbell script that I made in the previous blog post editing the URL and pin number so that it would trigger when the door was opened.
After changing the script to look like the below

#!/usr/bin/python3

import requests
import RPi.GPIO as GPIO

input_pin = 27
url = 'http://example.com/api/frontdoor'

GPIO.setmode(GPIO.BCM)
GPIO.setup(input_pin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)

def button_press(channel):
    state = GPIO.input(channel)
    if state == 1:
        req = requests.post(url, data = "on", headers = {"Content-type": "text/plain", "Accept-Encoding":""})
    return

GPIO.add_event_detect(input_pin, GPIO.BOTH, callback = button_press, bouncetime = 1)

try:
    while True:
        pass
finally:
    GPIO.cleanup()
I saved it as ./frontdor.py, made it executable and copied it to the /usr/local/bin/ folder

$ chmod +x ./frontdoor.py
$ sudo cp ./frontdoor.py /usr/local/bin/
And finally I created a new service file called “frontdoor.service” like this

[Unit]
Description=frontdoor service
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/frontdoor.py
Restart=always

[Install]
WantedBy=multi-user.target

then moved the file to the correct location and started the service like so

$ sudo mv ./frontdoor.service /etc/systemd/system/
$ sudo systemctl enable --now frontdoor.service
If you have been following along you will notice that have I also removed the sleep delay from the doorbell script, this was to try and improve the delays between the event in the real world and the trigger firing in the Pi's world.

After a few weeks of testing I finally decided that the pin checks still weren't quick enough for me and I also wasn't happy with having to create a separate script and service every time I wanted to use another pin, as it would make maintenance awkward and scalability horrible.

And this will bring me nicely onto the topic of my next post where I go in search of something faster. As always until next time, happy tinkering!

No comments:

Post a Comment