記事・メモ一覧

default eye-catch image.

OAuth2 implicit grant flow で FitbitAPI の認証をパスするサンプル

これまで、OAuth2 Authenticate code grant flow で FitbitAPI の認証をパスしてデータを取得する事例を書いてきた。implicit grant flow では認証をパスできないのか調べてみた。 Fitbit API の認証を implicit grant flowでパスする際の特徴は以下の通り。 implicit grant flow でFitbitAPI の認証をパスするには、アプリケーションタイプを Client として登録する必要がある。 access tokenの消費期限はユーザが決定する。 refresh tokenを使ってaccess tokenを更新する場合、ユーザの承認が必要となる。 本エントリにて、implicit grant flow で FitbitAPI の認証する方法を step by step で追ってみる。 Authenticate code grant flow と implicit grant flow の違いについて、↓が参考になりました。What is the difference between the 2 workflows? When to use Authorization Code flow? Authenticate code grant flow Authenticate code grant flow は以下の流れだった。 ClientID, ClientSecret から認可コードを取得する 認可コードと accessToken を交換する accessTokenを取得するためには ClientID, ClientSecret を保持しておく必要があった。 本家から図を転載する。 implicit grant flow 対して、implicit grant flow は以下のような流れとなる。 まず、本家からの図の転載。 まとめると次の通り。 ClientIDを使って accessToken を取得する https://www.fitbit.com/oauth2/authorize?state=fx2D6zGcbNVltC15sQlxh4wP8U8HH53%2B &scope=activity+heartrate+location+profile+settings+sleep+social+weight &response_type=token &client_id=xxxxxx &redirect_uri=http%3A%2F%2Fhoge.com%3A8002%2Ftest.php ブラウザ上で認証画面が表示される。この画面はブラウザである必要があり埋め込んでスルーしたりすることはできない。 許可すると、指定したコールバックURLがパラメータ付きで呼び出される。(当然伏字です) http://hoge.com:8002/test.php#scope=weight+location+social+settings+heartrate+sleep+activity+profile &state=fx2D6zGcbNVltC15sQlxh4wP8U8HH53%252B &user_id=xxxxx &token_type=Bearer &expires_in=69483 &access_token=eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NjY5MzMyMzcsInNjb3BlcyI6InJ3ZWkgc nBybyByaHIgcmxvYyByc2xlIHJzZXQgcmFjdCByc29jIiwic3ViIjoiM1FaVllYIiwiYXVkIjoiMjI3V EZKIiwiaXNzIjoiRml0Yml0IiwidHlwIjoiYWNjZXNzX3Rva2VuIiwiaWF0IjoxNDY2ODYzNzU0fQ.oy 0Px-mEauh5Jgw1yS8PF94U37tUW2Q35fbCHKcDFHU ここで得られたaccess_tokenを使って、データアクセスAPIを呼び出す。その際、クエリに含まれるaccess_tokenをAPIにアクセスする度に利用する。クエリに付けるのではなくBASIC認証のヘッダとして付与する。 URLのクエリからaccess_tokenを取得しBASIC認証で利用する。 GET https://api.fitbit.com/1/user/-/profile.json Authorization: Bearer eyJhbGciOiJIUz******************************* ******BybyByaHIgcmxvYyByc2xlIHJzZXQgcmFjdCByc29jIiwic3ViIjoiM1FaVll YIiwiYXVkIjoiMjI3VEZKIiwiaXNzIjoiRml0Yml0IiwidHlwIjoiYWNjZXNzX3Rva2 V**************************************eLtCF0V6IISPinTxy_ZgCLQl1tB0 rEMeqVk4 access_token を使いまわしていると、いずれ access_token の消費期限に到達する。 消費期限に到達した access_token を使ってデータ取得を行うと、以下のようなレスポンスが返ってくる。 { \"errors\": [ { \"errorType\": \"expired_token\", \"message\": \"Access token expired: eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0MzAzNDM3MzUsInNjb3BlcyI6Indwcm8gd2xvYyB3bnV0IHdzbGUgd3NldCB3aHIgd3dlaSB3YWN0IHdzb2MiLCJzdWIiOiJBQkNERUYiLCJhdWQiOiJJSktMTU4iLCJpc3MiOiJGaXRiaXQiLCJ0eXAiOiJhY2Nlc3NfdG9rZW4iLCJpYXQiOjE0MzAzNDAxMzV9.z0VHrIEzjsBnjiNMBey6wtu26yHTnSWz_qlqoEpUlpc\" } ] } ここで、Authenticate code grant flow と同様に refresh_token を使って access_token を更新する必要があるのだが、ドキュメントに記述があるように、implicit grant flow では refresh_token を取得するために client_id を使って再度認証する必要がある。 client_id はアプリケーションにストアすべきデータではなく、ユーザによる操作が必要。 Unlike the Authorization Code Grant Flow, the refresh tokens are not issued with the Implicit Grant flow. Refreshing a token requires use of the client secret, which cannot safely be stored in distributed application code. When the access token expires, users will need to re-authorize your app. また、以下に記述があるように、implicit grant flow における access_token の消費期限は Authenticate code grant flow のそれよりも長めに設定される。アプリケーション側で予め消費期限を設定できるが、最終的には認証画面においてユーザが消費機嫌を決めること値が決まる。 Access tokens from the Implicit Grant Flow are longer lived than tokens from the Authorization Code Grant flow. Users may specify the lifetime of the access token from the authorization page when an application uses the Implicit Grant flow. The access token lifetime options are 1 day, 1 week, and 30 days. Applications can pre-select a token lifetime option, but the user ultimately decides.

