Sunday, 8 March 2015

Sleep Analysis Using the FitBit API on a Raspberry Pi with Python

A couple of weeks ago I bought myself a Fitbit Charge HR.  This was for all the usual reasons, i.e. being more active, but also for the delicious geek data it could provide via the FitBit API!

This was my original post on using OAUTH1.0 to access the Fitbit API.  I've now "upgraded" to use OAUTH2.0; go to this blog post for a how-to guide. 

(As an aside, this chap DC Rainmaker has written an excellent review of the Charge HR, take a look if you're interested in getting one.  DC Rainmaker is always a good read).

It wasn't 100% easy getting access to data for the API, (less than a previous attempt with Strava), so I thought I'd share some of my learnings.  If you read this thinking, "dude that's easy stuff", remember I'm just a home hobbyist, not a professional, and I'm writing this for other similarly minded people.

Step 1 - Register an Application
The first things to do is to go to the Fitbit developer site and register an application.  This assumes that you are a developer wanting to write an app to access other people's data (with their permission).

Select the "REGISTER AN APP" tab and enter some details.  I specified:
  • Application Name - "Fitbit API Practise"
  • Description - "Using Fitbit data for my personal hobby"
  • Application website - http://pdwhomeautomation.blogspot.co.uk
  • Organisation - Geek Dad
  • Organisation website - http://pdwhomeautomation.blogspot.co.uk
  • Application type - Browser
  • Callback URL - http://pdwhomeautomation.blogspot.co.uk
  • Default Access Type - Read&Write
  • Subscriber - Endpoint URL = http://pdwhomeautomation.blogspot.co.uk <No other data entered>
This created an application and, most importantly, gave me some values for use later in the process.  These are:
  • Client Key - (Also known as the Consumer Key)
  • Client Secret - (Also known as the Consumer Secret)
Log these values somewhere.

Step 2 - Get User Key and Secret
I then needed to authenticate to be able to use the API to get user specific data.  The Fitbit documentation tells you that you need to use OAUTH 1.0 to authenticate users and warns you not to try and build this capability yourself but rather use a pre-built module.

A quick search around the internet led me to a Python Fitbit module that someone has written.  The module is here and the documentation is here. All credit to the author of this.

I downloaded and installed it on my Raspberry Pi using this command git clone https://github.com/orcasgit/python-fitbit.git

(I can't recall installing git so I assume it must come with Raspbian, the OS I'm using).

Now this is where I got a bit stuck.  There are a few blogs on the internet where people talking about using python-fitbit to authenticate and get user specific credentials.  They might be right for some but I just couldn't get it to work for me.  After a modicum of fumbling I struck upon this comment from the fitbit-python help page (RTFM is the best advice always!).


So this advises to use a script called "gather_keys_cli.py" to get the user keys.  I searched on my Pi and it wasn't included in fitbit-python but a quick internet search led me to here on Git, i.e. a sub area of python-fitbit.  I copied the script, pasted it into a Nano editor and then ran it, providing my key and secret from registering my app with FitBit.  Here's a step by step description of what happens.  I've:
  • Broken up the flow to show what you need to do at key stages.
  • Changed all the keys and tokens.  I'm not that stupid!
sudo python gather_keys_cli.py 12345fishalive 78910backagain
** OAuth Python Library Example **

* Obtain a request token ...

RESPONSE
{   u'oauth_callback_confirmed': u'true',
    u'oauth_token': u'1234qwetyuiop1234',
    u'oauth_token_secret': u'111222333aaabbbccc'}

* Authorize the request token in your browser

Verifier:

<Pause in flow>
Verifier?  What the heck's a verifier?  At this point the script stops and asks you to enter this value.

Now this is where this script doesn't help too much but I'd learnt from other failed attempts what to do.  So at this point the script's used your consumer secret and consumer key to obtain a temporary request token.  You then add this temporary token to an authorisation URL and paste it into a browser.  This takes you to a FitBit page where you log in and authorise your app to access your data.

What you need to do is take the URL:
http://api.fitbit.com/oauth/authorize?oauth_token=

...and append the oauth token from the step above, thus giving:
http://api.fitbit.com/oauth/authorize?oauth_token=1234qwetyuiop1234

So you've now authorised the app and you get re-directed to the website you specified when you signed up for a developer account.  Here's what I saw:


So the verifier is the last part of the URL.  Copy it from your browser and paste it into the script.

Verifier: abcde1234abcde1234

* Obtain an access token ...

RESPONSE
{   u'encoded_user_id': u'davedeedozybeakymickandtitch',
    u'oauth_token': u'ymcafuntoplay1234',
    u'oauth_token_secret': u'heisdisco1234heisdisco'}

Done.

So now you have all the keys you need to use the API!  The oauth_token is your user key and the oauth_token_secret is your user secret.  Make sure you log them somewhere!

Step 3 - Get Some API Data
So now for a Python script to access the API.  For a hint on how to do this I used this chap's blog.  Note I couldn't get the authorisation stuff he describes to work but the stuff he does to actually use the Python API wrapper did work for me.

In the script at the bottom of this post you see:

  • Me defining all the keys as constants.
  • Creating an object to use to access the API.  (authd_client._COLLECTION_RESOURCE etc.)
  • Using the API to get activities(authd_client._COLLECTION_RESOURCE('activities') etc.)
Here's it in action:


Now to do something with all that delicious Geek data!!

All the code:


import fitbit

#Constants
CLIENT_KEY = '12345fishalive'
CLIENT_SECRET = '78910backagain'
USER_KEY = 'ymcafuntoplay1234'
USER_SECRET = 'heisdisco1234heisdisco'

authd_client = fitbit.Fitbit(CLIENT_KEY, CLIENT_SECRET, resource_owner_key=USER_
KEY, resource_owner_secret=USER_SECRET)

fitbit_stats = authd_client._COLLECTION_RESOURCE('activities')
print 'Activities:'
print fitbit_stats