PythonからFitbit APIを使ってデータを取得する(OAuth2)

昨年2016年にFitbitデビューしました。APIを使って遊んでみたかったのですができていませんでした。 以前この記事でもFitbit APIを使ってみたい的なことを言ったのでこの度やってみました。

この手のやってみた系は日本や海外ブログでいくつか見つけたのですが、最初のトークン取得を別の方法でできたのと、OAuth2トークンを更新してから保存する部分について説明しているところが見当たらず試行錯誤したので共有します。

アプリの登録

ここは他の方が書いていることと大して変わらないためさらっといきます。

  1. https://dev.fitbit.com/appsにアクセス

  2. 「Register new app」タブを選択 f:id:ykarakita:20170319194958p:plain

  3. 設定内容はこんな感じにしました。

    • Application Name * : my3rdFBapp
    • Description * : my3rdFBapp
    • Application Website * : このブログのURL
    • Organization * : none
    • Organization Website * : このブログのURL
    • OAuth 2.0 Application Type * : Personal
    • Callback URL * : http://127.0.0.1:8080/
    • Default Access Type * : Read & Write
  4. agreeしてRegister

登録が完了するとトークンを発行するための情報が表示される。OAuth 2.0 Client IDClient Secretをメモしておく。

トークンの発行

続いて先ほどの作成したアプリのページ下部にある「OAuth 2.0 tutorial page」を選択します。(https://dev.fitbit.com/apps/oauthinteractivetutorial
ここからの手順が結構重要&複雑です。

  1. Authorize

    • Flow type : Authorization Code Flow
    • Fitbit URL : www.fitbit.com(デフォルト)
    • OAuth 2.0 Client ID : メモしたOAuth 2.0 Client ID
    • Client Secret : メモしたClient Secret
    • Redirect URI : http://127.0.0.1:8080/

    Select ScopesExpires In(ms)はデフォルトでOK。(Expires In(ms)は値を変えても反映されなかったのでよくわからないまま)

  2. これらをすべて入力すると、その下に長いURLが生成されている。それをクリックする。 こんな画面が表示されるので許可を選択。 f:id:ykarakita:20170319201317p:plain

    そうするとアクセスできませんの画面が表示されるけど、これでOK。 f:id:ykarakita:20170319201356p:plain

  3. ブラウザのURLのバーをみると、 http://127.0.0.1:8080/?code=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#_=_ 的な感じにリダイレクトされていると思う。 これのcode=の後から#の手前までのコードをコピーする。

  4. コピーしたコードを先ほどのチュートリアルページのCode:の後の入力ボックスにペーストする。 そうするとcurlコマンドが生成されて表示されるのでそれをコピーしてターミナルで実行する。

  5. 成功するとこんな感じのトークンとか他の情報が発行されるのでメモしておく。

{"access_token":"xxxx","expires_in":28800,"refresh_token":"xxxx",
"scope":"settings location sleep social heartrate activity nutrition weight profile",
"token_type":"Bearer","user_id":"XXXXXX"}

エラーが出たらここまでの手順でなにかミスっているのでやり直す。

ここでようやっとPython

以下の環境でやりました。

fitbitモジュールを使います。

$ pip install fitbit
$ vi token.txt

さっきの項目5でコピーしたトークンをまるごと貼り付ける
$ vi app.py

下のコードを貼る。CLIENT_IDCLIENT_SECRETを入れてください。

# -*- coding: utf-8 -*-

import fitbit
import datetime
from ast import literal_eval

CLIENT_ID     = "XXXXXX" # 自分のやつを入れる。
CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 自分のやつを入れる。
TOKEN_FILE    = "token.txt"

tokens = open(TOKEN_FILE).read()
token_dict = literal_eval(tokens)
access_token = token_dict['access_token']
refresh_token = token_dict['refresh_token']

def updateToken(token):
    f = open(TOKEN_FILE, 'w')
    f.write(str(token))
    f.close()
    return

def pound_to_kg(pound):
    kg = pound * 0.454
    return kg

client = fitbit.Fitbit(CLIENT_ID, CLIENT_SECRET,
    access_token = access_token, refresh_token = refresh_token, refresh_cb = updateToken)

#TODAY = datetime.date.today()
TODAY = "2017-02-02"
bodyweight = client.get_bodyweight(base_date=TODAY)
weight = bodyweight["weight"][0]["weight"]
print(pound_to_kg(weight), "kg")

実行する

$ python app.py
xx.xx kg

ポイント

コードの下手さは勘弁してください。ポイントになるのは、fitbit.Fitbit()を呼び出すときのrefresh_cb引数です。

Fitbit APIが採用しているOAuth2は、一定時間を超えるとアクセストークンが失効してしまいます(デフォルトでは8時間)。リフレッシュトークンを使えばアクセストークンを更新することができます。その際にリフレッシュトークンも更新されます。 python-fitbitモジュールではAPI実行時にトークンが失効していた場合はリフレッシュするところまでやってくれます。 しかし保存するところまではやってくれません。先程token.txtに書いたトークンを随時更新していく必要があるのでそこは自分で実装する必要があります。

そこで、refresh_cbに関数を渡しておくと、もしfitbit.Fitbit()を呼び出したときにトークンが失効していた場合は自動的にリフレッシュした後、指定した関数に新しいトークンを渡してくれます。 なのでupdateToken()では新しいトークンを受け取ってファイルに上書きするということをしています。

ちなみにトークン更新後にファイルに上書きするのに失敗した場合、再度トークンを使用するためにはトークン新規発行以外に方法はないので注意しましょう。

このコードではupdateToken()の中でファイルに上書きをしていますが、DBに入れるとかするともっといいと思います。

clientを認証した後は好きにやってあげてください。データの参照も更新もできるはずです。今回コード中でweightを参照していて、Fitbitなのに体重?と思うかもしれませんが、私の場合、体重計はWithingsを使っていてIFTTTを使ってFitbitにも反映されるようにしているので体重が見れます。

ハマったところ

  • CLIENT_IDとかCLIENT_SECRETとかcodeとかaccess_tokenとかrefresh_tokenとかもうよくわからない。
  • OAuth2が全然わからない。
    • アクセストークンとかの発行の仕方がよくわからなかった。
    • access_tokenとrefresh_tokenが発行できたあと、refresh_tokenの使い方がわからなかった。
    • refresh_tokenの使い方はわかったけど、リフレッシュした後の情報をどうやって保存すればいいのかわからなかった。
      • めっちゃ調べた&ソースコードを読んだ。つらかった。時間かかった。
  • トークンが失効するまでに8時間かかるので失効→リフレッシュ→トークンファイル更新を頻繁に試せない。
    • 最後までいいテスト方法がわからず。(だれか教えてください…)

まとめ

これで継続的にデータがとれるようになりました。 今回しんどいこと多かったですがPythonとOAuth2と英語のいい勉強になりました。
やっとAPIを使う準備ができたので今度はFitbit APIを使って何か作ってみようと思います。

体育学部出身エンジニアはDeep Learningを理解できるのか

こんにちは。 久しぶりの投稿となってしまいました。

この度Deep Learningを学習し始める良いチャンスがあったので、これから学習の経過を定期的に記録してみようと思います。 (こういうところで記録しないとすぐくじけそうで。)

ハードルを下げるつもりじゃないですが数学の知識もITの経験もほぼ無いです。 こんな自分でもDLを理解できたら自分でもすごいと思う。

ゴール設定

ゴールは「ゼロから作るDeep Learning』を理解しながら最後まで進められる」にしておきます。

現状

晒すのも恥ずかしいですが私の現在の状態です。

  • 数学について
    • 小学5年生の「割合」でこける。以後、算数・数学に拒否反応が出る。
    • 中学でも数学苦手意識が克服できず文系の道に進むことを志す。高校受験ももちろん数学以外。
    • 高校は英語学科なので数学はおまけ程度。ほとんど勉強した記憶がない。f(x)って黒板に書いてあったな、くらい
    • 大学はスポーツで入れていただいたので受験勉強せず。
    • 体育学部なのでもちろん数学はない。(スポーツ・バイオメカニクスで少し物理やったかな?)

こんな感じで今に至るので、数学の知識は中学くらいで止まっていて苦手意識もまだあります。

  • ITについて
    • エンジニア歴1年10ヶ月
    • インフラ(クラウド)設計・構築・運用をやってきた
    • これまで開発経験無し
    • Python歴は1ヶ月。少しバッチ処理とかが書けるレベル

・・おい本当に大丈夫かよ?

学習予定

『ゼロから作るDeep Learning』をパラパラ見てみましたが、見たこと無い記号とか書き方?がたくさんあるし当たり前に「行列」っていう言葉が出てくるしで、若干ヒヨってます。。。
「ベクトルや行列を一般化したものをテンソルと呼びます。」って説明、14ページ目で出てくるとか正気?

しかしDLの前に数学を学び直すのも結構時間かかりそうなので、DLの勉強を進めながら、数学でわからないことが出てきたらその箇所を並行して勉強していくスタイルでやってみようかなと思います。(そのやり方で限界を感じてきたらまた考えます・・)
数学の教材には、手にとってみてわかりやすそうだった『数IA・IIB・IIICがこの1冊でいっきにわかる もう一度 高校数学』を使います。

まとめ

伸びしろしかなかった。
DLを操れるようになったらスポーツの画像解析とかやって最適なフォームとか導き出せるんでしょグフフとか妄想しながら頑張りたいと思います。
また進捗投稿します。

以上です。