default eye-catch image.

FitbitAPI 1分毎の歩数を24時間、1ヶ月分 3次元プロットしてみる

前回、1分毎の消費カロリーを24時間 1ヶ月分 3次元プロットしてみた。 データを眺めていてもイメージがわかないので、前回と同様に歩数データもプロットしてみる。 Rawデータの3次元プロット X軸が日にち、Y軸が00:00:00からの経過時間(分)、Z軸が歩数である。 データはFitbitのtrackerが計測したもので、心拍数と同様に、1分あたり小数点のデータが入っている。 あくまでセンサーが出力した数値がそのまま出てくるのだろうと推測される。 (積分すると、ちゃんと1日の歩数になる。サンプリンク周期の方を1分に固定したために歩数の方が小数点になっているんだろう) 値が0から170-180までのレンジにあることが興味深い。 ジムのマシンでガンガン飛ばしているとき、マシンの数値は75回転/分から80回転/分程度。 1回転するのに2歩必要なのだから、150歩から160歩ということになる。 ちょっと多いような気もするが、だいたいそんなもん。 消費カロリーの3次元プロットと比べると、カロリーを消費していない時間帯にも割と歩いていることがわかる。 消費カロリーがフラットだが、歩数が立ち上がっている領域は、心拍数が低い領域である。 心拍数を上げずに歩いてもカロリーは消費されないことがわかる。 積分値の3次元プロット trackerが出力したRawデータを積分して、累積値を3次元プロットしてみる。 消費カロリーの積分プロットは、基礎代謝のおかげて傾きがゼロになることはないのだが、 座り仕事が続くと、歩数に関しては傾きがゼロになり、上記の図のように階段状になる。 気をぬくと、24時間フラットな図になるだろう。 基礎代謝の分を除けば、概ね、消費カロリーと歩数は相関がありそう(計算してないけど)。 万歩計はとても安くて揃えやすいから、歩数を健康の目標にすることが多いのだろうね。

default eye-catch image.

OAuth2 Implicit Grant Flow とセキュリティ

