記事・メモ一覧

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個入って正しい時刻が入るのかもしれない。

default eye-catch image.

RESTFul API 設計の掟

はじめに どうすれば、開発者に喜ばれるAPIを設計できるのか、RESTFulAPI設計のバイブル「Web API Design - Crafting Interfaces that developers love」をまとめてみます。 URLの設計方針 URLはリソースを表す URLはあくまでリソースを表す識別子とし名詞により表現すること リソースを複数形で表現すること。 リソースに対する操作を、動詞を使ったURLで表現しないこと 抽象的な名詞より具体的な名詞が良い より多くの意味を含もうとすると items といったボンヤリした単語になる。 items では、APIの利用者(開発者)にとって意味が分かりづらい。 例えば、以下のようなURLは適切。 /dogs/123 /dogs/123/age /dogs/123/color リソースに対する操作をHTTPメソッドで表現する リソースに対する操作をCRUDの4種類に分類すること CRUDを4種類のHTTPメソッドに対応させること。 操作HTTPメソッド CreatePOST ReadGET UpdatePUT DeleteDELETE リソースとHTTPメソッドの組み合わせは以下のような意味となる。 リソースPOSTcreateGETreadPUTupdateDELETEdelete /dogsdogを新規作成dog一覧を取得全てのdogを一括更新全てのdogを削除 /dogs/1234未定義ID=1234のdogを取得もしID=1234のdogがあれば更新もしID=1234のdogがあれば削除 リソース間の関連を簡潔に表現する 原理主義的に全てのリソースをURLに含めるとURLの階層が深くなりがちである。 /owners/954/dogs/123/red/runninng/park ... リソースとパラメータを分類することでリソースを表すURLの階層を浅く保つ パラメータはリスエストパラメータとして表現する /dogs?owner=954&color=&red&state=running&location=park エラーハンドリングをしっかりする API利用者にとってはAPIはブラックボックスとなる。API開発者は利用者に対してブラックボックス内部で発生した出来事を伝える義務がある。 さらにAPI開発者に対しても以下のようなメリットが生まれる TestFirstな開発を進めやすくなる プロダクトが世に出回ったとき発生したトラブルを追跡しやすくなる 以下の2つでエラーを表現する。 HTTPステータスコード HTTPレスポンス文字列 まず、以下の3つのステータスコードで済ませられないか検討する。 200 - OK 400 - Bad Request 500 - Internal Srver Error 必要であれば、以下から選んで上記に加える。 201 - Created 304 - Not Modified 404 - Not Found 401 - Unauthorized 403 - Forbidden 開発者向けメッセージ、利用者向けメッセージなどを含めるなど、レスポンス文字列を可能な限り充実させること。 バージョニング APIの更新による後方互換性を考慮し、URLにバージョンを含めること。例えば以下の通り。 api/v1/hoge/123 api/2016-06-12/hoge/123 api/hoge/123?v=1.0 旧APIをいつまで保守すべきかについて、以下のような方針を取ること。 少なくとも1個前は保守が必要 保守を停止することに対して開発者の反応を\"1サイクル\"見ること。 ここでいう\"1サイクル\"とは、開発対象による。モバイルアプリなら短いだろうしWebアプリなら長くなる。 リソース範囲を限定する方法 開発者はいつも全てのデータを必要としている訳ではない。以下の二つの戦略で取得したい範囲を限定できるべきである。 Partial Response戦略 あるデータについて常に全フィールドを返すのではなく、対応するデータのみ取得できる手段を提供すること。 リクエストパラメータに取得したいフィールドを付与することで実現すること。 Pagenation戦略 1回あたりの取得量を制限できる手段を提供すること。 例えば 100件のデータのうち、1回あたり20件を表示できるようにしたとき、page=3,limit=20 等をリクエストパラメータに付与できること。 複数のフォーマットをサポートする json、xml、csvなど複数のフォーマットをサポートする 以下のようなURL上の表現方法がある クエリパラメータに付与 : /api/v1/dogs/123?alt=json 拡張子 : /api/v1/dogs/123.json jsonフォーマットが最も普及しているためjsonをデフォルトとする jsonフォーマットを採用する場合、属性はJavaScriptの書式(CamelCase,オブジェクトタイプによる大文字小文字制御など)に従うこと 例外的な扱い HTTP Status Code を利用できない環境 HTTP Status Codeとして常に200=OKを返す レスポンスに StatusCode を表す属性を付与する PUT、DELETE等のHTTPメソッドが利用できない環境 全てをGETリクエストとする 動詞部分をクエリパラメータとする GET /api/v1/dogs?method=put&location=park など 認証 RESTfulAPIの認証で一般的なOAuth2.0を採用すること OAuth2.0と似て非なる認証を採用するのはN.G.なぜなら セキュリティ的に危険だから 開発者が慣れていないから 何度も呼び出さないといけないAPIにしない 開発者がどのようにAPIを使うか想像してAPIを設計すること 呼出回数を軽減することを心がけるkとお 例えば、ほとんどのケースである条件で絞り込んだ結果が求められるのに、必ずAPI経由で絞込みを行わせるなどは避ける 使われ方を想定したデフォルトを設定する

