Arduino-based Bluetooth Garage Door Opener

Introduction:

After seeing some videos on Youtube of people using their smartphones to open and close garage doors, a rather excited friend came to me to see if I could figure out how to get this working for his garage door.

Thanks to the rather costly keyfob his model of garage door used (Keeloq based, 433.92MHz) and its habit of buttons that died easily, I could see his point. Smartphones are useful for plenty of things, and it isn't too much of a stretch to give them the additional feature of opening and closing a garage door as well. The big question was "How?"

Getting Started:

First things first, I took a look at the videos that had gotten him so interested in the idea of a smartphone controlled garage door. I could see a few immediate issues however.

  • They involved use of a Bluetooth headset
  • They offered little to no actual security

As is well known, bluetooth security on audio devices has never been particularly good. Most have default pin codes of 0000, 1234 or six digit variations of the same. Almost all of these are defined at manufacture and can't be changed, making it trivial to guess. In any case, a four or even six digit pin can be cracked in a very short time with modern computing power available to all.

Using a bluetooth headset limited the actual functionality of the device. It could only be used to toggle, had no way of identifying the connecting device and would also likely be limited in useful range to a few metres at best.

There had to be better options available to the average hardware hacker than this!

The Proposed Solution:

After deciding to make a more secure device than the headphone based one that prompted the whole idea, I began investigating Arduino based solutions. I chose these because of the easy availability of parts, shields and existing code snippets and examples.

The requirements for the device were as follows:

  • Must allow wireless connection from a smartphone, either by WiFi or Bluetooth
  • Must be able to authenticate the connecting device
  • Must authenticate in a manner which provides as little useful information to an eavesdropper as possible
  • Must actually open and close the garage door

Some optional features:

  • Work with multiple different devices, and identify each separately
  • Record a log of triggers based on time and identity of connecting device

Equipment:

In this case, I opted to stick with Bluetooth as a means to wirelessly connect to the device. WiFi is equally as possible, and does come with some advantages in that it could allow true remote control via the internet. On the other hand, it could allow true remote control of the garage door via the internet, which could be a Bad Thing.

  • 1 x Arduino Uno (I had a spare lying around anyway)
  • 1 x Freetronics Relay Control module
  • 1 x SeeedStudio Bluetooth Shield
  • 1 x 12v Automotive Relay (SPST)
  • Other bits and pieces (power supplies, random components where needed, etc)

Putting it all together:

This was pretty simple. Just stack all the shield(s) together and make sure no pins conflict.

I also added an extra protoboard shield to allow me to solder in wires to run between the relay module and the Arduino itself.

In playing around with the SeeedStudio Bluetooth shield, I learnt that it was simply a shield board with a variant of HC-05 Serial Bluetooth module attached to it. Annoyingly, the module itself seemed to have a very limited command set available on it. Very few of the common AT commands would work on it. Also annoying was that very few of the extra pins on the board had been broken out for use.

As a result of the limitations, I found there was no practical way to reset the module to ensure it would both properly disconnect connected devices, and be available for subsequent connections in the future. However, some hunting around on the net for information on the HC-05 module showed that the extra pins on the module could be used to achieve my aims.

Time to get out the soldering iron! I removed the tin-can shielding attached over the module on the board, and began poking around on the extra pins that hadn't been broken out. According to the documentation I found, most modules would trigger a disconnect to all connected devices if PIO0 was given a 3.3v rising pulse. The downside, the Arduino operates at 5v.

To get around this, I used a simple voltage divider with two resistors attached between one of the available digital pins (D9 in my case) and ground. This gave me an additional pin to pulse which would now force all connected bluetooth devices to be disconnected. Excellent!

Software:

While the hardware was working perfectly with some test sketches which would trigger the relay when sent a serial command, this did not make a particularly secure system. The pin could still readily be guessed, and anyone eavesdropping on the communication could simply repeat the commands to trigger the garage door to open or close.

Time to get coding!

The first thing to do was to establish a basic set of commands that could be issued and recognised to ensure both the Arduino and the connecting device would know what state they were in and whether they were fully authenticated. The Arduino was not to allow any commands through until the device had been authenticated, and the commands were to be seeded with random data to ensure they only worked once per connection.

