Using R to Work with Fitbit Intraday Data
Andy Jones
I asked for a Fitbit Charge for Christmas. I always enjoy new data sets, and I’m interested in the so called “quantified self” movement, i.e. gathering data about oneself in order to monitor all kinds of things such as blood pressure and heart rate. The Fitbit Charge sounded ideal as it would provide new data for me to play with, and the data would be about my health. For example, I am particularly interested in the new intraday heartrate data available at one minute granularity that Fitbit recently made available via its API.
In the spirit of Christmas giving, alongside the qualifier to my family that I would buy it myself if I didn’t receive it as a Christmas present, I found a new Fitbit Charge under the tree. I immediately wanted to start working with the intraday heart rate data. I thought I would setup R code to interact with the Fitbit API. Being lazy, my initial thought was to Google a way to connect R to the Fitbit API and grab the intraday heart rate data. However, because Fitbit only recently modified the API to provide the intraday data and because the Fitbit API authorization doesn’t seem to conform precisely to the typical OAuth2.0 usage within R, I found I had to pave my own way. This turned out to be quite an adventure, involving working with a number of cool concepts that were new to me within the R environment. For example:
OAuth2.0 security from within R
using HTTP “GET”, “POST” and headers within R
working with JSON files returned by the Fitbit API
encoding, e.g. working with data encoded as base64 and raw bytes
I thought I’d share my struggle here for your enjoyment, to potentially help out anyone else with a Fitbit trying to use R to work with the relatively new Fitbit intraday data and most importantly to see if folks can point us towards a tighter and less hack-y approach.
Background
This post is specific to the Fitbit intraday heart rate data, so for this to be relevant the reader must own a Fitbit Charge or another of their models that monitor heart rate. However, the basic concepts extend to other data as well which are provided by other Fitbit models, e.g. basic data such as number of steps taken per day.
In a nutshell, the Fitbit data stream starts with the Fitbit device on your wrist that captures data about you. The device caches the data and sends to a Fitbit app (in my case on my iPhone) whenever ones synchs the app and the device, The application on the mobile device sends the data to the Fitbit servers. Finally, a Fitbit user can use the official Fitbit website or the Fitbit API to access the data from the Fibit servers.
If one wants to work with the data in a third party environment such as R, one needs to use the Fitbit API to register a FitBit “application”. See diections to do this at https://dev.fitbit.com/docs.
Once you have registered a FitBit “application”“, you will have all the security parameters you need to access the Fitbit data via OAuth2.0 in R, which we’ll show in detail below.
R Code
I used knitr for this write-up to provide the R code and sample output.
Note: I created and then deleted a Fitbit app so I could show all the private Fitbit application parameters that one would not typically show on a blog. I hope this makes for a better exposition.
R Libraries
library(httr) ## for interacting with the Fitbit API over the web
library(base64enc) ## authorization gymnastics requires some encoding
library(jsonlite) ## Fitbit API returns JSON file
library(ggplot2) ## have fun with the data when we finally get it
Fitbit Application Parameters
The Fitit API provides these parameters when one registers an application at https://dev.fitbit.com/apps/new. We’ll use these in the OAuth2.0 gymnastics below
fitbit_authorization_url = "https://www.fitbit.com/oauth2/authorize"
fitbit_access_url = "https://api.fitbit.com/oauth2/token"
fitbit_app <- "testBits"
fitbit_app_redirect_url = "http%3A%2F%2Flocalhost:1410"
fitbit_app_secret = "1117267a9dc748f00631915be59ff409"
fitbit_app_clientID <- "227HVW"
Use Access Token and HTTP to GET our Intraday Heartrate Data
Now that we finally have our access token, we can send a request for our heart rate data using an HTTP GET request, supplying the access token data as a header in the GET statement.
Break the URL up into reasonable chunks.
heartRateUrlPrefix <- "https://api.fitbit.com/1/user/-/activities/heart/date/"
heartRateUrlSuffix <- "/1d/1min/time/00:00/23:59.json"
heartRateUrlDate <- "2015-12-26"
hearRateURL <- paste0(heartRateUrlPrefix,heartRateUrlDate,heartRateUrlSuffix)
hearRateURL
## [1] "https://api.fitbit.com/1/user/-/activities/heart/date/2015-12-26/1d/1min/time/00:00/23:59.json"
If all goes well we will see a Status: 200 in the abbreviated JSON response to the GET
getHeartRateOneDay <- GET(hearRateURL,
add_headers(Authorization = fitbitToken))
getHeartRateOneDay
## Response [https://api.fitbit.com/1/user/-/activities/heart/date/2015-12-26/1d/1min/time/00:00/23:59.json]
## Date: 2016-01-05 05:15
## Status: 200
## Content-Type: application/json;charset=UTF-8
## Size: 43.2 kB
The Fitbit API returns the data in JSON format. It includes a number of fields as we can see below. We need to extract time and heart rate from list object in turn derived from JSON object
listData <- fromJSON(rawToChar(getHeartRateOneDay$content))
str(listData)
## List of 2
## $ activities-heart :'data.frame': 1 obs. of 4 variables:
## ..$ customHeartRateZones:List of 1
## .. ..$ : list()
## ..$ dateTime : chr "2015-12-26"
## ..$ heartRateZones :List of 1
## .. ..$ :'data.frame': 4 obs. of 5 variables:
## .. .. ..$ caloriesOut: num [1:4] 1496 842 291 629
## .. .. ..$ max : int [1:4] 85 119 145 220
## .. .. ..$ min : int [1:4] 30 85 119 145
## .. .. ..$ minutes : int [1:4] 1108 190 30 46
## .. .. ..$ name : chr [1:4] "Out of Range" "Fat Burn" "Cardio" "Peak"
## ..$ value : chr "71.15"
## $ activities-heart-intraday:List of 3
## ..$ dataset :'data.frame': 1374 obs. of 2 variables:
## .. ..$ time : chr [1:1374] "00:00:00" "00:01:00" "00:02:00" "00:03:00" ...
## .. ..$ value: int [1:1374] 64 63 63 63 62 62 62 62 63 64 ...
## ..$ datasetInterval: int 1
## ..$ datasetType : chr "minute"
Upon inspection one can see that the list element we want to focus on to get the minute-by-minute heart rate data is activities-heart-intraday$dataset
myTime <- listData$`activities-heart-intraday`$dataset$time
myValues <- listData$`activities-heart-intraday`$dataset$value
myDateString <- listData$`activities-heart`$dateTime
plotX <- as.POSIXlt(myTime, format = "%H:%M:%S")
plotY <- myValues
myPlot <- ggplot(data = data.frame(x = plotX, y = plotY), aes(x = x, y = y))
myPlot <- myPlot + geom_line()
myPlot <- myPlot + xlab("Time of Day (minutes)") + ylab("Heart Rate (bpm)") +
ggtitle(paste0("Minute Level Heart Rate from Fitbit for: ", myDateString))
myPlot
Conclusion
In a bit of a hack, we’re up and running with the Fitbit intradday data in R.
A lot more to do, e.g. writing code to plot multiple days, to plot an expanding window, applying some cool analysis to the data, combining with other “quantified self” style data, etc.
A lot more to learn about OAuth2.0, e.g. how to refresh the token and how to use the httr library with the Fitbit API in a more conventional manner.
Here’s to a Happy & Healthy 2016!