Implicit Grant Flow を「認証」のための方法として使ってはならない、というが、ちょっと不勉強で理解が曖昧だったので、少し深く理解してみることにした。 参考にしたソースは下記記事 The problem with OAuth for Authentication. 単なる OAuth 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる OAuth2 implicit grant flow 自分が所有する情報に対してアクセスを認めることを認可と呼ぶ。 自分が所有する情報と自分の間に第三者が入らない場合 その鍵を自分が管理することに問題はない アクセスするための鍵を自分自身が管理し、安全が保障されている通信の中で直接鍵を利用できる。 自分が所有する情報と自分の間に第三者(Webシステムやアプリ)が入る場合 Webシステムやアプリに対して自分自身の情報に対するアクセス権を移譲する。 鍵をWebシステムやアプリに渡してしまうと、Webシステムやアプリの脆弱性により鍵そのものが危険にさらされてしまう。 代わりに合鍵(accessToken)を作成し、Webシステムやアプリは合鍵を使って自分自身の情報にアクセスするようにする。 以後、第三者は大元のアクセス権に触れずに、accessToken/refreshTokenを使う。 第三者システムを仮に実装してみると、accessToken/refreshTokenを該当システムのIDに紐付けて保存することで、そのシステム上のログインユーザにリソースオーナーへのアクセス権を付与できる implicit grant flow を認証に使う implicit grant flow を認証に使う、というのは、第三者システムが、リソースオーナーから取得したIDをそのまま第三者システムのIDとして使うことを指す。例えば、GoogleやYahooに保存されたID(emailなど)に対してアクセスを許可するだけで、第三者システムのログインそのものを許可してしまうようなものを指す。 だいたいどんなサービスを作るにしても、最初は知名度が低くて、ユーザ登録などしてくれないことがほとんど。 サービス提供者が考えるのは、GoogleやYahooなどのログインを自システムへのログインに代替できないか、ということ。 自分自身の情報へのアクセスを認めただけなのに、勝手に自分自身のログインであることの証明に使われてしまう、というのが問題。 問題は 第三者システムに悪意はなくて、ただ借りパクしたいだけなら被害はない。 第三者システムが悪い奴で、取得したaccessToken/refreshTokenを使って、本人になりすまして、別の第三者システムにログインしてしまったら...。 別の第三者システム的には、本人からのアクセスなのか、本人になりすましたシステムからのアクセスなのか、区別することができないから、CSRF対策を行って防げる攻撃ではない。

default eye-catch image.

FitbitAPI 24時間消費カロリーを1か月分 3次元プロットしてみる

ふと、そのようなことを思いついた。 Fitbitのtrackerは、消費カロリー、歩数、移動距離、階数、上下移動距離を24時間1分間隔で保存している。 心拍数は「1秒間隔」というエクストリームな保存の仕方だが、アクティビティは常識的な詳細度だ。 1分間隔で保存された各値を積分すると1日分の値になる。 各値と、累積値をそれぞれプロットしてみる。 Rawデータの3次元プロット APIから返されるデータをそのまま3次元プロットしてみた。 心拍数が安静時心拍数に近い領域では消費カロリー値がゼロに近い。たぶんこれが基礎代謝。 日中(ほとんどPC作業...orz)、やはりゼロに近い(1から3の間)。 歩いたり、ジムで運動したときにオレンジの領域がポツポツ現れる。 累積値の3次元プロット 当たり前だが、1日の消費カロリーは瞬間消費カロリーの積分だ。 各値の積分値が1日分の値になるはずだ。1分毎の累積値を計算してプロットしてみた。 ジムで1時間程度の有酸素運動を行うとき、傾きが一気にきつくなり最終的に2700から2800程度に到達する。 サボると2400程度に留まる。 上記は、傾きが小さい(基礎代謝が低い)のを、なんとか運動で補正してカロリーを消費している図。 消費カロリーには基礎代謝が積分で効いてくるので、基礎代謝の上昇量(値)から想像する以上に消費カロリーは上昇することになる(と思う)。 筋肉無いのは悪だ。

default eye-catch image.

FitbitAPI 1ヶ月分の24時間心拍数を3次元プロットしてみる

