先日、よく行くバーのダイエット部に入部したため、体重計を買う事になりました(ちなみにダイエット部とは、7月末までにどのくらい痩せるかという目標を決めて、お互いに励ましあいながらがんばるという部活です)。
どうせ買うなら多機能で Internet of Things 的なヤーツが欲しかったので、まずは量販店に見に行きました。いろいろ出てはいるのですが、外部API連携が出来るかどうかとかが分からない(どこにも書いてないし、店員さんに聞いてももちろん分からない)ので、一旦諦めていろいろ調査をしてみました。
結局買ったのは、Withings ネットワーク対応 体重計 Smart Body Analyzer WS-50(Amazon.co.jpリンク)というヤツです。
これのいいところは、
- スマホをいじらなくても乗るだけで WiFi 経由でインターネットにデータを飛ばせる
- (一応)APIがある ※一応と書いた訳は後述
- IFTTTに対応している
といった点です。
API について
公式ドキュメントは以下から。
npm パッケージもいくつか引っかかりますね。
ん?
withings-request : The Withings OAuth implementation is not perfect. This lib hides that.
なんかキナ臭い。
Top Six Things You Need To Know About The Withings API* によれば、Withings の API は
- It’s inconsistent about formatting
- They don’t understand OAuth.
- It is incomplete
- It disagrees with itself
- Account linking and device sharing is terrible.
- They don't listen
だいぶひどい言われようです。
IFTTT での連携
というわけでAPI叩くのはやめて IFTTT を使う事にしました。
もしかして IFTTT を知らない人のために補足すると、IFTTT は IF-This-Then-That の略で、トリガーとアクションを指定する事で、2つのデバイスやサービスをいい感じに連携させるサービスです。
例えば、体重計に乗ったら、Slack に通知する、なんていうのをポチポチ作るだけで、朝体重計に乗ると
なんていう通知が飛んできます。
同じように Twitter に流す事も可能ですが、さすがに自分の体重を全世界におっぴろげるのは憚られます。
また、目標に対してどの程度の進捗なのかも知りたいですよね。
という事で、クラウドを使ってそのあたりを解決したいと思います。
構成
- 体重計に乗ると IFTTT にプッシュされる(実際には一定のタイミングでポーリングっぽい動作)
- IFTTT から Slack に通知
- IFTTT から Maker Channel 経由で、API Gateway に HTTPS で POST リクエスト
- API Gateway が Lambda をキック
- 諸々の計算を行って、IFTTT の Maker Channel(incoming webhook) に HTTPS POST
- IFTTT から Twitter にポスト
開始体重からの差分: -7kg
— moto (@j3tm0t0) 2016年4月22日
目標体重までの差分: 2.2kg
予想目標到達日:5/18(目標の74日前)
Lambda 詳細
inputには、下記のようなJSONを期待しています(Maker channelで設定する)
{
"WeightKg": {{WeightKg}}, // その日の体重計の読み(Kg)が入る
"StartKg": xx.x, // 開始日の体重
"StartDate": "2016/1/29", // 開始日の日付
"TargetKg": yy, // 目標の体重
"TargetDate": "2016/7/31" // 達成目標日
}
上記のパラメータを元に、諸々計算を行って、Maker channel の endpoint に HTTPS POST します。
console.log 'Loading function'
request = require 'request'
exports.handler = (event, context) ->
console.log JSON.stringify event
current_kg = event.WeightKg
start_kg = event.StartKg
target_kg = event.TargetKg
current_date = (new Date)/(24*60*60*1000)
start_date = Date.parse(event.StartDate)/(24*60*60*1000)
target_date = Date.parse(event.TargetDate)/(24*60*60*1000)
diff_kg = Math.round(100 * (event.WeightKg - event.StartKg) ) / 100
togo_kg = Math.round(100 * (event.WeightKg - event.TargetKg) ) / 100
due_pace = (target_kg - start_kg)/(target_date - start_date)
due_kg = start_kg + due_pace * (current_date - start_date)
progress_kg = Math.round(100*(current_kg - due_kg))/100
progress_days = Math.round(progress_kg / due_pace)
actual_pace = (current_kg - start_kg)/(current_date - start_date)
estimated_date = new Date( (new Date) - (togo_kg / actual_pace)*24*60*60*1000 )
margin_days = Math.round(target_date - estimated_date/(24*60*60*1000))
message = """
開始体重からの差分: #{diff_kg}kg
目標体重までの差分: #{togo_kg}kg
予想目標到達日:#{estimated_date.getMonth()+1}/#{estimated_date.getDate()}(目標の#{margin_days}日前)
"""
console.log message
request.post
url: 'https://maker.ifttt.com/trigger/twitter/with/key/XXXXXXXXXXXXXXXXX'
form:
value1: message
, (err, response, body) ->
context.fail err if err
context.succeed body
return
効果
もともと Slack に投稿していた時も結構減ってたんですが一旦停滞してて、Twitter でより広範囲に晒すことでそれまで以上に順調に減ってきています。
おわりに
俺、このダイエットが終わったら、美味しいお好み焼きを食べに行くんだ!