Fitbit APIとPythonで心拍数時系列データの取得方法

以前の記事でfitbit APIとPythonにより、心拍数の時系列データの取り出しができることを書きました。

この記事では、簡単にですがそのやり方について書きます。

環境と必要な物

・Python 3.5
・Fitbit製品(心拍数を測れるもの。今のところChargeHRとSurgeのみか?)
・python-fitbit(こちらからダウンロードできます。“download zip”からダウンロードしてください。)

準備すること

※Pythonが実行できるとこまでを前提としておきます。

1.Fitbitのデベロッパーサイトに登録

https://dev.fitbit.com/から登録してください。

2.dev.fitbit.com内、「REGISTER AN APP」からAPIを登録

Application Name, Description, Application Website, Organization, Organization Websiteまではなんでも良いと思うのでテキトーに入力。
僕の場合、Websiteとかはこのブログにしました。

その他の設定:
・OAuth 1.0 Application Type => Browser
・OAuth 2.0 Application Type => Personal ※ここが重要です
心拍数取得にはOAuth2.0が必須で、Personalにしておくと時系列データが取得できるようになります。
メモ:Personalは割と最近実装されたみたいで、少し前まではfitbitにメールしてアクセス許可をもらう必要があったみたいです。

・Callback URL => http://127.0.0.1:8080/ ※ここも重要です
コールバックURLは、OAuth2.0認証の時に必要です。Python-fitbitではCherrypyというモジュールを使っており、そのデフォルトがhttp://127.0.0.1:8080になっています。
もしポート8080が使用中であったりすると認証できないので、その場合は8080を別の値に変えます。もし変えた場合はいくつかモジュールの書き変えも必要です。後ほど説明します。

・Default Access Type => Read & Write

として登録します。

3.python-fitbitに必要なモジュールをインストール

こちらのReadmeにも書かれていますが、以下を実行することでモジュールのインストールができます。
sudo pip install -r requirements/base.txt
sudo pip install -r requirements/dev.txt
sudo pip install -r requirements/test.txt

他にもcherrypyというモジュールが必要なので、インストールしておきます。

ここまでが事前に必要な準備です。

“Access Token”と”Refresh Token”の取得

OAuth2.0認証に必要な”Access Token”と”Refresh Token”を取得できるプログラムがpython-fitbit内にある”gather_keys_oauth2.py”です。

実行には、API登録後に見られる”OAuth 2.0 Client ID”と”Client (Consumer) Secret”が必要です。

以下のように実行すると、アプリ登録画面がブラウザで開き、認証できれば、”You are now authorized to access the Fitbit API!”と表示されます。

Python gather_keys_oauth2.py “OAuth 2.0 Client ID” “Client (Consumer) Secret”
※””はいりません。IDの後にスペースはもちろん必要です。

これで”Access Token”と”Refresh Token”がコンソールに表示されるので、これらを使って心拍数を取得していきます。

もし認証できない場合、8080ポートが使用中である可能性があります。その場合には以下の書き換えが必要です。

・Callback URL => http://127.0.0.1:”8080以外の使われていないポート番号”/

・gather_keys_oauth2.py内:(僕の環境では17行目)redirect_uri=’http://127.0.0.1:8080’のポート番号を上記で設定したポート番号に変更

・cherrypyのポート番号変更方法:gather_keys_oauth2.py内で、”import cherrypy”の後に以下を追加します。

cherrypy.config.update({‘server.socket_host’:’127.0.0.1′,’server.socket_port’:ポート番号})

心拍数の取得

心拍数取得のための命令を記載します。

“Access Token”と”Refresh Token”を使って以下のようにOAuth2.0認証を行います。

auth2_client = fitbit.Fitbit(‘OAuth 2.0 Client ID’, ‘Client (Consumer) Secret’, oauth2=True, access_token=’Access Token’, refresh_token=’Refresh Token’)

後は、データを受け取るだけです。