ふと、タイトルのようなことを思い立った。 詳細度=1分間隔で1日分の心拍数を取得する 月初から月末まで繰り返す X軸=日にち、Y軸=0時0分からの経過時間、Z軸=心拍数となるようにデータを格納する gnuplotのsplotコマンドで格納したデータをプロットする Fitbit API の呼出し制限 思い立つこと20分、コードを作成しAPIサーバからガシガシデータを取得していたのだが、ある時点からデータが取れなくなった。 以下のようなメールがFitbitから届いた。 Hello XXXXXXX, This is an automated courtesy notice. No action is required. Your application, Test Php Application, exceeded the Fitbit API client+viewer rate limit for the users listed below. HOGEHOGE (Hit: 2016/06/18 18:08:38, Reset time: 2016/06/18 18:59:59) If you receive this notice regularly and would like to discuss potentially more efficient ways to use the Fitbit API, please contact api@fitbit.com. Best regards, The Fitbit API team 1分刻みの24時間データを31日分、5回ほどのTry&Errorでリミットに達した。APIから取得したデータをファイルに書き込んでみると、20KBくらいになる。jsonのオーバーヘッドがあるとしても1MBは取っていないはずだ。1時間後にはリミッターが解除されるので、あくまで攻撃対策なのだろうか。 実際、サービスを作るとしたらもっと高頻度にAPIを叩くと思うので、ちょっと大風呂敷広げている割にはリミッターが早いな、という印象。 ちなみに、石狩リージョンのさくらvpsからFitbitAPIに上記のような叩き方をした場合、ターンアラウンドタイムは5秒くらい。結構長い。都度つど取って良いデータではなく、1度とったら使いまわせるように保存しておかないとダメだ。 プロットしてみる プロットしてみた。gnuplotで時系列データを扱うのは割と面倒。 set grid xtics ytics mxtics mytics set datafile separator \',\' set size square set xdata time set timefmt \'%Y-%m-%d\' set format x \'%d\' set xrange [\'2016-05-01\':\'2016-05-31\'] set yrange [0:1440] set zrange [40:200] set xtics 345600 set mxtics 2 set xlabel \"day\" set ylabel \"minutes elapsed [min]\" set zlabel \"heart rate [bpm]\" set terminal png set view 60,30,1,1 set output \"hoge.png\" set ticslevel 0.5 splot \'hoge.csv\' using 1:2:3 w d lc palette title \'Heart Rate every day\' 結果 なんとなく絵になるグラフが出てきただけで、思っていたのと違うな。 手前から奥へ0時0分からの時間経過を表すが、大陸棚みたいになっている部分が睡眠時間。経験的に大陸棚が浅いと体調が悪い。心肺機能を高めると安静時心拍数が下がる(大陸棚が深くなる)ので、結果として体調が良くなる効果がある(と思う)。 奥の方でオレンジ色がポツポツ立ち上がっているのは、週4でジムに通って1時間の有酸素運動をしている部分。有酸素運動1時間というのは慣れても楽な運動ではないのだが、1日のうちの割合でいったら大した率ではないことがわかる。こうして体積を俯瞰してみると、ジムで運動することによる心拍数の増加時間の体積は無視できるような大きさに過ぎない。あぁ、悲しいなぁ。 大陸に上がってから、日によってベースとなる高度が異なることがわかる。例えば12日あたりを境にベースとなる高度が下がっている。カレンダーを遡ってみると、実はこの日は慢性的なストレスを抱える原因になっている出来事にある程度の区切りがついた日でした!すげぇ、心拍数。すげぇ。 心拍数の推移を体積として俯瞰すると、こうして何事もなかったかのようにやり過ごした心身に対するストレスを自覚するきっかけになる(かもしれない)。 ということで、とても面白いので、もう少しFitbitAPIで遊んでみます。

default eye-catch image.

FitbitAPI 詳細な心拍数データを時系列で取得する

