GeoHopper and iBeacons for proximity scripting

[Tweet]

I have been working for a long time to make lights in my house follow me around with accurate proximity detection. I always have my iPhone on me, so I’ve been using Bluetooth to handle this. Originally, I hacked around with Proximity to accomplish this, but ultimately found EventScripts to be a better solution. It still wasn’t as accurate as I wanted it to be.

I started playing with iBeacons. iBeacons use Bluetooth Low Energy (BTLE) and can provide more precise Bluetooth proximity detection than any other method I’ve tried. It’s also easier on mobile device batteries than Bluetooth, which is relevant in this case because a setup like this requires polling and broadcasting on the mobile device.

The technique I’m using can be set up on any web host, depending on what actions you want to trigger. My scenario requires a local web host, so the examples provided will only be of interest to Mac users who have the knowledge (or search engine skills) to set up a local server. It’s also tailored to AppleScript and Indigo, but you can use this method to perform any actions you want on a computer when your phone comes into range.

Choosing your weapon

I’ve been through many iterations at this point. I’m using Bleu Station beacons for the most part, but I learned you can also set up a BTLE-equipped Mac as a transmitting beacon with little effort. I’ve gotten far enough to have written my own prototype apps for triggering my lights, but the most constructive solution I’ve found so far is to use the GeoHopper app.

With both the Bleu beacons and the BeaconOSX method, you can set the power of the signal to control the range of the beacon (within a margin of error1). With the Bleu beacons, you use the iOS setup app to control the power, and with a homebrew Mac-beacon, you can set the transmit power in the code.

Triggering scripts

The trick is to get events to trigger when a device enters the beacon’s region. I’m using GeoHopper on my iPhone to trigger events when I come into or leave the region of a beacon. There’s a GeoHopper Mac app that can trigger scripts when devices enter and exit, but I’ve found it a bit “crashy.” The iOS app has been quite reliable, though.

You can add iBeacons to GeoHopper on your iPhone (also see the url scheme), and when the device running it enters or exits a beacon’s region, it can send JSON payloads to webhooks. This can be used with services like IFTTT, or — as I’ve done — you can set up your own CGI for it.

Writing the CGI

This requires a local web server. I’m not going to go into details on how to set that up, but I highly recommend MAMP Pro as an easy way to handle virtual hosts and settings. I set mine up to handle Ruby scripts as CGIs and built out a handler for the JSON messages.

To make a virtual host under Apache run Ruby scripts, make sure ExecCGI is enabled and add this to the virtual host directory settings:

AddHandler cgi-script .rb

Now you can make any Ruby script executable and have it use the ‘cgi’ library to handle tasks without building out an entire API. Of course, all of this can be done with PHP or whatever language your preferred platform supports.

I built my script to handle query strings first, so I can ping an address such as “http://myserver.com?a=lightson” directly from any web browser and turn lights on. Then I added a handler for the GeoHopper webhook.

The payload that GeoHopper sends looks like this:

{
	"sender":"your.device@email.com",
	"location":"office",
	"event":"LocationExit",
	"time":"2013-09-11 02:03:33 +0000"
}

My script just checks to make sure the sending device is authorized, then takes the event — “LocationEnter” or “LocationExit” — and runs AppleScripts (using osascript) for Indigo based on which event occurred. It currently only handles my default location (“office”), but the “location” key can provide a pivot for setting up different scripts to execute for multiple locations from the same web host.

Example webhook

Since anyone who wants to set this up will have to customize the script to some extent, I’m just providing my version below as an example.

Once you have the CGI set up and a URL for it, see the GeoHopper FAQ for information on adding a web service as a notification.

I’m not providing support for this, but if you know enough about web servers and Ruby to get started and run into specific problems, feel free to drop me a line.

  1. proximity is determined by a ratio of transmit and reception strength, which can fluctuate significantly.