February 07, 2013
After reading Jack Perkes' article Tracking Your iPhone's Location I decided I wanted to do this with my phone.
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
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
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.
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.
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
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:
My server through WebFaction provides multiple Python versions, the
python2.6 specifies the exact version I want.
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
DATABASE_URL respectively. At the command prompt I exported these variables, filling in the appropriate values:
$ export APPLE_EMAIL="firstname.lastname@example.org" $ export APPLE_PASSWORD="lettersAndNumbers" $ export DATABASE_URL="postgresl://<user>:<password>:@localhost:5432:<databasename>"
bootstrap.py with the exports in place created the table needed inside the PostgreSQL database.
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.
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.