前:Web+DB Press vol.82にJawbone Up24について書いた

先月末に発売されたWeb+DB Press vol.82で、コードが長すぎてページが足りなくて入りきらなかったネタ


研究室でにわかにjawbone up24が流行り始めていて、slackの#newsというチャットルームに「起きた(5時間寝た、3回二度寝した)」とかログが流れてくる。

そこに「何歩歩いた」あるいは「活発に活動中」というログも流すようにした。


これは記事の中に書いた俺APIというJawbone APIのプロキシを使ってる。Bluetooth LEで自動同期できるup24がちょっと歩く毎にガンガンwebhookでpushしてくるのを俺APIが受信して、さらにそこからsocket.ioでhubotに再配信してくれる。
JawboneのAPIはOAuth2で認証しないと使えないんだけど、もっと細かくてどうでもいい事に気軽に使いたかったのでAPIプロキシを立てた。あと俺が起きてるか寝てるかなんて認証かける必要なく公開されてていいと思った。ので作った。


hubot-ore-api.coffee

ちょっと長いけど、こういうhubot scriptを書いておけばチャットに運動の通知が流せる。(実際使ってるやつから抜粋してきた)
歩いた時は〜〜歩歩いたってslackに流れるし、歩かずにデスクワークしている時もpush来るので「活発に活動中」とかslackに通知するようにしている。

俺APIでoauth2認証しておけば色々なところからjawboneのイベントが使えるようになるので便利だと思う。

hubot-ore-api.coffee
debug = require('debug')('hubot-ore-api')

config =
url: 'https://ore-api.herokuapp.com'
slack:
room: "#news"

module.exports = (robot) ->

socket = require('socket.io-client').connect config.url

## jawboneから動いたイベントがpushされてくる
socket.on 'move', (event) ->
debug "move - #{JSON.stringify event}"
if event.action is 'updation'
notify_move event

last_notify_at = {}
## 動いた事を通知する
notify_move = (event) ->
if Date.now() - (last_notify_at[event.screen_name] or 0) < 1000*60*60 # 1時間毎に間引く
debug "throttled #{event.screen_name}'s notify_move"
return
last_notify_at[event.screen_name] = Date.now()
get_activity "moves", event.screen_name, event.event_xid, (err, move) ->
if err or move.details?.steps < 1
debug 'no steps data in event'
return
current_steps = move.details.steps
last_steps = robot.brain.get("steps_#{event.screen_name}") or 0
robot.brain.set("steps_#{event.screen_name}", current_steps)
if last_steps > current_steps
last_steps = 0
new_steps = current_steps - last_steps
if new_steps > 0
txt = "@#{event.screen_name} が#{new_steps}歩運動しました (本日合計#{current_steps}歩 #{move.details.km}km)"
else
txt = "@#{event.screen_name} が活発に活動しています"
robot.send config.slack, txt

## ore-api.herokuappにあるJawbone APIプロキシを使う
get_activity = (type, screen_name, xid, callback = ->) ->
robot.http("#{config.url}/#{screen_name}/#{type}.json?xid=#{xid}").get() (err, res, body) ->
if err
callback err
return
try
data = JSON.parse body
catch err
callback err
return
debug data
callback null, data.data
return