default eye-catch image.

FitbitAPI 日中の詳細なActivityデータを時系列に取得する

秒単位の消費カロリーなど詳細なデータを取得する Fitbit APIにより、秒単位の消費カロリーなど、詳細な分析を行うのに必要なデータを取得することもできる。 Access to the Intraday Time Series for personal use (accessing your own data) is available through the \"Personal\" App Type. 詳細なActivityデータの利用は個人的な利用に限られる ドキュメントの先頭に以下のような注意書きがあり、あくまで個人的な利用を想定しているようだ。商用利用を目的とする場合は api@fitbit.com を通じて許可を得る必要があるようだ。理由は、かなりのデータ量になるためリソースに対するチャージであったり、fitbitの真髄である「24時間秒単位の心拍数」を\"ヒドいアプリに応用されたくない\"というイメージ的なモノであったり、いろいろだと思う。 OAuth2 Authenticate grant flowの一番最初のフェーズにおいてWebアプリを登録する際に、アプリケーションタイプとして「Personal」を選択しないとデータを得られないようだ。 Access to the Intraday Time Series for personal use (accessing your own data) is available through the \"Personal\" App Type. 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を叩いても秒単位の心拍数データを得られなかった。秘伝のタレは簡単には渡してもらえないということか。ドキュメント上は以下のデータに限って詳細データを取得できる。 activities/calories activities/steps activities/distance activities/floors activities/elevation 諸々の注意事項 trackerは7日分のデータを蓄えることができる。それを超えると古いデータから順に失われる。 trackerが7日以上同期されていない場合、辻褄合わせが発生する。抜けた分について、概要は同期されている分だけ、詳細な歩数はゼロ、詳細なカロリーはBMR、EERから計算される。なお、失われた詳細な歩数はFitbitが用意する式によって計算できる。 現在の実装では、ユーザのタイムゾーンにおけるタイムスタンプ値のみ出力する。 trackerデータ欠損時のデータ補完アルゴリズム ちょっと難しくて訳せず... If a user had no Fitbit tracker data for the specific day then the greater of Logged Activities + BMR (for minutes when there is no activity) and the calories calculated from the EER for that day (if EER enabled for this user\'s profile) are taken. In case, there was some data from the tracker for the specific day, that data where available is used and for time where data is unavailable, the BMR is used. If the total is less than 20% greater than BMR then the EER (cals < EER * 0.8) is used. EER never used to calculate calories for today. Fitbitが採用するBMR算出式 身長、体重など簡単に取得できるデータからBMRを推定する計算する式がいくつか存在する。 その中で、Fitbitは MD Mifflin-St Jeor equation を採用している。 9.99 * weightKg + 6.25*heightCm - 4.92*ageYears + 5 (男性) 9.99 * weightKg + 6.25*heightCm - 4.92*ageYears - 161 (女性) 参考)他には以下のようなものがある。それぞれに関して資料を見つけた。 Harris–Benedict式 Owen式 Wang式 Cunningham式 日本人のための式? 母集団が脳梗塞急性期の患者だしn数が30と少ないので俯瞰するに留めるが、推定の精度について議論がある分野のようで、特に欧米人向けの推定式を日本人にそのままあてはめて良いか、という大きな議論があるようだ。 推定式平均値分散二乗平均平方根 Harris–Benedict 式1087980099 Mifflin 式101234829187 Owen 式129051573227 日本人のための簡易式128547083217 Wang 式120832631181 Cunningham 式117527216165 このペーパーの中では、Miffin式は、間接熱量計実測値よりも推定量が下振れする傾向を示している。 Fitbitが採用するEER(TEE,Total energy expenditure) EERとは、Estimated Energy Requirement の略。何のこっちゃであるが、括弧付きで TEE ,Total energy expenditure が付与されているところから、カロリー消費を推定する指標なのだろう。Fitbitは 米国CDC(疾病予防管理センター)のペーパー(An Easy Approach to Calculating Estimated Energy Requirements)のEER推定式を採用している。 式は以下である。 TEE = 864 - 9.72 x age (years) + 1.0 x (14.2 x weight(kg) + 503 x height (meters)) (男性) TEE = 387 - 7.31 x age (years) + 1.0 x (10.9 x weight(kg) + 660.7 x height (meters)) (女性) 取得方法 PHPを使ったOAuth2認証については過去エントリ(djchen/oauth2-fitbitを使ってPHPで簡単にFitbitのデータを取得する)を参考のこと。 詳細データのリソースURIは、過去エントリ(FitbitAPI Activityデータを時系列で取得する)で紹介した概要データのリソースURIに似ている。ただし、詳細データの取得を要求できるリソースは以下に限定される。 activities/calories activities/steps activities/distance activities/floors activities/elevation RESTFul APIは以下の通りである。 GET https://api.fitbit.com/1/user/-/[resource-path]/date/[date]/[date]/[detail-level].json GET https://api.fitbit.com/1/user/-/[resource-path]/date/[date]/1d/[detail-level].json GET https://api.fitbit.com/1/user/-/[resource-path]/date/[date]/[date]/[detail-level]/time/[start-time]/[end-time].json GET https://api.fitbit.com/1/user/-/[resource-path]/date/[date]/1d/[detail-level]/time/[start-time]/[end-time].json 概要データの取得に加え、[detail-level]という項目が追加されている。その値として「1min」か「15min」のいずれかを使用する。 実行例 せっかくなので、日課の1時間ランで絶賛カロリー消費中の時間帯について1分ごとの詳細データを取得してみた。 /1/user/-/activities/colories/date/2016-06-05/1d/1min/time/22:45/23:00.json Array ( [activities-calories] => Array ( [0] => Array ( [dateTime] => 2016-06-05 [value] => 129.13 ) ) [activities-calories-intraday] => Array ( [dataset] => Array ( [0] => Array ( [level] => 3 [mets] => 87 [time] => 22:45:00 [value] => 9.6848402023315 ) [1] => Array ( [level] => 3 [mets] => 88 [time] => 22:46:00 [value] => 9.7961597442627 ) [2] => Array ( [level] => 3 [mets] => 87 [time] => 22:47:00 [value] => 9.6848402023315 ) [3] => Array ( [level] => 3 [mets] => 87 [time] => 22:48:00 [value] => 9.6848402023315 ) [4] => Array ( [level] => 3 [mets] => 89 [time] => 22:49:00 [value] => 9.9074802398682 ) [5] => Array ( [level] => 3 [mets] => 74 [time] => 22:50:00 [value] => 8.2376804351807 ) [6] => Array ( [level] => 3 [mets] => 62 [time] => 22:51:00 [value] => 6.9018402099609 ) [7] => Array ( [level] => 3 [mets] => 66 [time] => 22:52:00 [value] => 7.347119808197 ) [8] => Array ( [level] => 3 [mets] => 64 [time] => 22:53:00 [value] => 7.1244797706604 ) [9] => Array ( [level] => 3 [mets] => 64 [time] => 22:54:00 [value] => 7.1244797706604 ) [10] => Array ( [level] => 3 [mets] => 64 [time] => 22:55:00 [value] => 7.1244797706604 ) [11] => Array ( [level] => 3 [mets] => 66 [time] => 22:56:00 [value] => 7.347119808197 ) [12] => Array ( [level] => 3 [mets] => 66 [time] => 22:57:00 [value] => 7.347119808197 ) [13] => Array ( [level] => 3 [mets] => 64 [time] => 22:58:00 [value] => 7.1244797706604 ) [14] => Array ( [level] => 3 [mets] => 64 [time] => 22:59:00 [value] => 7.1244797706604 ) [15] => Array ( [level] => 3 [mets] => 68 [time] => 23:00:00 [value] => 7.5697598457336 ) ) [datasetInterval] => 1 [datasetType] => minute ) )

