0

Jawbone Up24のpubsub APIを受信する

Jawbone Up24を買った。Apple Storeで売ってた。
前のUpと比べてbluetoothで同期できるので楽というのもあるが、webhookによるサーバープッシュAPIの方が気になってて買った。

UP for Developers: Pub Sub


通知

oauthで認証してもらったユーザーが寝たり・起きたり・活動したりすると、約10秒後に自作のwebアプリにjsonでwebhookが通知される。
jawbone up—(bluetooth)—>スマホ—(HTTP)—>jawboneのサーバー—(HTTP webhook)—>自作webアプリ
と通知がリレーされていくわけです。

最近色々とまともなAPIのあるガジェットは増えてるけど、出力側ばっかりで、入力というかトリガー側(センサー)になるやつはあまり無い。


ソースコード

前に作ったJawbone UpのAPIで睡眠時間などを取得するを少し改造した。

https://github.com/shokai/jawbone-up-api-study


設定

アプリケーションの設定にpubsubのURLを書くだけで通知が来るようになる。


プログラム

post ‘/pubsub’を追加した。あとAPIのscopeを色々追加した。move_readが無いと運動した時に空の通知が来てしまっていたので。

https://github.com/shokai/jawbone-up-api-study/tree/master/auth
def app_root
"#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}"
end

def oauth_client
@client ||= OAuth2::Client.new(CLIENT_ID, APP_SECRET,
:site => 'https://jawbone.com',
:authorize_url => '/auth/oauth2/auth',
:token_url => '/auth/oauth2/token')
end

