Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
7.2 KiB

  1. Health trackers are the current craze. After I bought a Fitbit, I
  2. wanted to determine what exactly could I do with Fitbit data. Can we
  3. actually learn something from this data that we did not know before?
  4. Most people don't need a watch to tell them that they walked a lot
  5. today or that they got a ton of sleep. As humans we have a pretty good
  6. gauge of our basic physical health. I am interested in figuring out
  7. how we can use data science to look at our health data over a longer
  8. period of time and learn something useful.
  9. Lets look at a few things that people typically use Fitbit data for
  10. before we jump into the weeds.
  11. - Setting Goals
  12. - Motivation
  13. - Tracking Progress
  14. Ever since I bought a Fitbit, I found that I went to the gym a lot
  15. more frequently. Having something which keeps track of your progress
  16. is a great motivator. Not only is your daily steps recorded for your
  17. own viewing, you can share that data with your friends as a
  18. competition. Although I only have 1 friend on Fitbit, I found that was
  19. a good motivator to hit the ten thousand steps per day.
  20. Goals which are not concrete nearly never get accomplished. Simply
  21. saying that "I will get in shape" is a terrible goal. In order for you
  22. to actually accomplish your goals, they need to be quantifiable and
  23. measurable. Rather than saying "I will improve my health this year",
  24. you can say "I will loose ten pounds this year by increasing my daily
  25. step count to fifteen thousand and going to the gym twice a week". One
  26. goal is wishy washy where the other is concrete and measurable. Having
  27. concrete data from Fitbit allows you to quantify your goals and set
  28. milestones for you to accomplish. Along the way to achieving your
  29. goal, you can easily track your progress.
  30. Simply knowing your Fitbit data can help you make some better educated
  31. decisions about your fitness. By comparing your data against what is
  32. healthy you can tweak your lifestyle. For example: if you notice that
  33. you are only getting 6 hours of sleep per night, you can look up the
  34. recommended amount of sleep and tweak your sleep routine until you hit
  35. that target.
  36. Alright, lets do some data science!
  37. ![Tom and Jerry Data Science Meme](media/fitbit/dataScience.jpg)
  38. # Getting The Data
  39. There are two options which we can use to fetch data from Fitbit.
  40. ## Using Fitbit's API
  41. Fitbit has an [OAuth 2.0 web
  42. API](https://dev.fitbit.com/build/reference/web-api/) that you can
  43. use. You first have to register your application on Fitbit's website
  44. to recieve a client ID and a client secret.
  45. I decided to fetch the Fitbit data using an Express app with node.
  46. Fetching the data this way will make it really easy to use on a
  47. website. Node has tons of NPM modules which makes connecting to
  48. Fitbit's API really easy. I'm using Passport which is a pretty common
  49. authentication middleware for Express.
  50. ```javascript
  51. /** express app */
  52. const express = require("express");
  53. /** Manages oauth 2.0 w/ fitbit */
  54. const passport = require('passport');
  55. /** Used to make API calls */
  56. const unirest = require('unirest');
  57. /** express app */
  58. const app = express();
  59. app.use(passport.initialize());
  60. app.use(passport.session({
  61. resave: false,
  62. saveUninitialized: true
  63. }));
  64. var FitbitStrategy = require( 'passport-fitbit-oauth2' ).FitbitOAuth2Strategy;
  65. var accessTokenTemp = null;
  66. passport.use(new FitbitStrategy({
  67. clientID: config.clientID,
  68. clientSecret: config.clientSecret,
  69. callbackURL: config.callbackURL
  70. },
  71. function(accessToken, refreshToken, profile, done)
  72. {
  73. console.log(accessToken);
  74. accessTokenTemp = accessToken;
  75. done(null, {
  76. accessToken: accessToken,
  77. refreshToken: refreshToken,
  78. profile: profile
  79. });
  80. }
  81. ));
  82. passport.serializeUser(function(user, done) {
  83. done(null, user);
  84. });
  85. passport.deserializeUser(function(obj, done) {
  86. done(null, obj);
  87. });
  88. passport.authenticate('fitbit', { scope:
  89. ['activity','heartrate','location','profile']
  90. });
  91. ```
  92. Since our authentication middlware is all set up, we just need to add
  93. the express routes which are required when authenticating.
  94. ```javascript
  95. app.get('/auth/fitbit',
  96. passport.authenticate('fitbit', { scope:
  97. ['activity','heartrate','location','profile'] }
  98. ));
  99. app.get( '/auth/fitbit/callback', passport.authenticate( 'fitbit', {
  100. successRedirect: '/',
  101. failureRedirect: '/error'
  102. }));
  103. app.get('/error', (request, result) =>
  104. {
  105. result.write("Error authenticating with Fitbit API");
  106. result.end();
  107. });
  108. ```
  109. Now that we are authenticated with Fitbit, we can finally make
  110. queries. I created a helper function called queryAPI which attempts
  111. to authenticate if it is not already authenticated and then fetches
  112. the API result from a provided URL.
  113. ```javascript
  114. const queryAPI = function(result, path)
  115. {
  116. return new Promise((resolve, reject)=>
  117. {
  118. if(accessTokenTemp == null)
  119. {
  120. result.redirect('/auth/fitbit');
  121. resolve(false);
  122. }
  123. unirest.get(path)
  124. .headers({'Accept': 'application/json', 'Content-Type': 'application/json', Authorization: "Bearer " + accessTokenTemp})
  125. .end(function (response)
  126. {
  127. if(response.hasOwnProperty("success") && response.success == false)
  128. {
  129. result.redirect('/auth/fitbit');
  130. resolve(false);
  131. }
  132. resolve(response.body);
  133. });
  134. });
  135. };
  136. app.get('/steps', (request, result)=>
  137. {
  138. queryAPI(result, 'https://api.fitbit.com/1/user/-/activities/tracker/steps/date/today/1m.json').then((data)=>
  139. {
  140. if(data != false)
  141. {
  142. result.writeHead(200, {'Content-Type': 'text/html'});
  143. result.write(JSON.stringify(data));
  144. result.end();
  145. }
  146. else
  147. {
  148. console.log("Validating with API");
  149. }
  150. });
  151. });
  152. ```
  153. ## Exporting Data from Website
  154. On [Fitbit's website](https://www.fitbit.com/settings/data/export)
  155. there is a nice page where you can export your data.
  156. ![Fitbit Website Data Export](media/fitbit/fitbitDataExport.png)
  157. The on demand export is pretty useless because it can only go back a
  158. month. On top of that, you don't get to download any heart rate data.
  159. The only data that you do get is aggregated by day. This might be fine
  160. for some use cases; however, this will not suffice for any interesting
  161. analysis.
  162. I decided to try the account archive option out of curiosity.
  163. ![Fitbit Archive Data](media/fitbit/fitbitArchiveData.png)
  164. The Fitbit data archive was very organized and kept meticulous records
  165. of everything. All of the data was in JSON format and was organized
  166. nicely in in separate files labeled by date. Fitbit keeps around 1MB
  167. of data on you per day; most of this data is from the heart rate
  168. sensors. Although 1MB of data may sound intimidating, it is probably a
  169. lot less after you store it in a format other than JSON. Since Fitbit
  170. hires a lot of people for hadoop and SQL development, they are most
  171. likely using [Apache Hive](https://hive.apache.org/) to store user
  172. information on the backend. Distributing the data to users as JSON is
  173. really convenient since it makes learning the data schema very simple.
  174. # Visualizing The Data
  175. # Pulling Outside Data
  176. # Analysis