追記
CircleCI で定期的に... (01/04)
CircleCI の Schedule Job を利用して定期的に処理させようと思ったいたんだけど, Access Token の期限切れ対策で, 一日に一回よりも短い周期でスクリプトを動かす必要がありそう.
となると, CircleCI の Schedule Job では, crontab によく書く以下のような書き方をする必要があるんだけど...
# 5 分おきに my-script.rb を実行する */5 * * * * ruby my-script.rb
上記のドキュメントに,
Note: Cron step syntax (for example, /1, /20) is not supported. Range elements within comma-separated lists of elements are also not supported.
と書かれていて, 本案件では, 残念ながら CircleCI は利用出来なさそう.
Access Token の期限切れ対策 (01/03)
Access Token が expire する可能性があるので, Refresh Token を利用して Access Token を再取得しないといけないかもしれない.... 「かもしれない」じゃなくて, Refresh Token を利用して, Access Token の再取得が必須でした.
Fitbit Charge2 はスマートウォッチではなくトラッカー (01/03)
Fitbit Charge2 はスマートウォッチではなく, トラッカーという位置付けのようです.
tl;dr
箱根駅伝で母校を応援しながら, 自分は故障で走れない悔しさをどこかにぶつけたくて Fitbit Web API を pixela を使って可視化 (草を生やす) してみたいと思います.
モチベーション
自分は, 常日頃から Fitbit Charge2 を単純に腕時計, 走る時にストップウォッチと参考程度に心拍数を確認する目的で利用しています.
Fitbit Charge2 フィットネストラッカー Blue Lサイズ [日本正規品] FB407SBUL-JPN
- 発売日: 2016/10/21
- メディア: エレクトロニクス
既に Fitbit Charge3 なる製品もリリースされているようですが, 今のところ Charge2 で間に合っているので買い換える予定はありません. 歩数や距離はイマイチ信頼性は低い印象ですが, バンドを変えられたり出来るので長く使えるスマートウォッチトラッカーなんじゃないかと思っています.
この Fitbit Charge2 (のみならず, 各種 Fitbit 製品) で収集した各種活動量等は REST API を介して取得することが出来ます. せっかくなので, この活動量 (この記事では走行 or 歩行距離のみを扱います) を年間を通して可視化してみたいと思います.
Pixela とは
過去に Fitbit Web API を利用して心拍数を Mackerel を使って可視化する記事を書きました.
似たようなことを, 今度は pixela という草を生やすサービス (ずいぶん乱暴な説明ですいません) を使って可視化してみたいと思います. 草を生やすというのは, Github のプロフィールページに掲載されているグラフです.
pixela は REST API を利用して, このグラフを生成するようなサービスです. 以下のように REST API で全ての操作が可能です.
# ユーザー登録 curl -X POST https://pixe.la/v1/users -d '{"token":"my-token-please-self-generate", "username":"username", "agreeTermsOfService":"yes", "notMinor":"yes"}' # グラフ作成 curl -X POST https://pixe.la/v1/users/username/graphs -H 'X-USER-TOKEN:my-token-please-self-generate' -d '{"id":"my-graph","name":"my-graph","unit":"km","type":"int","color":"shibafu"}' # グラフの設定 Timezone を Asia/Tokyo に設定 curl -X PUT https://pixe.la/v1/users/username/graphs/my-graph -H 'X-USER-TOKEN:my-token-please-self-generate' -d '{"timezone":"Asia/Tokyo"}' # グラフの設定 selfSufficient を increment に設定 curl -X PUT https://pixe.la/v1/users/username/graphs/my-graph -H 'X-USER-TOKEN:my-token-please-self-generate' -d '{"selfSufficient":"increment"}' # データの登録 curl -X POST https://pixe.la/v1/users/username/graphs/my-graph -H 'X-USER-TOKEN:my-token-please-self-generate' -d '{"date":"20200102","quantity":"5"}' # データの削除 curl -X DELETE https://pixe.la/v1/users/username/graphs/my-graph/20200102 -H 'X-USER-TOKEN:my-token-please-self-generate' # 登録データの取得 curl -X GET https://pixe.la/v1/users/username/graphs/my-graph/stats -H 'X-USER-TOKEN:my-token-please-self-generate
ドキュメントが充実しているので, シュッと使い始めることが出来ます.
Fitbit の Web API
OAuth で認証する部分がややこしいですが, アクセストークンを取得してしまえば, curl なり, 各種言語の HTTP ライブラリを利用して活動量を JSON で取得出来るようになります.
今回は, 以下の記事を参考にさせて頂いて, OAuth 認証を設定し, Ruby スクリプトも参考にさせていただきました. 有難うございます.
作ったもの
リポジトリ
活動量の取得
Fitbit Web API から, 活動量を取得する部分は以下の通りです.
class FitBitActivity def initialize(date) @base_url = 'https://api.fitbit.com/1/user/-' @request_header = { 'Authorization' => "Bearer #{ENV['FITBIT_ACCESS_TOKEN']}" } @date = date end def method_missing(resource) send("fetch_resource", resource, @date) end private def fetch_error(e) puts 'Error: ' + e['errors'][0]['errorType'] exit 1 end def fetch_resource(resource, date) activity_url = "#{@base_url}/activities/#{resource}/date/#{date}/1d.json" res = fetch(activity_url) res["activities-#{resource}"][0]['value'] if res.has_key?("activities-#{resource}") fetch_error(res) if res.has_key?('success') end def fetch(url) uri = URI.parse(url) https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true req = Net::HTTP::Get.new(uri.request_uri, @request_header) begin res = https.request(req) JSON.parse(res.read_body) rescue => ex puts 'Error: ' + ex exit 1 end end end
Activity から以下のような歩数, 距離数, カロリー毎に値を取得することを想定しています.
activities/calories activities/steps activities/distance activities/floors activities/elevation
例えば, 前日の消費カロリー数を取得したい場合には, 以下のように書きます.
d = Date.today - 1 puts FitBitActivity.new(d.strftime("%Y-%m-%d")).calories
実行すると, 以下のように出力されます.
$ ruby my-activity.rb
1608
単位はキロカロリーとなります.
同様に歩数を取得したい場合には, 以下のように書きます.
d = Date.today - 1 puts FitBitActivity.new(d.strftime("%Y-%m-%d")).steps
実行すると, 以下のように出力されます.
$ ruby my-activity.rb
4230
単位は歩数となりますな. 冬休みと故障中ということで歩数が全然伸びていないのが切ないですね...
草を生やしてみると...
サンプルのスクリプトを使って実際に草を生やしてみたのが以下の通りです.
パラメータに mode=short
を付けると以下のようになります.
おおー, いい感じです.
そして, CircleCI
毎日一回, このスクリプトを叩かせたい. となると思いつくのは Lambda + CloudWatch Events の組み合わせなんですが, とりあえず CircleCI で転がしてみようと思います.
version: 2.1 executors: default: docker: - image: circleci/ruby:2.6.5 jobs: check: executor: name: default steps: - checkout - run: name: Check Activity command: | ruby my-activity.rb workflows: check: jobs: - check: filters: branches: only: - master scheduled-check: triggers: - schedule: cron: "57 15 * * *" filters: branches: only: - master jobs: - check: filters: branches: only: - master
とてもシンプルな設定だと思います. ちゃんとした運用を考慮するならば, Slack 通知の orbs なんかを追加していい感じで自動化出来るのではと考えていますが, まだやっていません.
以上
Fitbit Web API と pixela を使って走行 (歩行) 距離を可視化を検討してみました. 毎日書いている日記に貼り付けてドヤってみようかなと考えています. やっぱり可視化は楽しいですね.