Thursday 31 March 2016

Controlling my Door Lock from Android using Bluetooth-LE


Part 3 of My Fancy Bluetooth-LE Operated Door Lock series
Original Nexus 5 image (Fetx2002  / Flickr CC BY 2.0)

This is the last post of my 3 part series on hacking an off-the-shelf electronic lock to be controlled by my Android phone using a Bluetooth capable Arduino board.   Whew!

So the final pieces to this is to create a usable Android App that I can use to control my door lock.

It's easier said than done!

What I ended up creating is an app with four screens, and a notification.



  • Door Control is just a giant animated button that opens and closes the door (if configured).
  • Keypad is pretty much the door lock's keypad on the phone
  • Bluetooth Device is for discovering and pairing with the doorlock
  • Preferences are... well... preferences (just the door code at the moment).
  • Notification


If any of this looks at all useful to you, feel free to grab the code on Github.

It's free, as in beer.

But before you get too excited though, read on (hint: The antagonist of this story is Bluetooth-LE on Android).

Now, I'm not going to get into all the gritty details of how to develop Android Applications, or provide a detailed tutorial on Bluetooth-LE for Android.  There's lots of documentation and existing tutorials for that, and as a last resort the actual source code.  You'll find some links at the bottom of this article.

Ideally, I just wanted some easy way to lock/unlock my door whenever I pressed a button.  Opening the app everytime I want to lock/unlock the door is a pain, so I use a notification as my primary interface.

Click.  Locked.  Click.  Unlocked.  Click.  Locked.  Click.  Unlocked.

What fun!  I could do this all day.

The trickiest part was actually implementing a service to discover, connect to, and communicate with Bluetooth Board.

I based my initial code for the service off of the Android BluetoothLeGatt sample code. The Bluno Sample Code  is also based off of the Android sample code, but I didn't like the code quality, so I created mine from scratch.

The service's (DoorlockService.java) job is to:
  • Scan for the Bluetooth-LE device (the doorlock) in the background
  • Connect the doorlock whenever it's in range
  • Keep track of, and query the state of the doorlock (connected/disconnected + locked/unlocked)
  • Send messages (button presses) to the doorlock
  • Display the notification when in range

Sounds straightforward at least, right?

Not really, no.  You see, Bluetooth-LE on Android is buggy as shit.



Actually, that may not be entirely fair.  The coding is probably fine (I've looked at it), it's just incredibly complicated.  There's are a lot of functionality the Bluetooth-LE code needs to cover.

What makes it over-the-top difficult for the Google developers is the large number of different Bluetooth-LE radios on each and every Android handset, combined with the vast number buggy or broken Bluetooth-LE consumer devices.  Apple by way of comparison, only has to deal with 1/2 of this problem.

Awesome.  Here's a fun list of issues I ran into, along with emoticons that depict how I felt upon discovering each of them.

Bluno uses an UUID in a reserved range.  This isn't an Android issue, but the DFRobot guys didn't appear to have read the BT-LE spec.
BLE filtering doesn’t work for 128-bit UUIDs (at least until very recently).
BLE offloaded filtering doesn't work consistently and misses devices
Not all devices even support offload filtering, and you have to test for it before using certain methods.  Do the docs explain which methods need offloadFiltering and that they will fail if its not present?  Nope.
BluetoothGatt fails repeatedly with ("Register with GATT stack failed.").  Even better is why it fails.  There's a concurrency issue in the Bluetooth stack, and after your device has been scanning for while, you may eventually hit it.


Conclusion

Bluetooth-LE on Android: Very cool once you get it working, but be prepared to spend some time to get it there.  However, there's a huge difference in the implementation pre-Lollipop (5.0).  Had I been writing this for someone other than myself and needed to support more devices, it would have been a much rougher experience.

In the end, I'm pretty happy with my app, but it was more work that I was expecting.

Fin (julianrod/ Flickr CC BY-NC-ND)

Epilogue

If you're still interested in writing a Bluetooth-LE app for Android despite the potential difficulties, here are some links that I would suggest reading to give more of a flavour for the state of Bluetooth-LE on Android.

Official Android Docs on Bluetooth-LE: 

Marc Allison's Tutorial on Bluetooth-LE: 
http://blog.stylingandroid.com/bluetooth-le-part-1/

My code (don't look too closely, or you'll go blind):
https://github.com/jpuderer/Bluedoor

Good article on beacons and 4.3 problems:
Lollipop BLE Overview:
http://www.argenox.com/blog/android-5-0-lollipop-brings-ble-improvements/

Spotty support for BT-LE on older (N5) devices:

Power consumption while scanning:

Also, while developing it's very helpful to be able to interact with your Bluetooth-LE device (be it a Bluno Beetle, or something else).  Nordic Semiconductor makes an absolutely awesome application for debugging Bluetooth-LE devices called nRF Master Control Panel (these guys probably know way more about Bluetooth-LE than I do).

Get it on Google Play

1 comment :

  1. Thanks for a realy good post about this project, i have just orderd a bluno nano and some relays to start building a simular project but i think i skip the app and try to have all the code on the bluno and connect the "pair"-light to a pin and let the bluno look for that signal.

    ReplyDelete