default eye-catch image.

AWSにオレオレ証明書を登録する

この記事は「AWSでhttpsを使いたい」という要望に5分で応えるために書きます。難しい話は他のサイトを参考にしてください。 AWSでhttpsを使う際のポイントは以下 証明書はPEM形式でないとN.G.。Apacheで使う形式ではダメ。 2016年6月現在、AWSの各種ダッシュボードからは何故かアップロードできない。 AWS CLIを使ってコマンドラインから証明書をアップロードして登録する。 EC2、Beanstalkのロードバランサに対して、ポート番号443をリスナ登録する際に登録済み証明書を設定する。 前提として、AWS CLIがインストール済みであるものとします。まだの人は過去記事(IAM (Identity and Access Management)ユーザの追加と AWS CLIのセットアップ)を参考にしてインストールを済ませてください。 オレオレ証明書(PEM形式)の作成 サーバ証明書の作成 $ pwd /home/ikuty/cert $ openssl req -new -keyout certkey.pem -text -out cert.req -- 秘密鍵のパスワードを入力 Country Name (2 letter code) [AU]:JP State or Province Name (full name) [Some-State]:Tokyo Locality Name (eg, city) []:Minatoku Organization Name (eg, company) [Internet Widgits Pty Ltd]:OreOreCompany Organizational Unit Name (eg, section) []:Tech Common Name (eg, your name or your server\'s hostname) []:oreore.com Email Address []:ikuty@oreore.com Please enter the following \'extra\' attributes to be sent with your certificate request A challenge password []: An optional company name []: -- 次に証明書の自己署名。 $ openssl req -x509 -in cert.req -text -key certkey.pem -out cert.crt 上記の秘密鍵のパスワードを再入力 秘密鍵からパスワードを削除 $ openssl rsa -in certkey.pem -out certnokey.pem 上記の秘密鍵のパスワードを再入力 AWS CLIを使ってオレオレ証明書をアップロード ※改行は見易さのためです。コピペする時は1行にしてください。 $ pwd /home/ikuty/cert $ aws iam upload-server-certificate --server-certificate-name MyOreOreCertification --certificate-body file://cert.crt --private-key file://certnokey.pem 成功するとjsonが返ってくる。 { \"ServerCertificateMetadata\": { \"ServerCertificateId\": \"**********************\", \"ServerCertificateName\": \"MyOreOreCertification\", \"Expiration\": \"2016-07-11T06:10:41Z\", \"Path\": \"/\", \"Arn\": \"*********************************\", \"UploadDate\": \"2016-06-11T06:17:20.991Z\" } } 確認 EC2のロードバランサに443のリスナを追加する画面で、上で追加したMyOreOreCertificationを選択できるようになります。 Elastic Beanstalkのロードバランサでも同様に MyOreOreCertificationを証明書として443のリスナを追加できるようになります。