Κυριακή, Ιανουαρίου 12, 2014

Replace Apple's Find My iPhone with a Raspberry Pi

This is a small project that took about two weekends to figure out, but admittedly most of this time was spent on trial-and-error - and there were a LOT of errors.

The aim was to roll out a proof-of-concept clone of Apple's Find My iPhone service. As always, this kind of projects are more about learning about new technologies rather than making something production-ready.

Most of the information here is already available on the web. Jan-Piet Mens is the man to follow for MQTT related stuff.

So, how does this work?

< required intro >
MQTT is a relatively new machine-to-machine protocol for transmitting telemetry data. It is based on a client-server architecture, where the server ("broker") receives messages that clients send ("publish") for certain topics and relays messages to clients that have "subscribed" to certain topics.
< /required intro >

The broker we are going to use is Mosquitto, an excellent piece of open-source software. For extra Nerd Points, Mosquitto will be running on a Raspberry Pi. Start installing!
apt-get install mosquitto mosquitto-clients python-mosquitto

You don't need to do any special configuration on Mosquitto, just make sure it's listening on port 1883. By the way, now would be a good time to forward that TCP port from your router to your Pi.

On the phone side we are going to use MQTTitude, a handy little app that transmits location data in a JSON format using the MQTT protocol. Download and configure through Settings:
  • DeviceID: myPhone
  • Host: this should be your server's public IP/hostname
  • UserID: something
  • Password: something  (yeah, not really important, they just need to be there)
  • Expert Mode Settings:
  • - Subscription: mqttitude/#
  • - Client ID: mq  (also not important, just pick something)
  • - Port: 1883
  • - TLS: off

Alrighty, now you should be good to go. Go back to your shell on the Pi and try to subscribe to messages with the topic mqttitude:
mosquitto_sub -h localhost -p 1883 -t 'mqttitude/#'

Run MQTTitude on your iPhone and tap on the blue pin (center of bottom line). If everything went fine, you should see something like this:
{"tst":"1389527088","lat":"59.430221","_type":"location","lon":"17.951341","acc":"65","batt":"75"}

Actually, this is a very good point you've reached. You can now use MQTTitude on your phones as a replacement for Find My Friends - as long as your friends connect to the same server. You won't have a web interface but the app should be sufficient.

The web interface is the complicated part, mainly because the tricky part is to update your position on Google maps on-the-fly.

There are two options here: the proper one is to set up a web server with Websockets support and load Node.js and some Websockets javascript library and use Websockets to read from webserver + mosquitto.

Sooo... the lazy option we're doing here is a small Python script (stolen with no regrets from Jan-Piet Mens' related article) to write down the location data on a flat text file on the web server's root that will essentially replace Websockets. Ugly lazy hack, yes. Also: works. My version of the script is a bit different - some things just wouldn't work for me.


Keep that script running. It should write data in /var/www/location.current every time your location changes.

You'll need a Google Maps API key (go get it!).

Now you need a web page to display your location on Google Maps. This is where my big disclaimer comes in: this was written by a person with below zero knowledge of Javascript (i.e. me). It's a miracle that it works. No need to comment on how bad the javascript is in this.

Here's what I'm working with:
This will create a page that will open up centered in Stockholm (because that's were I live) and will read that location.current file every 5 seconds and update the marker position.

So, what I ended up with is this:

Congrats! You are now ready to disable Find My iPhone! (don't do that)

Some comments on this:
  • The webpage will take a little bit of work to support more than one user. As I said, proof-of-concept.
  • MQTTitude's battery life is a bit horrible. One way to combat this is to set up Geofences and only update your location in predefined places ("home", "work", etc) and manually.
  • Actually, predefined Geofences are awesome. OpenHAB is a home automation software that supports -among other things- MQTT. That means you can hook it up to your mosquitto broker and have it do stuff (eg turn on lights) every time you return home. This is probably my next weekend project.
I hope this will be a good starting point for some of you.