Pssst – want some high tech protection for your home office, or a secret lock for your “workshop” (ok, you got me, it’s actually a dungeon/gaming room) that the kids won’t be able to figure out? We’ve got you covered. Let’s build a DIY smart lock that automatically detects when you’re there, and locks when you’re not.
How does it work? NOBODY KNOWS! Or more specifically, Bluetooth.
Your smartphone is a powerful device that’s constantly revealing information about itself to the outside world; one way it does this is Bluetooth.
In discovery mode, it broadcasts a unique identification number – but even when not specifically allowing itself to be discovered, anything that knows that address can try to ping it. If a response is heard, that would indicate whether it’s in range or not.
We’ll be setting up a Raspberry Pi with a Bluetooth adapter to constantly be on the lookout for when your smartphone is out of range, and when it is, the relay will snap into action and lock the door.
You Will Need
- Raspberry Pi – any model should work since it’s not an CPU intensive task, but I’m using a older model B, and the GPIO pinouts may be slightly different on your model. See the section on board mode below. You’ll also need some basics like a wired Ethernet connection or Wi-Fi configured; plus SD card and micro USB power cable.
- Bluetooth USB adaptor. Adafruit sells a Bluetooth 4.0 BLE module confirmed working (what’s Bluetooth 4.0?), but you should test any you already have lying around before purchasing a new one just for this project. I found an old standard Bluetooth mini adaptor I bought in Japan that appears to work fine. We don’t care about transfer speeds or connection reliability, as all we’re doing is sending out a quick handshake to see if a device is alive and well.
- GPIO breakout board (“cobbler”) and jumper cables. You could work directly from the pins on the Pi, but it’s a lot easier if you have labels on each pin, and they’re only $6 anyway.
- Relay board. You’ve got a wide variety of choices here, and anything will work if it’s designed for use with a microcontroller and can drive at least 12 volts at 5 amps. I’ve used a generic 4-channel board similar to this one for around $5, but I’m going to assume you know how to work yours.
- 12/24V electromagnet lock, though an electronic solenoid lock should also work. The one I purchased has 180KG holding force and comes complete with mounting plates and instructions, for about $35.
- 12/24V power supply. The magnet lock must have a separate power supply – whatever you do, don’t try to pull power for it from the Pi.
- Lock.py Python app, but we’ll write this as we go along.
Working with Bluetooth
Bluetooth is central to this project, so let’s start by installing some Bluetooth support and test our adapter. You can either do this directly from the Pi, or SSH in remotely (how to set up Windows to SSH into you Pi).
sudo apt-get install bluez python-bluez
Insert your dongle if you haven’t already, and let’s have a look at what it’s reporting.
If you have something listed in the output, you’re good to go. Next we’ll use a Python script to poll for nearby Bluetooth devices, and grab the unique device address. We only need to do this once for each device.
wget https://raw.githubusercontent.com/karulis/pybluez/master/examples/simple/inquiry.py python inquiry.py
If you see “0 devices found”, you either don’t have a compatible USB Bluetooth dongle, or your smartphone isn’t discoverable. Don’t despair though: I found I had to actually open the Bluetooth settings page on my iPhone to kick it into discovery mode, then this happened:
Great, now let’s create the first stage of our software that do the detection. Create a Python app called detect.py, and open it with Nano.
Paste in this sample code:
#!/usr/bin/python import bluetooth import time while True: print "Checking " + time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime()) result = bluetooth.lookup_name('78:7F:70:38:51:1B', timeout=5) if (result != None): print "User present" else: print "User out of range" time.sleep(10)
and adjust the following line with your Bluetooth device address:
result = bluetooth.lookup_name('78:7F:70:38:51:1B', timeout=5)
Press CTRL-X and Y to close and save. Run the same code, and you see something like this:
The code should be very simple to understand even if you’ve never touched Python before: it’s scanning for a particular Bluetooth device every 10 seconds, and it prints out a different message depending on whether it’s found or not. Toggle the Bluetooth on your phone to simulate moving in and out of range (probably about 4m in reality). You can decrease or increase the time between scans, but I felt 10 seconds was a reasonable amount of time to potentially have to wait for the door to unlock, which is where we’re going with this whole project after all.
I should add, I don’t know about the power consumption of doing this, but I would assume pinging a device more often would necessarily consume more power. I haven’t seen any obvious performance issues in testing, but if battery life is a serious concern for you, consider having a switch inside your office which activates and deactivates the scan loop, so once you’re inside, you can pause the lock system, then re-activate the scanning when you leave.
Congratulations, you now have a Python app that knows when you’re within range, so we can start to act on that.
GPIO Board Modes
Before continuing, you need to figure out which board mode you’re going to use. There’s no right or wrong answer, it just affects whether you specify the literal pin number or the virtual GPIO pin number.
The default is to use the literal pin number (“board mode”), starting with pin 1 in the bottom left (if looking down at the Pi with USB ports on the right). Pin 2 is just above that.
However, if you have a GPIO breakout (“cobbler”) board, the labels you have are from an alternate mode, called “BCM” (Broadcom SOC channel), and are commonly written with GPIO or P prefixing the number. You don’t strictly need a GPIO breakout – it just makes things easier. If you don’t have a breakout board and don’t want to buy one, use this diagram:
Note that the original model B revision 1, revision 2, and the model B+ and Pi2 all have different pin outs. Refer to this StackExchange question for a diagram correct to your board.
In this project code, I’m using the BCM GPIO numbering system which corresponds to the Adafruit breakout board I have. Minor modifications are needed if you wish to use the literal pin mode.
Wire in a Relay
Attach the breakout board, ensuring that the wire from pins 1 and 2 (the ones in the corner of your Pi) attach to 3v3 and 5V0 on the breakout. You might want to pull out a voltage tester to check this.
Before proceeding, check if anyone else has used your particular relay with the Raspberry Pi (or find one beforehand that you know works). Some may require 5V to activate – but the RPi can only provide 3.3V on the GPIO output pins. By chance, the one I’m using is happy with 3.3V, so I didn’t need any additional circuitry, just the 5V0 to VCC, GND to GND, and GPIO pin 23 for the first relay input.
My previous tutorial on GPIO showed how to wire up a transistor circuit to scale up 3.3V to a full 5V if you need to (in fact, I used the same relay board for that tutorial, but it turns out I didn’t need 5V after all).
No need to wire in the electromagnet yet, as you’ll be able to hear an audible click when the relay fires.
Next up, let’s grab some code to interact with the GPIO ports.
We’ll start by testing outside of Python to confirm everything is working on the ports themselves. Install wiringPi, which gives you some useful command line tools.
git clone git://git.drogon.net/wiringPi cd wiringPi ./build
Once installed, configure GPIO pin 23 to be an output.
gpio -g mode 23 out
Now, do a quick scan of all the ports to confirm
gpio -g readall
You’ll have something similar to this, though yours may be longer on a model B+ or Pi2 since it has more GPIO pins:
This can be a bit confusing at first, but the table is split down the middle and the column order is reversed on each side. On the far left and far right is the BCM pin number. Since we’re using 23, you should see the mode listed now as OUT. This is a useful little command just to get a good idea of what’s going on with all your pins at any point.
To write the pin high or low, just use
gpio -g write 23 1 gpio -g write 23 0
Hopefully, if you have the relay wired correctly, you’ll hear it clicking on and off. If not, don’t continue until you’ve figured out the wiring. Remember, you may need a higher voltage to activate the relay.
Once you’ve confirmed the relay and GPIO is working, add the Python modules for GPIO.
sudo apt-get install python-dev python-rpi.gpio
Now let’s modify our Python app to trigger the relay on or off when the phone is detected. You’ll find the final code at this Gist. Copy the existing detect.py to a new lock.py, and add the following import and setup commands:
import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) RELAY = 23 GPIO.setup(RELAY, GPIO.OUT)
In the IF statement, add a command to either activate or deactivate the relay. Note that your relay may work with either a low or a high signal, so adjust accordingly after testing.
To run this new version, prefix the command with sudo – access to GPIO requires root privileges.
Hooking It Up
Once you’ve confirmed the relay is firing with your proximity sensor, add in your electromagnet lock. On the relay side, bring the 12V positive into the terminal labelled COM (common), then the positive power input from the electromagnet to the NO terminal (normally open, ie. this is normally not connected to the common terminal but will be when you activate the relay).
Join the ground from the power supply and the electromagnet on the GND terminal.
Refer to the fitting instructions that came with your lock; the door needs to be quite thick, and it’s easier if it opens away from the side you want the lock to be on. Mine was the opposite, so I need the L-shaped mounting bracket, as well as an additional bit of wood to increase the door thickness.
This was a proof of concept for me to build on with other projects, and really just to keep prying eyes out of my office when I’m not there – it’s not designed to be a foolproof security system. For that, you’d need a backup battery to keep the power flowing in the event of being cut.
Of course, if someone breaks into your house and goes to the trouble of cutting your power, you’ve probably got the bigger issue of them being a psychopath who’s out to kill you, rather than a casual burglar. You’d also want a physical deadbolt lock in addition to an electronic one, and a really big stick.
Of course, this proximity detection technique using Bluetooth isn’t just limited to an automatic door lock – you could also use it to trigger your garage door opening when you come home, or turn on your home cinema before you walk in the door.
What feature do you think I should add next? Did you have any problems building this? Let me know in the comments and I’ll do my best to help!