get '/' do
unless session[:oauth_token]
@mes = %Q{<p><a href="/login">login</a></p>}
else
@mes = %Q{<p><a href="/logout">logout</a></p>
<p>your token : #{session[:oauth_token]}</p>}
end
end

get '/login' do
scope = "basic_read extended_read mood_read move_read sleep_read generic_event_read"
redirect oauth_client.auth_code.authorize_url(:scope => scope,
:redirect_uri => "#{app_root}/auth")
end

get '/auth' do
code = params["code"]
halt 400, 'code missing' unless code
begin
session[:oauth_token] = oauth_client.auth_code.get_token(code).token
puts "TOKEN : "+session[:oauth_token]
rescue => e
STDERR.puts e.message
end
redirect "/"
end

get '/logout' do
session.delete :oauth_token
redirect "/"
end

post '/pubsub' do
request.body.rewind
puts request.body.read
"ok"
end


こういうのがpushされてくる
{"events": [{"action": "enter_sleep_mode", "timestamp": 1396797071, "user_xid": "gvT5W2FhlrHsB3r9Wq_unA"}], "notification_timestamp": 1396797074}
{"events": [{"action": "exit_sleep_mode", "timestamp": 1396797115, "user_xid": "gvT5W2FhlrHsB3r9Wq_unA"}], "notification_timestamp": 1396797117}
{"events": [{"action": "creation", "timestamp": 1396797240, "user_xid": "gvT5W2FhlrHsB3r9Wq_unA", "type": "move", "event_xid": "mD99tHyRBx4xNT7HoSCUmA"}], "notification_timestamp": 1396798341}

1

Jawbone UpのAPIで睡眠時間などを取得する

oauth2で認証してからjawbone gemを使う。

ここに置いてある
https://github.com/shokai/jawbone-up-api-study


腕輪型アクティビティロガーのAPI

腕輪型アクティビティロガーではJawbone Up、FitBit、FuelBandの3つが有名だと思う。どれもAPIがある。

JawboneがOAuth2、FitBitがOAuthで認証して詳細なデータが取得できて、APIもいろいろあって遊べる。作ったアプリを他人に使ってもらいやすい。
Nike FuelBandは野良開発者は自分のバンドしかデータが取れず、しかも詳細な数値はナイキのパートナーしか取得できないようだ。遊べない。

Jawbone Up24(Bluetooth LEでiPhone/Androidと同期するやつ)はwebhookのURLが登録できて、OAuth2で読み取り権限をくれたユーザーのデータがガンガン自分のwebアプリにサーバー間プッシュされるらしいので興味深い。例えば睡眠に入った、起きた、等のタイミングでpushされるらしい。普通のUpでも同期したタイミングでpushされてくるかなと思って試したけど、webhookされなかった。Up24がほしい。

俺が普通のJawbone Upを買ったのは3つのAPIドキュメントを比較してみて、Jawboneが一番面白そうだなと思ったからなんだけど、当時AndroidではUp24とbluetooth接続できなかったので普通のUpを買ったという次第。Up24ほしい。


まずアプリを登録する

https://jawbone.com/up/developer/

とりあえずローカルホストでアプリを作るのでcallbackをうけるためにlocalhost:5000で登録する。

Client IdとApp Secretをメモしておく。


認証する


これをSinatraで実装する
UP for Developers: Authentication

config.ru

require 'sinatra'
require 'oauth2'

CLIENT_ID="your-client-id"
APP_SECRET="your-app-secret"

require_relative 'main'

enable :sessions
set :session_secret, (ENV["SESSION_SECRET"] || "zanmai-kazusuke-kazudon-marutaka")

run Sinatra::Application

main.rb

def oauth_client
@client ||= OAuth2::Client.new(CLIENT_ID, APP_SECRET,
:site => 'https://jawbone.com',
:authorize_url => '/auth/oauth2/auth',
:token_url => '/auth/oauth2/token')
end

get '/' do
unless session[:oauth_token]
@mes = %Q{<p><a href="/login">login</a></p>}
else
@mes = %Q{<p><a href="/logout">logout</a></p>
<p>your token : #{session[:oauth_token]}</p>}
end
end

get '/login' do
scope = "extended_read sleep_read mood_read"
redirect oauth_client.auth_code.authorize_url(:scope => scope,
:redirect_uri => "http://localhost:5000/auth")
end

get '/auth' do
code = params["code"]
halt 400, 'code missing' unless code
begin
session[:oauth_token] = oauth_client.auth_code.get_token(code).token
rescue => e
STDERR.puts e.message
end
redirect "/"
end

get '/logout' do
session.delete :oauth_token
redirect "/"
end

起動

% bundle exec rackup config.ru -p 5000


loginするとjawboneのサイトに飛んでoauthで認証しlocalhost:5000に戻ってくる。


APIで睡眠データを取得する

/users/@me/sleeps
 を読む。

これが
UP for Developers: Endpoints

ラップされてjawbone gemになる

["move", "body_event", "workout", "sleep", "meal", "cardiac_event", "generic_event", "mood"]
が使える。


require 'jawbone'
require 'awesome_print'

OAUTH_TOKEN = "your-oauth-token"

client = Jawbone::Client.new OAUTH_TOKEN

ap client.user
ap client.sleeps
睡眠時間などを取得する


何時から何時まで寝たか(asleep_timeとawake_time)、深い眠り(deep)と浅い眠り(light)の長さ、ただ横になっているだけで寝ていない時間(awake)、二度寝を何回したか(awakenings)などがわかる。
単位は全て秒とunixtime。

0

irkitコマンドで家の外からIRKitを操作する

前:赤外線学習リモコンIRKitのrubygemを作った


irkit gemに付属のirkitコマンドは、Internet APIも使えるので家の外からIRKitを操作できます。
解説しておく。

インストール

% gem install irkit
% irkit --help

デバイスをirkitコマンドに登録する

最初のこの設定だけはIRKitと同じLANの中にいなければならない。

% irkit -device:add デバイス名

なお2つ以上IRKitを持っている場合は、-addressでIPアドレスを指定すればそれぞれ保存できる。
% irkit -device:add デバイス名 -address 192.168.1.123

登録されているか確認

デバイスリストと赤外線データのリストが見れる。LAN内のIRKitもbonjourで探す。
% irkit -list

なおこのデータはホームディレクトリ直下にjson形式で保存されている。
Ruby使ってるならirkit gemをrequireすればこのように取り出せる。普通学習は1回しかしなくて、発射ばかりするはずなので、学習とデータ管理はirkitコマンドに任せてもいいと思う。
require 'irkit'

IRKit::App::Data["IR"] ## 赤外線データ
IRKit::App::Data["Device"] ## デバイスデータ
もちろんRuby以外の言語でも、ホームディレクトリ下の.irkit.jsonを直接読める。


外に出る

ここからはIRKitを家に置いて、外にでても操作できる。

赤外線を学習する

% irkit -get 赤外線データ名 -device デバイス名


赤外線を発射する

% irkit -post 赤外線データ名 -device デバイス名


おわり。

1

赤外線学習リモコンIRKitのrubygemを作った

IRKitはよく「iOSから操作できる赤外線リモコン」と説明されるけど、そのAPIはHTTPなのでiOS以外からももちろん使えます。
というわけでRubyから使いやすいようにした。

ソースコードはgithubにある。不具合等はissuetwitterにお願いします。

irkitコマンドという便利ツールも入れておいた。
bonjourでLAN内のIRKitを発見する機能や、赤外線データのgetとpost(と保存)、家のLANの外からIRKitを操作するInternet API関連が実装されているので
プログラムを書かなくてもirkit gemをインストールすればすぐIRKitが使える。


なんでこういうツールが付いているかというと、デバイス系はコマンド一発で全部実行できるテストコードが書きにくい部分がかなりあって、しょうがないから各機能をテストしやすい実行可能コマンドを作るぐらいしかない。

IRKit


先週買った。うちのエアコンの赤外線はデータが長くて、既存の学習リモコンで学習できない事が多いんだけどIRKitだとokだった。
置き場所もカーテンレールの上に適当に置いてるだけなんだけど、エアコンの赤外線受光部は死角のはずなのに壁で反射してるのかちゃんと届いてる。よくできてると思う。


インストール

https://rubygems.org/gems/irkit
実行にはRuby2.0.0以上が必要。1.8.7は非サポート。(1.9.3でももしかしたら動くかもしれない)
% gem install irkit

なおubuntuやdebianでは事前にavahiをインストールしておく必要がある。これはLAN内のIRKitを見つけるのにbonjourを使っている為。
% sudo apt-get install libavahi-compat-libdnssd-dev

使い方


https://github.com/shokai/ruby-irkit#usageに書いた。サンプルコードもある。

BonjourでLAN内のIRKitを見つけて、赤外線が読み書きできる。
require 'irkit'

irkit = IRKit::Device.find.first
ir_data = irkit.get_messages

irkit.post_messages ir_data

また、Internet APIというプロキシを使うとLAN外からも操作できるんだけど、そのためのclientkeyやdeviceid等の発行もできる。

くわしくはgithubのREADMEとサンプルコード見てほしい。


irkitコマンド

gemをインストールすると実行可能コマンドも付いてくる。
普通のHTTP APIとInternet API両方とも使える。
コマンドからリモコン操作できるので、crontabで朝あらかじめ暖房をつけるとかできる。
エアコンのリモコン探すよりCUI使ったほうが速いので、shellの履歴から「暖房」で検索して「irkit -post 居間エアコンOFF」を探してenter押せば暖房が消せる。

% irkit --help
% irkit --get tv_on # tv_onという名前を付けて赤外線データを保存
% irkit --post tv_on # tv_onを赤外線発射
% irkit --list # デバイスやデータのリストを見る
% irkit --post tv_on --address 192.168.0.123 # IPアドレスを指定してtv_on赤外線発射
% irkit --device:add myhouse # myhouseという名前でInternet APIのclientkey等を保存
% irkit --device myhouse --post tv_on # 自宅のIRKitをLAN外からtv_on発射

1

895円の超小型Ardunoクローン DigiSparkを買った

とにかく小さくて安いのに、ほぼArduinoとして使える。
そしてズボンのコインポケットに入れて持ち歩けるので電車内hackに便利。

DigiSpark


ソースコードはここに置いておいた。
デジタル出力・アナログ出力・アナログ入力・Mac上のRubyとのUSB通信を試した。
https://github.com/shokai/digispark-study

「webサービスと連動したちょっとしたハードウェア」にはArduinoはオーバースペックだと思うので、DigiSparkちょうどいいと思う。





普通のArduinoとの違い

詳しくは digispark:tutorials:basics [Digistump Wiki]

多少制限はある。
  • IOピン数が6本、PCとUSB通信する場合は4本しか無い
  • プログラムを書き込めるメモリ領域が6Kbyteしかない
  • PCからは仮想シリアルポートではなくただのUSB-HID(ヒューマンインタフェースデバイス)として認識される

内部のソースコード読んだらすごかった。
DigiSparkはマイコン上のプログラムを工夫する事で部品点数を減らし、価格と基盤サイズを抑えている。

ここの一番下にある回路図を見ればわかるが、DigiSparkはATTiny85という安い8ピンマイコンと、抵抗・ダイオード・三端子レギュレータしか使っていない。部品点数が少なく基板も片面実装なので安い。

ATTiny85にはUSB機能は付いていないが、micronucleusというDigiSparkのファームウェアがArduinoブートローダとソフトウェアUSBを同時に実装しているから、たったこれだけの部品でArduinoになれる。

micronucleusはV-USBというUSB1.1のソフトウェア実装を取り込んでいる。

V-USBは、10年ぐらい前に流行った「12MHz以上のAVRマイコンならUSB-HIDになれる」というhackを綺麗に書きなおしてオープンソースで公開されているライブラリ。

実際に使う上で一番大きい違いは仮想シリアルポートではなくUSB-HIDとして使わなければならない所だけど、これはDigiSparkを単体で使う場合は関係ないし、PCと通信させて使う場合もRubyならdigiusbというgemを使えば普通のシリアルデバイスの様に使える。
digiusbの実装を見ると普通にlibusbを使っているだけなので、他の言語でもたぶんなんとかなるんじゃないかと思う。

誰かnode.jsのC拡張くわしい人、digiusb npm作ってください


購入

注文して1週間ぐらいで届いた。

Digispark USB Development Board – Digistump

日本円でも決済できる。
単体で9ドル、現時点で895円。
発送方法は色々選べるけど安いUSPS First Class Package Insuredの965円にした。14+ daysって書いてあったけど1週間ぐらいで来た。

最低でもこのUSB Development Boardだけあれば良いが、シールドなども色々あるのでまとめていろいろ買った。
DigiSparkをUSBポートに接続し、PC/Mac上のソフトで自作プログラムを書き込めば動くので特に別途マイコン書き込み器等は必要ない。

他に頼んだもの

Stackable Headersはシールドを2階建以上積むる時に使う。
Starter KitはUSB Development boardにRGB Shield KitPrototype Shield Kitが付いたもので、壊した時の為にもう一枚DigiSpark欲しかったから買った。バラで買うより100円安い。
Temperature Sensor Shieldは1-wireで温度が計れる。


ボードへのプログラムの書き込み

DigiSpark用のIDEを使う。

Arduino IDEはJavaで実装されていて、Mac/PC/Linuxで使える。それにDigiSparkへの書き込み機能とDigiSprak用のマイコン側のライブラリを追加したものがこれ。

タイトルバーにArduino IDEって書いてあるけど、[ツール]→[書込装置]にDigiSparkが追加されている。
また、スイッチサイエンスが作って本家Arduino IDEに取り込まれた日本語化も有効になっている。


とりあえず使う

プログラムの書き込みはArduinoと同じを押すだけ。
しかしボード上にリセットボタンが無いのでUSBポートを抜き差しする事で代替する。
Arduinoのファームウェアは電源が入ってから数秒はプログラム書き込み待ち状態になり、特にプログラムが送られてこない場合は今持っているプログラムを実行するようになっている。

基板上のLEDを点滅させる


基板上にテスト用のLEDがあるが、基盤のリビジョンによりpin0にあったりpin1にあったりする。とりあえず500ミリ秒ごとに両方点滅させた。

led_blink.ino
bool led_stat = false;

void setup(){
pinMode(0, true);
pinMode(1, true);
}

void loop(){
digitalWrite(0, led_stat);
digitalWrite(1, !led_stat);
led_stat = !led_stat;
delay(500);
}


LEDをぼんやり点滅させる

analogWriteを使った。なおanalogWriteにはpinModeの設定はいらない(arduino.cppが勝手にやってくれる)


led_fade.ino
void setup(){
}

void loop(){
for(char i = 0; i < 26; i++){
analogWrite(0, i*10);
analogWrite(1, i*10);
delay(20);
}
for(char i = 25; i > 0; i--){
analogWrite(0, i*10);
analogWrite(1, i*10);
delay(20);
}
}


Macと通信する

Rubyでやる場合、libusbのラッパーのdigiusb gemをインストールする
% brew install libusb
% gem install digiusb
digitermという実行コマンドも付いている。


アナログセンサーを読んでMacに送る

analogReadしてUSBでMacに送る

SerialライブラリのかわりにDigiUSB.hを使う。delayもDigiUSB.delayにしないと通信できなくなる。
adb_usb.ino
#include <DigiUSB.h>

void setup(){
DigiUSB.begin();
}

void loop(){
DigiUSB.println( analogRead(1) );
DigiUSB.delay(100);
}

なおLEDを点滅させながらanalogReadしたら値がブレまくるけど、キャパシタを入れれば大丈夫だと思う(まだ試してない)

digitermで見る


センサーつないでないけどanalogReadは取れてる。


Rubyで受信する

adc_usb.rb
require 'digiusb'

spark = DigiUSB.sparks.first

loop do
recv = spark.gets.strip
puts "analog value: #{recv}"
end

digiusb gemは普通にIOっぽく使えるので、serialport gemからの移行も楽だと思う。


Macから基盤上のLEDを点灯・消灯する

今度はMacからDigiSparkに命令を送る。

‘o’が来たら点灯、’x’が来たら消灯するプログラムを書いた
usb_led.ino
#include <DigiUSB.h>

void setup(){
pinMode(1, true);
DigiUSB.begin();
}

void loop(){
if(DigiUSB.available()){
char recv = DigiUSB.read();
switch(recv){
case 'o':
digitalWrite(1, true);
break;
case 'x':
digitalWrite(1, false);
break;
}
}
DigiUSB.delay(10);
}

digitermを起動して、oやxを入力しenterキーで送信で操作できる。


RubyからLED点灯・消灯命令を送る


1秒ごとに点灯消灯

usb_led.rb
require 'digiusb'

spark = DigiUSB.sparks.first

led_stat = false

loop do
puts led_stat
spark.write( led_stat ? 'o' : 'x' )
led_stat = !led_stat
sleep 1
end


このように簡単に使えるし、安いし、ズボンのコインポケットにピッタリはいるから電車内hackに便利。
arduino_firmataのdigispark版を作ろうと思う。けど6Kbyteのプログラムメモリに入れるために機能を削らないとならないかもしれない。
node用のdigiusb npmも欲しい。

あと、AndroidとArduinoを接続したりした時も思ったけど、もうUSB上で仮想シリアルポート使うのやめたほうがいいんじゃないかと思う。DigiSparkのようにUSB-HIDならドライバいらないし、libusb使えば自作プログラムとマイコンの通信も簡単だし、シリアル通信を115200bpsとかいう速度で読み書きするのもなんかおかしい気がする。