例1.2015年11月16日1日分の15分刻みのデータが欲しい場合:
fitbit_stats = auth2_client.intraday_time_series(‘activities/heart’, base_date=’2015-11-16′, detail_level=’15min’)

例2.2015年11月1日12時~13時までの1分刻みのデータが欲しい場合:
fitbit_stats = auth2_client.intraday_time_series(‘activities/heart’, base_date=’2015-11-01′, detail_level=’1min’, start_time=’12:00′, end_time=’13:00′)

これでfitbit_statsに辞書データとして心拍数と時刻のデータが書きこまれます。

print(fitbit_stats)を実行すると以下のようなデータが出力されます。例1の出力です。

{‘activities-heart-intraday’: {‘dataset’: [{‘value’: 85, ‘time’: ’00:30:00′}, {‘value’: 73, ‘time’: ’00:45:00′}, {‘value’: 67, ‘time’: ’01:00:00′}, {‘value’: 65, ‘time’: ’01:15:00′}, {‘value’: 65, ‘time’: ’01:30:00′}, {‘value’: 65, ‘time’: ’01:45:00′}, {‘value’: 66, ‘time’: ’02:00:00′}, {‘value’: 62, ‘time’: ’02:15:00′}, {‘value’: 59, ‘time’: ’02:30:00′}, {‘value’: 58, ‘time’: ’02:45:00′}, {‘value’: 58, ‘time’: ’03:00:00′}, {‘value’: 62, ‘time’: ’03:15:00′}, {‘value’: 64, ‘time’: ’03:30:00′}, {‘value’: 61, ‘time’: ’03:45:00′}, {‘value’: 59, ‘time’: ’04:00:00′}, {‘value’: 58, ‘time’: ’04:15:00′}, {‘value’: 60, ‘time’: ’04:30:00′}, {‘value’: 60, ‘time’: ’04:45:00′}, {‘value’: 60, ‘time’: ’05:00:00′}, {‘value’: 64, ‘time’: ’05:15:00′}, {‘value’: 61, ‘time’: ’05:30:00′}, {‘value’: 58, ‘time’: ’05:45:00′}, {‘value’: 60, ‘time’: ’06:00:00′}, {‘value’: 58, ‘time’: ’06:15:00′}, {‘value’: 58, ‘time’: ’06:30:00′}, {‘value’: 62, ‘time’: ’06:45:00′}, {‘value’: 60, ‘time’: ’07:00:00′}, {‘value’: 61, ‘time’: ’07:15:00′}, {‘value’: 59, ‘time’: ’07:30:00′}, {‘value’: 64, ‘time’: ’07:45:00′}, {‘value’: 61, ‘time’: ’08:00:00′}, {‘value’: 57, ‘time’: ’08:15:00′}, {‘value’: 58, ‘time’: ’08:30:00′}, {‘value’: 60, ‘time’: ’08:45:00′}, {‘value’: 61, ‘time’: ’09:00:00′}, {‘value’: 59, ‘time’: ’09:15:00′}, {‘value’: 58, ‘time’: ’09:30:00′}, {‘value’: 62, ‘time’: ’09:45:00′}, {‘value’: 64, ‘time’: ’10:00:00′}, {‘value’: 65, ‘time’: ’10:15:00′}, {‘value’: 64, ‘time’: ’10:30:00′}, {‘value’: 61, ‘time’: ’10:45:00′}, {‘value’: 62, ‘time’: ’11:00:00′}, {‘value’: 63, ‘time’: ’11:15:00′}, {‘value’: 63, ‘time’: ’11:30:00′}, {‘value’: 66, ‘time’: ’11:45:00′}, {‘value’: 68, ‘time’: ’12:00:00′}, {‘value’: 66, ‘time’: ’12:15:00′}, {‘value’: 65, ‘time’: ’12:30:00′}, {‘value’: 62, ‘time’: ’12:45:00′}, {‘value’: 63, ‘time’: ’13:00:00′}, {‘value’: 66, ‘time’: ’13:15:00′}, {‘value’: 73, ‘time’: ’13:30:00′}, {‘value’: 80, ‘time’: ’13:45:00′}, {‘value’: 83, ‘time’: ’14:00:00′}, {‘value’: 78, ‘time’: ’14:15:00′}, {‘value’: 80, ‘time’: ’14:30:00′}, {‘value’: 79, ‘time’: ’14:45:00′}, {‘value’: 80, ‘time’: ’15:00:00′}, {‘value’: 93, ‘time’: ’15:15:00′}, {‘value’: 108, ‘time’: ’15:30:00′}, {‘value’: 89, ‘time’: ’15:45:00′}, {‘value’: 85, ‘time’: ’16:00:00′}, {‘value’: 88, ‘time’: ’16:15:00′}, {‘value’: 74, ‘time’: ’16:30:00′}, {‘value’: 71, ‘time’: ’16:45:00′}, {‘value’: 68, ‘time’: ’17:00:00′}, {‘value’: 71, ‘time’: ’17:15:00′}, {‘value’: 67, ‘time’: ’17:30:00′}, {‘value’: 66, ‘time’: ’17:45:00′}, {‘value’: 64, ‘time’: ’18:00:00′}, {‘value’: 66, ‘time’: ’18:15:00′}, {‘value’: 65, ‘time’: ’18:30:00′}, {‘value’: 64, ‘time’: ’18:45:00′}, {‘value’: 65, ‘time’: ’19:00:00′}, {‘value’: 70, ‘time’: ’19:15:00′}, {‘value’: 97, ‘time’: ’19:30:00′}, {‘value’: 79, ‘time’: ’19:45:00′}, {‘value’: 86, ‘time’: ’20:00:00′}, {‘value’: 82, ‘time’: ’20:15:00′}, {‘value’: 97, ‘time’: ’20:30:00′}], ‘datasetType’: ‘minute’, ‘datasetInterval’: 15}, ‘activities-heart’: [{‘dateTime’: ‘2015-11-16’, ‘value’: {‘customHeartRateZones’: [], ‘restingHeartRate’: 67, ‘heartRateZones’: [{‘min’: 30, ‘caloriesOut’: 1423.58755, ‘max’: 97, ‘name’: ‘Out of Range’, ‘minutes’: 1162}, {‘min’: 97, ‘caloriesOut’: 234.92623, ‘max’: 135, ‘name’: ‘Fat Burn’, ‘minutes’: 43}, {‘min’: 135, ‘caloriesOut’: 0, ‘max’: 164, ‘name’: ‘Cardio’, ‘minutes’: 0}, {‘min’: 164, ‘caloriesOut’: 0, ‘max’: 220, ‘name’: ‘Peak’, ‘minutes’: 0}]}}]}

