Tracking Your iPhone's Location

February 07, 2013

After reading Jack Perkes' article Tracking Your iPhone's Location I decided I wanted to do this with my phone.

Getting a Copy of the Project

I started by forking the Github findi project. There is a sample Heroku project as well, complete with instructions on using Heroku to host your tracking efforts. While I'm not using Heroku I did make use of the bootstrap.py and record_location.py scripts and requirements.txt file from the findi-heroku-example project.

Once I had cloned the fork to my laptop, I copied the contents of the bootstrap.py, record_location.py, and requirements.txt files to my local copy of the project. This way my fork is based on the findi project itself, and not the example Heroku one, but I have the additional files from the example project.

I also added a Python .gitignore to my fork.

Testing on the Command Line

Next I tested findi against my iPhone. findi wrappers Apple's Find My iPhone API and therefore is dependent upon your Apple ID. Once you instantiate a findi object using your Apple ID and Password, you can get a list of all the devices you are tracking. In my case that list contained 5 devices: my laptop, an original iPad, a brand-new iPad Mini, my iPhone, and my work iMac.

Plugging the index of my iPhone (3, in a zero-based list) into the API gave my my current latitude and longitude. Using copy and paste I was able to verify my location on Google Maps.

Modifying the Script for My Device List

The record_location.py script expects a device mapped to your Apple account.

"Fetches an iPhone location from the Apple API and creates a Location Object"
    iphone = FindMyIPhone(APPLE_EMAIL, APPLE_PASSWORD)
    iphone_location = iphone.locate()

Since I have 5 devices I changed the code slightly and hard-coded the index for my iPhone:

"Fetches an iPhone location from the Apple API and creates a Location Object"
    iDevices = FindMyIPhone(APPLE_EMAIL, APPLE_PASSWORD)
    # my phone is the 4th device (index 3) in the list
    iphone_location = iDevices.locate(device_num=3)

By default the script records the UTC time for each location.

date = Column(String, default=datetime.utcnow,
                  onupdate=datetime.utcnow)

I'd rather have the time for my timezone, so I changed the utcnow method to be today:

date = Column(String, default=datetime.today,
                  onupdate=datetime.today)

Finally, in order to execute record_location.py easily from cron, I added a hash-bang to the top of the file:

#!/usr/local/bin/python2.6

My server through WebFaction provides multiple Python versions, the python2.6 specifies the exact version I want.

Setting Up PostgreSQL and Cron

I used WebFaction's control panel to create a new PostgreSQL database, along with a database userid and password. record_location.py expects the Apple Email, Apple Password, and database URL to be in environment variables called APPLE_EMAIL, APPLE_PASSWORD, and DATABASE_URL respectively. At the command prompt I exported these variables, filling in the appropriate values:

$ export APPLE_EMAIL="you@example.com"
$ export APPLE_PASSWORD="lettersAndNumbers"
$ export DATABASE_URL="postgresl://<user>:<password>:@localhost:5432:<databasename>"

Running bootstrap.py with the exports in place created the table needed inside the PostgreSQL database.

Running the record_location.py script now resulted in a new row being inserted into the database.

Cron runs in its own environment and knows nothing about my exports, so I created a .cronvars file to house the required variables, so that I could source them, thereby making them available to the cron environment when the the script was executed. Here's the line I added to my crontab:

* 0 0 0 0 source $HOME/.cronvars; $HOME/pyapps/findi/record_location.py > /dev/null

Initially I set the cron job to run every few minutes so I could see some rows appear in the table and verify that everything was working. Once it was clear that it was working, I changed the time to be 0, or once an hour on the hour.

Fun and Profit

Now I have to wait a while to start collecting data from my phone's location; which by and large is my location. Eventually I'll use TileMill and MapBox to create a map. That will be the subject of a future posting.

Author's profile picture

Mark H. Nichols

I am a husband, cellist, code prole, nerd, technologist, and all around good guy living and working in fly-over country. You should follow me on Twitter.