After some research, I opted to use a variation of a Challenge Handshake Authentication Protocol. This provides some level of protection against replay attacks, and pretty much limited the potential window of attack to the time period in which a legitimate user is opening or closing the garage door.

Due to the very limited processing power and available RAM in the MCU, I also opted to use MD5 as the encryption method. While MD5 is considered broken, it still was more than suitable for the level of security I was seeking to achieve and is easy to work with on just about any smartphone environment.

Based on these decisions, I came up with the following workflow for a connecting device:

Smartphone Direction Arduino
Connects -> Accepts Connection
Send Authenticate Request (AUTHENTICATE) -> Generates random string and calculates expected response
Receives Challenge <- Issues random string as challenge (CHALLENGE aljhkjhad78d3ludhakd)
Sends response calculated from shared secret and challenge string (AUTH-RESPONSE -> Receives response and authenticates
Waits for result of challenge response (Display outcome to user) <- Issue response of either ERROR or AUTH-SUCCESS, if error, issue DISCONNECT then trigger physical disconnection

(Assuming successful authentication)

Sends request for command challenge, to calculate one-time variables to prevent replay attacks.

(REQ-COMMANDCHALLENGE)

-> Generates random string and calculates expected response for each known command.
Receives Challenge <- Issues random string as challenge (CMD-CHALLENGE oa948rpojseerjcfvrv)

Sends chosen command calculated from different shared secret and challenge string (CTRLCMD

 

(Commands can be UP, DOWN or TOGGLE)

-> Compares received command string to known possible commands.

Confirm command executed via CMD-SUCCESS or ERROR response, display outcome to user

<- If a valid command, execute and respond with CMD-SUCCESS, else respond with ERROR and force disconnect.

Issue DISCONNECT

-> Force disconnect, reset all buffers and prepare for subsequent connections

For the Arduino, I started writing a basic sketch and adding in the various elements I needed along the way. Not the cleanest way of writing code, but it worked well enough.

The MD5 library I chose was sourced from the Arduino Playground, and is written by Vasilis Georgitzikis, who forked the original code from Scott MacVicar and packaged it up into a nice and very easy to use library. To talk with the Bluetooth module, I used the SoftwareSerial library.

The end result sketch does the job, all commands react exactly as I want them to. However, the use of so many serial lines and strings ended up using pretty much all the RAM available and preventing the sketch from working at all. Fortunately many of these strings were being used for debugging, or were completely static in nature. With the Arduino 1.x IDE, it was simple to transfer most of these strings to PROGMEM using the F() function instead.

 

For the smartphone, I initially tried using the Android development kit to write a native application. As it turns out, Android application development is not the kind of thing you can just pick up instantly having never done it before. The various cobbled together programs I attempted to make ended up crashing more often than not, and that was just in trying to get the device to choose and connect to the correct bluetooth slave device. I opted to try a different approach instead, hopefully one which would let me use an environment I was more used to.

Enter SL4A. SL4A provides a scripting environment for Android devices, and at time of writing supports Python, Perl, JRuby, Lua, BeanShell, JavaScript, Tcl, and shell. In my case it was the support of Python that caught my eye, as I find it pretty easy to work with, and code examples are surprisingly plentiful for working with bluetooth serial connections.

Compared to the Arduino sketch, the code in Python was a lot easier and faster to write. That said, the script I wrote made a whole pile of assumptions and crashes under just about any unexpected conditions. Not surprising given it took me half an hour to write and was purely a proof of concept attempt as the excitable friend was on their way over to visit and I knew he wanted to see the whole thing work.

The Result:

Amazingly, the whole thing actually worked! When the Python script was executed on the phone, it would connect to the bluetooth module of the Arduino (if it was in range), and run through the full authentication process. Once authenticated, the garage door would rumble to life and either open or close. Originally I had planned to have some sort of state detection which would identify if the door was open or closed, but it turned out the door mechanism didn't have any way of identifying this itself, and would figure out what to do by testing whether it could or could not move the door. Without any endstops or similar to tap, it was easier to drop the functionality and just stick with a toggle function in the same way the original keyfobs worked.

Of course, there were some unexpected and rather annoying quirks.

After five or six complete cycles of authentication, command (toggle) and disconnection, the Arduino would stop responding and would require a reset. After hunting through all of my code and finding no obvious bugs, I've come to the conclusion a memory leak or heavy fragmentation must exist somewhere. Further investigation thus far suggests the MD5 library may be the issue, although the liberal use of String() throughout the sketch almost certainly has made the problem worse, if not being responsible in its own right.

Sadly, fixing this problem is well outside my depth, although I might learn how some day!

The Python script itself is ugly and unstable. Not unexpected, but certainly annoying. Taking some more time to refine it and even consider adding a slightly pretty interface is somewhere deep in the future, however I'm more than happy to accept any suggestions or refinements.

Conclusion (for now?):

So, having hit a bit of a dead-end with the Arduino side of things, and having not enough time to work on the SL4A/Python side of things either, I've decided to throw the code to the winds of the Internet, and see what others out there might come up with.

In its current form, the system does actually work. However the stability and crashing issues really need to be resolved before it can be safely implemented in a garage door opener.

I suspect the code, or pieces of it may be useful for other solutions too. One variant of the opener I was considering was a network connected version, which could be accessed via WiFi, or with the appropriate amount of insanity and router port forwarding, could be accessed from anywhere on the internet. In theory so long as the PSKs are not known, cracking the system could be quite difficult (Of course, some solution to prevent bruteforcing of the PSK would be a good idea, but this could be as simple as a timeout to slow things down, or for more complex solutions, a method of reporting attacks to a firewall device to block them upstream).

If you do end up using parts of the code, or if you have any suggestions, ideas or revisions, please let me know using the Guestbook section at the bottom of the page, and please apply credit where credit is due in any code. For anyone planning to make money out of this, my real question would be "Why?", but if you really are that interested, please contact me to discuss options further.

Also, if anyone really wants them, I'm happy to put together some vague schematic diagrams...

Links to both the Arduino sketch and Python script are below:

Arduino Sketch

Python Script

Comments:

Posted by Andy Murray on
Very interesting read! You're getting some interest over on Hack a Day (http://hackaday.com/2014/05/25/arduino-garage-door-opener-is-security-minded/) Maybe one of those comments helps solve the memory leak you're experiencing? Could you post the details of the various bits of hardware you used? What sort of range are you getting with the bluetooth receiver shield you're using?
Posted by Webmaster on
Hi Andy,
The comments over there have been quite useful! I haven't yet had a chance to try the changes out (its somewhere on my to-do list). I suspected the issue was either in my use of String everywhere, or an issue with the MD5 function (or how I was using it).

As for bits of hardware, I used a SeeedStudio BT shield, which contains one of the many variants of HC-05 bluetooth module, a Freetronics relay driver module (http://www.freetronics.com/products/relay4-4-channel-relay-driver-module) and an automotive relay. The smartphone in question was a Samsung Galaxy S3.

Range varied depending on where I put the unit, being 2.4ghz the signal can have trouble getting through some surfaces (particularly wet ones, or ones with metal in them, such as many garage doors). I could still get a few metres out of it even behind the door while it was closed, and at least twice that with the door open. Ideally the unit really needs to be mounted up against the inside of one of the front walls to get good outdoor coverage.
Posted by Mike S. on
Hello,

I found out about your project via Hackaday and I have to say, good job. I did see some things that could be cleaned up within your SL4A Python code and wanted to share it with you.

I noticed that there are about 6 instances where you are creating a dialog alert box, and these could be replaced with a single definition call. Here is an example, and hope the comments section here keeps the spacing. I'll start and end the "code" with triple quotes.

"""
import android
from time import sleep

def GenDialog(title, caption):
droid.dialogCreateAlert(title, caption)
droid.dialogSetPositiveButtonText('Ok')
droid.dialogShow()
droid.dialogGetResponse()

GenDialog('Test Title 1', 'Test Caption 1')

sleep(2)

GenDialog('Test Title 2', 'Caption 2')
"""

This should not only help in cleaning up the code as you are wanting to do, but should also allow you to quickly add other similar dialog boxes with ease.

Side Note: The code was tested using Python 4 Android R5 (Python 2.6.2) on a Google Nexus 7 Tablet.

Hope this helps,
Mike S.
Leave a Reply



(Your email will not be publicly displayed.)