こんな感じになってるので、時系列データのみにしたり、ヒストグラムにしたりするには適切なデータ処理が必要かと思います。

データ処理

データ処理として色々なやり方があるかと思いますが、僕が作りましたヒストグラム化までを行えるコードを公開しておきます。
2015年11月1日の心拍数をヒストグラム化するコードです。

Access Tokenとかをコピペするのが面倒だったので、”gather_keys_oauth2.py”を参考にOAuth2.0認証部分も含めています。

時系列データのテキストデータ化も行っています。(dataHR-timeseries.txtとして出力)

初心者が書いたコードですので読みづらい部分もあるかもしれませんが、ご了承ください。

参考サイト

https://dev.fitbit.com/docs/heart-rate/
http://pc.atsuhiro-me.net/entry/2014/05/07/022857
http://janliphardt.com/2015/06/14/fitbit-api-and-high-resolution-heart-rate-data/


11 thoughts on “Fitbit APIとPythonで心拍数時系列データの取得方法

  1. When I run “gather_keys_oauth2.py” I get the following error message on the Fitbit web page that loads:

    “The app you’re trying to connect did not provide valid information to Fitbit. Please report this issue to them.
    Developer information: invalid_request – Invalid redirect_uri parameter value”

    I’ve tried changing the port as recommended, but it’s had no effect.

    Anyone got any ideas?

    1. Thank you for your comment.

      I run my python program and got same error today.
      But, I solved this error by trying following revision.
      Please revise “the callback URL” to “http://127.0.0.1:8080/” (last slash is important).

      Additionally, you said that you changed the port number.
      Did you change the port number in “cherrypy” too?

  2. Hey man,

    nice work on the tutorial, so farm it’s been the best one I found.
    I’ve been stuck on gathering access&refresh tokens though.
    After clicking “Allow” on the auth page, instead of getting my keys into console, I get this error: http://imgur.com/C7KjiZa

    Looking forward to hear from you,
    Martin

    1. Thank you for your comment.

      I think the error is caused by “wrong default encoding”.
      Please try the following

      $ python
      >>> import sys
      >>> sys.getdefaultencoding()

      If you get ‘ascii’ as the response, you have to change ‘ascii’ to ‘UTF-8’.

      The default encoding can be changed by making or editing “sitecustomize.py” in “/usr/lib/python2.7/dist-packages/”(perhaps in your environment).
      Please add the following code to “sitecustomize.py”

      import sys
      sys.setdefaultencoding(‘utf-8’)

      And, try the above command again.
      If you get ‘utf-8’ as the response, you maybe run the program.

      1. Hey,

        thanks for a quick reply! I’ve managed to get it working, the problem was in a dodgy oauth library.
        The HR historgram looks great, but now I’m looking to get a timestamped graph of my HR. Did I see correctly in your next blogpost preview that you’ve done this already (http://blog.mr-but-dr.xyz/en/programming/fitbit-python-heartrate/)? If so, is there possibility to see the english version (code)?

        Regards,
        Martin

        1. You can get “dataHR-timeserieses.txt”, which is just the time-series data of HR, if you run the program in “http://blog.mr-but-dr.xyz/en/programming/fitbit-python-heartrate-howto/”.
          Did you see that data? I just use the data and MS Excel to show the time-series HR in the post you stated.

          Thank you.

  3. Hi!

    i’m getting troubles with refresh token. is it supposed to be automatically? i checked all the code. In the makerequest function it is supposed to refresh the token but it keeps me giving the 401 error after 1 hour of the code running

    1. Thank you for your comment.

      As stated in “dev.fitbit.com”, the access tokens have a one-hour lifetime.
      Please visit the page “https://dev.fitbit.com/docs/oauth2/”.

  4. こんにちは
    私は学生でfutbit,pythonを使って分析をしようと思っています。
    IDとSecretは取得できました。そこからプラウザにとんで認証したいのですが、いつも「接続しようとしたアプリは・・・」の画面になり、認証できません。アクセストークン、リフレッシュトークンを取得したいのですが。
    原因を探しているのですが見つからないです。
    pythonは2.7.4で行っているのですが、それがいけないのでしょうか・
    教えていただきたいです。

    1. 質問ありがとうございます。

      この記事のコードをそのまま使用するとその問題が発生するかもしれません。
      以下に更新版がありますので、そちらのコードをご参照いただけないでしょうか?
      http://blog.mr-but-dr.xyz/programming/fitbit-python-heartrate-howto-revise/
      もし、それでもできなければまた連絡ください。
      pythonのバージョンに関しては、恐らく同じコードを使用するとエラーになるところがあるかもしれません。
      ただ、アクセストークンやらの取得までは問題ないと思います。
      この辺は僕も初心者なのでご自身で調べられるなりしていただけると助かります。

      ちなみに、興味本位なのですが、どういったことをされるのでしょうか?
      Fitbitやらのライフロガーデバイスからデータサイエンスするといったような記事はあまり見ないので、
      何かおもしろい話があれば聞きたいな~という感じです。
      なので、口外すると良くない話(卒業論文とか)のためであるのであれば、スルーしていただいて結構です。

Comments are closed.