FitbitAPI 詳細な心拍数データを時系列で取得する おそらく、Fitbitに蓄えられているデータのうち最も利用価値が高いであろう、詳細な心拍数データを取得してみる。ドキュメントの先頭に以下の記述があり、Personal としてアプリを登録した場合にのみ利用できる。 Access to the Intraday Time Series for personal use (accessing your own data) is available through the \"Personal\" App Type. このデータを使うアプリケーションは、ユーザにとってFitbitに代えがたい価値を提供しなければならない。としている。心拍数データがあってもなくても良いようなクソアプリには使うなよ、ということだろう。非営利目的ならOKとのこと。24時間心拍数を計測可能なウェラブルデバイスが何に応用できるのか、Fitbitもこうして一般に門戸を開いて研究中ということか。超絶便利で画期的なアプリやシステムを考案したら、case-by-caseで商用利用可能の許可が下りるそうだ。 Fitbitという会社の価値は24時間心拍数データの保存にあるということはわかった。 Access to the Intraday Time Series for all other uses is currently granted on a case-by-case basis. Applications must demonstrate necessity to create a great user experience. Fitbit is very supportive of non-profit research and personal projects. Commercial applications require thorough review and are subject to additional requirements. Only select applications are granted access and Fitbit reserves the right to limit this access. To request access, email api@fitbit.com. 実際、データ量が大きいので、現実的な問題としてリソース負荷も大きな理由の一つだろう。 API概要 RESTfulAPI は以下の通り用意されている。何故か dateとend-dateを両方指定できる書式があるが、以下の通り 1日以上のデータを取得することはできない。これはimplicitに\"超絶凄いアプリを考え付いたら複数日分取得できるようにするよ\"ということなのかもしれない。 If your application has the appropriate access, your calls to a time series endpoint for a specific day (by using start and end dates on the same day or a period of 1d), the response will include extended intraday values with a one-minute detail level for that day. GET /1/user/-/activities/heart/date/[date]/[end-date]/[detail-level].json GET /1/user/-/activities/heart/date/[date]/[end-date]/[detail-level]/time/[start-time]/[end-time].json GET /1/user/-/activities/heart/date/[date]/1d/[detail-level].json GET /1/user/-/activities/heart/date/[date]/1d/[detail-level]/time/[start-time]/[end-time].json parameterformatmeanings dateyyyy-MM-ddデータを取得したい日付 end-dateyyyy-MM-ddデータを取得したい日付(dateと同じである必要がある...) start-timeHH:mm(オプション)取得時間を範囲指定する場合、開始時刻を指定できる end-timeHH:mm(オプション)取得時間を範囲指定する場合、終了時刻を指定できる detail-level1sec or 1minデータを1秒区切りで取得するか1分区切りで取得するか。1日は24*60*60=86400秒だ。巨大なレスポンスとなる。 解像度と精度 脈波から心拍数を推測しているとはいえ、心拍数はだいたい1分間に60から120くらいの数値だ。1秒に1回か2回、1Hzか2Hzか、そんな程度の頻度で出現するデータだ。「1秒毎の心拍数」というのは一体どう解釈すれば良いのだろうか。 実際に計測しているのは腕の血流量だが、もしかしたら血流量の変動は心拍数を推測する以上に高頻度に変動する量なのかもしれない。実際、本エントリの末尾に「1秒毎の心拍数」をプロットして貼ってみたが、同一時間でかなりの幅をもっている。単なる歪みなのか、それとも...。detail-level = 1sec を許す fitbit の狙いが知りたい。 レスポンス概要 activities-heart-intradayの下にdatasetという名前で、時刻と心拍数のセットが永遠に繰り返される。 実行例 レスポンスが巨大すぎて実行結果をWordPressのエディタに貼り付けたら編集できなくなった。。代わりにデータをプロットしたので貼っておく。 本当に24時間分の心拍数を1秒区切りで返してくる。ときどき1.5秒になったりする。APIサーバの応答は早い。APIサーバとクライアントの間のネットワーク帯域に依存しそう。PHPがjsonをパースして配列に格納する処理の時間も無視できなさそう。 こんなデータを24時間記録するのにバッテリーが5日も持つなんて!面白くないが最初の2分を載せてみる。こんな調子で24時間心拍数データを記録できるFitbitChargeHRに感謝! [activities-heart-intraday] => Array ( [dataset] => Array ( [0] => Array ( [time] => 00:00:05 [value] => 73 ) [1] => Array ( [time] => 00:00:20 [value] => 74 ) [2] => Array ( [time] => 00:00:30 [value] => 76 ) [3] => Array ( [time] => 00:00:45 [value] => 76 ) [4] => Array ( [time] => 00:00:50 [value] => 74 ) [5] => Array ( [time] => 00:01:05 [value] => 74 ) [6] => Array ( [time] => 00:01:10 [value] => 73 ) [7] => Array ( [time] => 00:01:20 [value] => 72 ) [8] => Array ( [time] => 00:01:30 [value] => 74 ) [9] => Array ( [time] => 00:01:40 [value] => 75 ) [10] => Array ( [time] => 00:01:55 [value] => 75 )

default eye-catch image.

FitbitAPI 心拍数ゾーン毎の滞在時間を取得する

一般的に運動の強度を心拍数の下限と上限の範囲で定義することが多いようだ。Fitbitでは心拍数ゾーンが定義されていて、各ゾーンでの滞在時間数を取得できるようになっている。 API概要 書式は2通り用意されている。 GET /1/user/[user-id]/activities/heart/date/[date]/[period].json GET /1/user/[user-id]/activities/heart/date/[base-date]/[end-date].json parameterformatmeaning dateyyyy-MM-ddperiodパラメータを用いて期間指定する場合にその最終日を指定する period1d, 7d, 30d, 1w, 1m定義された識別子により範囲指定を行う。 base-date]yyyy-MM-dd取得範囲を指定する場合の開始日 end-date]yyyy-MM-dd取得範囲を指定する場合の終了日 他のAPIと同様に1か月を超えて範囲を設定することはできない。 レスポンスのスキーマ heartRateZoneオブジェクト parameterformatmeaning caloriesOutXXX.XXXX該当心拍数ゾーンにおける消費カロリー 有効桁数が考慮されている(と思う) maxXXX該当心拍数ゾーンにおける最大心拍数 minXXX該当心拍数ゾーンにおける最小心拍数 minutesXXX該当心拍数ゾーンにおける滞在時間 nameXXX該当心拍数ゾーンを識別する名称Out of Range,Fat Burn,Cardio,Peakが定義されているようだ。このうち、Fat Burnには脂肪燃焼ゾーン、Cardioには有酸素運動ゾーン、のように日本語訳が付けられている。 restingHeartRate安静時心拍数 その他 parameterformatmeaning dateTimeyyyy-MM-ddデータの日時 restingHeartRate安静時心拍数 実行例 customHeartRateZones という空のオブジェクトが返ってきた。どこかで設定できるのだろうか。 Array ( [activities-heart] => Array ( [0] => Array ( [dateTime] => 2016-06-14 [value] => Array ( [customHeartRateZones] => Array ( ) [heartRateZones] => Array ( [0] => Array ( [caloriesOut] => 1480.75044 [max] => 92 [min] => 30 [minutes] => 1137 [name] => Out of Range ) [1] => Array ( [caloriesOut] => 824.94048 [max] => 128 [min] => 92 [minutes] => 221 [name] => Fat Burn ) [2] => Array ( [caloriesOut] => 585.03432 [max] => 156 [min] => 128 [minutes] => 67 [name] => Cardio ) [3] => Array ( [caloriesOut] => 0 [max] => 220 [min] => 156 [minutes] => 0 [name] => Peak ) ) [restingHeartRate] => 69 ) ) )

default eye-catch image.

FitbitAPI 体重-体脂肪率グラフを作ってみる

せっかく生データを取得できるようになったので、記念にグラフを作ってみることにする。3ヶ月分のデータを2軸のグラフとしてプロットしてみたい。 方針は以下の通り。 認証 djchen/oauth2-fitbitを使用しOAuth2をパスする 過去エントリを参照のこと 取得 BMI/体重/(体脂肪率)取得APIを叩く 期間は3ヶ月分とする。APIを3回叩くことになる。 出力 gnuplotで描画するため、csvとする 体重、体脂肪率はFitbitAPIから得たデータを加工なしにそのまま使う 日付についてFitbitのyyyy-MM-ddからgnuplotのyyyy/MM/ddに変換する 描画 gnuplot。学生のとき以来だな^^ sakura vps の CentOS6 に yum で入れる。便利になったものだ。 gnuplot sakura vpsにgnuplotをインストール。当然 X11とかないのでバッファに出力するだけ。 $ pwd /home/ikuty $ sudo yum install gnuplot gnuplotスクリプトは以下の通り。やはり単にプロットするだけなら R より GnuPlot の方が楽で良い。 set xdata time set timefmt \"%Y/%m/%d\" set datafile separator \",\" set terminal png set output \"plot.png\" set y2tics set y2range [12:22] set multiplot set xlabel \"date\" set ylabel \"weight[kg]\" set y2label \"fat[%]\" set grid plot \"plot.csv\" using 1:2 with lp axes x1y1 replot \"plot.csv\" using 1:3 with lp axes x1y2 外部ファイルを読み込む。 $ gnuplot < gnu.plot 結果 Arialフォントが無いので文字がとても汚いが、グラフ専用ツールなので形にはなる。 朝晩2回計測しているのだがWiththingsとの連携だと1日のうち最後に計測した値だけがFitbitにストアされる。なので、以下のグラフは夜の体重、体脂肪率のグラフということになる。それではハッキリ言って意味がない。 ※体脂肪率が下がっていないのに体重が落ちているのは、筋肉量が落ちている、ということ。カロリー収支のマイナス幅が大きすぎて筋肉量も減らしてしまっているのかも。

default eye-catch image.

FitbitAPI BMI、体重データを取得する

体脂肪率と同様にオプション的な扱いだが、Fitbit では 体重、BMI を記録、閲覧できる。 体脂肪率と体重・BMI の両方を取得するにはそれぞれ異なるAPIを叩く必要があるが、これは計測機器への配慮だろう。体重・BMIと体脂肪率を一度に取得するということは、体重・BMI・体脂肪率が全て揃っていることが前提となり、両方測定できる体組成計があることを前提としなければならない。 体重だけであればかなり安価な計測機器があるはずだ。一方で、安価な体重計とWiFi機能の組み合わせは不釣り合いという事情がある。これもIoTのジレンマかな。 ※実際は、体脂肪率データが一緒に記録された場合、このAPIによって体重、BMI、体脂肪率を1度に取得できる。FitbitAPIは仕様との互換性を保ちつつ便利な方向に拡張される傾向がある。 API概要 体重・BMIを取得するRESTfulAPI は以下の通り3パターン用意されている。 GET /1/user/[user-id]/body/log/weight/date/[date].json GET /1/user/[user-id]/body/log/weight/date/[base-date]/[period].json GET /1/user/[user-id]/body/log/weight/date/[base-date]/[end-date].json parameterformatmeaning dateyyyy-MM-ddデータの日付 base-dateyyyy-MM-dd[period]が指定された場合は指定期間の末尾を指定する。[end-date]が指定された場合は指定期間の最初を指定する。 period1d, 7d, 30d, 1w, 1m取得範囲を指定する。1d=1日, 7d=7日, 30d=30日, 1w=1週間, 1m=1か月。1か月と30日が別に用意されていて親切だ。 end-dateyyyy-MM-dd指定期間の末尾を指定する。 データの取得期間は31日を超えてはならない。単位系はHTTPヘッダに付与したAccept-Languageによる。日本は\"ja-JP\"である。 レスポンス レスポンスのスキーマは以下の通りである。 keyformatmeaning bmiXX.XBMI値、(formatは有効桁数を表すと思われる) dateyyyy-MM-ddデータ日付 weightX.XX体重値 (formatは有効桁数を表すと思われる) logIdログID、ユーザ毎にユニークだが、グローバルにユニークではない timeH:i:s計測時刻 (Time of the mesurement) 計測機器がサポートしない場合は前日の最終時刻。 sourceAria,Withthings,APIなど計測装置、入力経路の識別子、[オプション] API経由で入力すると\"API\"が設定される 1日に数回計測した場合の扱いは計測装置の事情によるようだ。Withthingの場合、複数回計測すると最後の値で上書きされる。朝と夜、2回の計測は必須だと思うが、残念ながら計測装置によって目的を達成できない 実行例 最初の書式を叩いてみた。この日は2回計測したのだがデータは1個だけである。上記で説明したスキーマ以外に体脂肪率も付いてきた。仕様通りbmiとweightについては有効桁数が考慮されている。一方、体脂肪率は考慮されていない。 /1/user/[user-id]/body/log/weight/date/2016-06-14.json Array ( [weight] => Array ( [0] => Array ( [bmi] => 22.01 [date] => 2016-06-14 [fat] => 15.918999671936 [logId] => 1465948799000 [source] => Withings [time] => 23:59:59 [weight] => 67.4 ) ) ) 2個目の書式を叩いてみた。「2016-06-14を末尾として1週間取得する」という意味。 GET /1/user/[user-id]/body/log/weight/date/2016-06-14/1w.json Array ( [weight] => Array ( [0] => Array ( [bmi] => 22.01 [date] => 2016-06-07 [fat] => 14.520999908447 [logId] => 1465343999000 [source] => Withings [time] => 23:59:59 [weight] => 67.4 ) [1] => Array ( [bmi] => 22.27 [date] => 2016-06-08 [fat] => 15.515999794006 [logId] => 1465430399000 [source] => Withings [time] => 23:59:59 [weight] => 68.2 ) [2] => Array ( [bmi] => 22.14 [date] => 2016-06-09 [fat] => 14.659999847412 [logId] => 1465516799000 [source] => Withings [time] => 23:59:59 [weight] => 67.8 ) [3] => Array ( [bmi] => 21.94 [date] => 2016-06-10 [fat] => 14.616000175476 [logId] => 1465603199000 [source] => Withings [time] => 23:59:59 [weight] => 67.2 ) [4] => Array ( [bmi] => 21.94 [date] => 2016-06-11 [fat] => 16.163000106812 [logId] => 1465689599000 [source] => Withings [time] => 23:59:59 [weight] => 67.2 ) [5] => Array ( [bmi] => 22.07 [date] => 2016-06-12 [fat] => 14.592000007629 [logId] => 1465775999000 [source] => Withings [time] => 23:59:59 [weight] => 67.6 ) [6] => Array ( [bmi] => 21.94 [date] => 2016-06-13 [fat] => 14.64999961853 [logId] => 1465862399000 [source] => Withings [time] => 23:59:59 [weight] => 67.2 ) [7] => Array ( [bmi] => 22.01 [date] => 2016-06-14 [fat] => 15.918999671936 [logId] => 1465948799000 [source] => Withings [time] => 23:59:59 [weight] => 67.4 ) ) )

default eye-catch image.

FitbitAPI 体脂肪率を取得する

Fitbitは WiFi体組成計と連携して体重、体脂肪率を記録することができる。Fitbit自体が製造販売しているWiFi体組成計「Fitbit Aria」との連携が一番自然だが、Fitbit以外が製造販売しているメジャーなWiFi体組成計とも連携できる。内部的に体組成計を識別する文字列を一緒に記録している。 運動するきっかけとして「減量のため」というのはかなり上位に来るだろうから、もう少し扱いの重要度を上げても良さそうなのだが、オプション的な扱いである。「Aria」で計測したデータであってもサードパーティ製体重計で計測したデータであっても、機能上は同じように扱われる。 API概要 以下に体脂肪率を取得するRESTfulAPIを示す。RESTfulAPI は3パターン用意されている。なお、別のエントリで紹介するAPIにより、体重、体脂肪率、BMIを一度に取得できる。 GET /1/user/[user-id]/body/log/fat/date/[date].json GET /1/user/[user-id]/body/log/fat/date/[date]/[period].json GET /1/user/[user-id]/body/log/fat/date/[base-date]/[end-date].json ドキュメントには以下の記述がある。\"should not be\"は「すべきではない」ではなく「あってはならない」。1か月以上のデータを1度に取得することはできない。 Range end date when date range is provided. Note: The range should not be longer than 31 days. このAPIに限らず、FitbitAPIは、HTTPヘッダにAccept-Languageを設定することで単位系を設定する。成功すると以下の配列を取得できる。 date計測日時?取得日時? fat計測値、Accept-Languageにより単位を設定する logidユーザ内でユニークなID、グローバルではユニークでない time計測時刻?取得時刻? source計測装置、\"Aria\",\"Withthing\"など 時刻まで記録されることから、1日に数回計測した場合にはそれぞれ記録される。 実行例 PHPによりOAuth2のAuthenticate grant flowをパスしてAPIを叩く散布については過去エントリを参照のこと。なお、Wifi体組成計は Withthings製である。 /1/user/-/body/fat/date/2016-06-13.json この日は2度計測しているのだが... Array ( [fat] => Array ( [0] => Array ( [date] => 2016-06-14 [fat] => 15.9 [logId] => 1465948799000 [source] => Withings [time] => 23:59:59 ) ) ) 1個しか得られなかった。また、時刻がテキトウな値になっている。 純正のAriaなら、ちゃんと2個入って正しい時刻が入るのかもしれない。