アーカイブ
RubyでBuffalo/玄人志向の赤外線学習リモコンを操作する
11月22-23日にSFC ORFというSFCの研究室の発表会があって、そこでデモするブツに使う部品としてBuffaloの赤外線学習リモコンのRubyラッパーを書きました。これで家に帰る前に暖房つけたりできてうれしいですね。
玄人志向のKURO-RSとBuffaloのPC-OP-RSを操作できます。
MacとLinuxと、試してないけどたぶんWindowsでも動く気がする。コードはgithubに置いてる。
学習リモコン/KURO-RS/(1)使ってみる – 脳みそ沸騰中!のPerlのコードを参考にしました。
■PC-OP-RSを買う
気がついたらKURO-RSがどこにも売ってないんだけど、PC-OP-RSがKURO-RSと同じハードウェアで箱と付属ソフトが違うだけなのでどちらでも動かせます。
売り上げランキング: 4538
■インストール
gem install kuro-rs
そしてKURO-RSをMacやLinuxに刺す。
Windowsの人はドライバを入れてBuffaloアプリが動くことを確かめてからUSBポートに刺す。
KURO-RSはUSBポートに接続するとシリアルデバイスとして認識されます。MacやLinuxなら/dev/tty.usb****という名前になる。WindowsならドライバをインストールしていればCOM1とかCOM2とか名前がつく。
■赤外線リモコンを学習する
kuro-rsというコマンドがgemと一緒にインストールされています。
terminalで実行する
% kuro-rs /dev/tty.usbserial-0012a3b4そして15秒以内に赤外線をKURO-RSの本体に当てると、termialに16進数で赤外線データが出力されます。
学習した赤外線を発射しましょう
% kuro-rs /dev/tty.usbserial-0012a3b4 ffffffff0300f0e0018083...のように第二引数に16進数でデータを与えます。
これでテレビのチャンネルが切り替わるはず。
■自分のプログラムから使う
こんな感じでIOっぽく使えます。くわしくはexamplesディレクトリを見るといい。
require 'rubygems'
require 'kuro-rs'
# open KURO-RS
kr = KuroRs.open('/dev/tty.usbserial-0012a3b4')
# read
puts kr.read
## => hex dump (ffffffff0300f0e0018083...)
# write
kr.write 'ffffffff0300f0e0018083'
# close
kr.close
# block
KuroRs.open('/dev/tty.usbserial-0012a3b4'){|k|
k.verbose = true
puts k.read
## => hex dump (ffffffff0300f0e0018083...)
}
■Webアプリから使う
シリアルポートは複数プロセスで共有できないし、また複数スレッドから同時に書き込んだりもできないのでRailsやSinatraアプリにkuro-rs gemをそのまま組み込むのはオススメできません。
そういう時はkuro-rs-serverを使いましょう。
こうすると8080番portでhttpサーバーが起動します
% kuro-rs-server /dev/tty.usbserial-0012a3b4 --port 8080
curlから赤外線読み書きしてみる
# readreadもwriteも正常に行われるとstatus 200が返ります。失敗すると200以外。
% curl 'http://localhost:8080'
# => hex dump (ffffffff0300f0e0018083...)
# write
% curl -d 'ffffffff0300f0e0018083...' 'http://localhost:8080'
kuro-rs-serverを内部APIとしてRailsやSinatraから、あるいはAjaxから使うのが良いと思います。
canvasとwebsocketでお絵かき共有
http://canvas.shokai.org
HTML5のcanvasを使ってみたかったので作った。
websocketも使っているので、chromeかsafariで動く。ブラウザ2つ開いてみると、同期しているのがわかりやすい。
画像のURLを末尾につけるとその画像が読み込めて、マウスで線を引くとみんなでリアルタイムに描ける。Gyazoと合わせて使うと便利。
http://canvas.shokai.org/http://gyazo.com/365d02afdf4953d40ec904df5019aa13.png
ソースはgithubに置いた https://github.com/shokai/shared-canvas
こんな風に、オンラインゲームのマップを置いて、友達と「ここ攻めろ」みたいな指示を共有したいなと思って作ってみた。
http://canvas.shokai.org/http://gyazo.com/1b2f1f6b0df60aa2d0dfe3da79106a4e.png
canvasのプラグインは色々あるけど、canvasのAPIの操作感が変わりすぎる物ばかりだったので、とりあえず何も使わないで操作してみた → draw.js
Imageオブジェクトで画像を読み込んで、onloadイベント発生時にcanvasのサイズを変更するとぴったりのサイズになる。かならずdrawImage前にサイズ変更をすること。
(92行目あたり)
var draw_img = function(img_url, onload){
var img_tag = $('canvas#img');
ctx = img_tag[0].getContext('2d');
var img = new Image();
img.onload = function(){
img_tag.attr('width', img.width).attr('height', img.height);
ctx.drawImage(img, 0, 0, img.width, img.height);
if(onload && typeof onload == 'function') onload();
};
img.src = img_url; // 読み込み開始
};
rubyとem-websocketで作ったwebsocketサーバーは、daemontoolsで自動起動・復活するようにしてある。DBは無くて、最近10万本のlineの色と太さと座標データを保存している。
また線にはどの画像URLの線か、というデータも付いているので、これで画像URL毎に部屋分けを行っている。
Sinatra+Haml+jQuery入門
研究室の後輩にSinatraとhamlとjQueryを教えるために作ったテンプレートについて、ここにも書いておく
ソースコード https://github.com/shokai/sinatra-template
実際動いているもの http://masui.sfc.keio.ac.jp/sinatra-template/
git clone git://github.com/shokai/sinatra-template.git
■Sinatraを何に使うか
Sinatra+haml+jQueryが便利。
Railsと似てるけど、ちょっと違う。
個人的には
Rails → HTMLのページをいっぱい作るのに便利
Sinatra → 画面遷移あまりしなくて、同じURLのままjsonのAPIをjQueryのajaxで取得して動的に表示を変えるwebページを作るのには便利
に感じる。
でもSinatra自由すぎるので、ある程度実装パターンを知らないとメチャクチャになるのでこのテンプレートを参考にすると良いよ
個人的にはserial-http-gatewayと一緒に使ってデバイスと連動したwebページを作る、とかが手軽にできてよく使う。
■動かし方
gemでsinatra入れて、ruby development.ru
詳しくはREADME嫁
■テンプレートの解説
最低限の動作するおみくじアプリです
おみくじ結果をJSONで返すAPIがある
jQueryでajaxでJSON読んで表示する
hamlでhtmlを作る
開発用とデプロイ用の2種類のRackUp(*.ru)ファイル付き
■ファイルの説明
・README.md
まず読め
・development.ru
開発サーバーを起動し、main.rbとhelper.rbを読み込んでSinatraアプリを実行するスクリプト
・config.ru
本番サーバーのapacheやnginxでsinatraアプリを実行するためのPassenger用スクリプト
・config.yaml
”やむる”形式の設定ファイルです。アプリのタイトルしか書いてない。
ここに設定値を書くようにするとアプリを配布するのに便利
(必要になったら)DBの接続設定などを書くと良い。
・Gemfile
アプリで使うgemを書いておく
bundlerでgemを管理する時に使う
・helper.rb
起動時に一回だけ読み込まれる
必要なライブラリをロードするコードはここに書く
(必要になったら)データベースへの接続などをここで行うと良い。
app_rootという関数が定義されている(重要)
これにより、開発サーバー・サブドメインでの運用・サブディレクトリでの運用でも内部のURLがズレない
jsからサーバーのAPIにアクセスする時、hamlでcssを読み込む時などに便利
・main.rb
Sinatraアプリ本体
HTTPでアクセスしてきた時のresponseを書く
app_root/omikuji.json でアクセスしてきた時に、ランダムなおみくじを返す
・views/
hamlを置くディレクトリ
・views/index.haml
http://(app_root)/ にアクセスした時に表示されるhamlファイル
index.hamlをどのURLの時に表示するかは、main.rbで指定している
main.js, main.cssを読み込んでいる
rubyの変数のapp_rootをjsの変数app_rootに渡している(重要)
・public/
画像やjavascriptなどの静的ファイルを置くディレクトリ
・public/js/jquery.js
最新版のjquery
・public/js/main.js
index.hamlから読み込まれるJavaScript
・public/css/main.css
index.hamlから読み込まれるcss
SinatraやjQueryの基本的な使い方についてはググる。ライブラリの入門サイトとかを頭から読むよりも既に動いているアプリのソースを読んでわからない所を調べるのが一番速い。
■工夫しているところ
そんなに多いわけでもないけど、
・config.ruとdevelopment.ruを分ける。developmentから起動した時だけsinatra/reloaderを使ってアプリを毎回リロードさせている
・helper.rbの中身は1プロセス毎に1回しか呼ばれないので、DBとの接続や設定ファイルの読み込みはmain.rbと分けてここに書いておくといい
・app_rootという関数を定義してあって、開発環境や本番環境でAPIのURLがずれないようにしている
・haml内に書かれたRubyコードの動作についてはここにまとめた
■アプリの動作
ruby development.ruする→helper.rb読む→helperがyamlの設定ファイルを読む、app_rootという関数を作る→port8080でサーバーがthinに設定される→Sinatraアプリ(main.rb)を起動→main.rbは”/”へのアクセスにindex.hamlを返す、”/omikuji.json”にはランダムなおみくじと時刻を返す
ブラウザで”/”にアクセスする→cssとjsを読む、ajaxでおみくじを取得する関数がボタンに関連付けられる→ボタン押す毎におみくじ表示される
こんな感じで、ajaxでデータ取ってきてhtmlを書き換えるアプリの最低限のテンプレートを用意しました。
意外とDB無くてもglitchtweetやTweetButtonや増井研オーディオAPIのようなものは作れるので、まずはDBなしでSinatra+Haml+jQueryで何か作ってみるのが良い。
DB使うときは、SQL系ならActiveRecordsかSequelかDataMapperあたりがメジャーなのかな?多分。そのへんをまず単体で使ってみて、適当にtwitterのクローラーとか作ってみると良い。
それからSinatraの中に混ぜて使ってみる。いきなりjsで画面が書き換えて、Sinatraもいじって、DBも使うとかやると確実に破滅するので一つずつやるのオススメします
Google Latitudeから自分の位置情報を取得する
以前自分でAndroid用のGPSロガーアプリを作っていたんだけど、収集した位置情報をAndroid内に持っていても特に面白いことが出来なくて悩んでた。
Android版のgoogle latitudeはもちろんサーバーに位置情報が溜まっているので、これを別の自分のサーバーから取得したほうが使い勝手がよい。
作ったもの https://github.com/shokai/google-latitude-logger
■google latitudeから位置情報を取る方法
GData APIからGoogle Latitude APIが使えるが、なんかわけがわからなかったのでgoogle latitude badgeからデータを取ることにした。
Google Latitude公開ロケーションバッジのページにgoogleアカウントにログインした状態で行き、「有効にして最新の現在地情報を表示する」にチェックを入れる。
webサイト用のembedコードから api?user=1234567890 の部分をメモする。
で、 http://www.google.com/latitude/apps/badge/api?user=1234567890&type=json を見ると自分の位置情報が書かれている。
位置情報を取得してMongoDBに保存するコードをlatitude-logger.rbに置いておいた。さくらVPSのサーバーで数分おきに動かして位置情報を保存している。
■保存した位置情報を使う
移動の方角と速度を計算してtwitterに投げるようにしてみた。

俺が元気に活動している様子がわかる。例えば、時速200km以上で西に移動するのが連続していたら新幹線に乗ってるのかなとか、そういう想像ができる。
位置情報をそのまま公開するのは気持ち悪いし危険だし誰も得しないので、何か加工して表示する必要があるのでちょっと抽象的な表現にしてみた。
地理的な知識があれば速度と方角だけでも結構何をしているかわかる。時速20〜40kmで東西に移動しているなら神奈川中央交通のバスに乗っているし、時速80kmぐらいだったら電車で東京に向かっている事が多い。けっこうわかる。
KMLで出力してGoogle Earthに表示してみた。これは先週木曜に学校に行こうとしてバスを乗り過ごして迷子になった時の移動のログ。

KMLファイルはAndroidで開いてもMapに描画されるので、サーバーで定期的に生成されてるようにしてあるからほぼ以前作ったAndroid用GPSロガーと同じ事ができている。
今後は俺が近くに来たら通知するアプリを作って配布しようかと思ったけどあまりうれしくないのでやめた。
iPhone JavaScript Console作った
作った → https://github.com/shokai/iphone-js-console
iPhone用のJavaScript shellのようなもの。FirebugやChromeの開発パネルみたいな感じで使う。
chrome拡張やiPhoneシミュレータでiPhone用のwebページの動作は確認できるが、加速度センサやGeo Location APIなんかは実機で動かさないとデバッグできない。
しかしデバッグをしようにも、iPhone上で大量のalertを出すと気が狂ってしまう。iPhoneで実行中のwebページ上の任意のオブジェクトの中身を、Macから覗いたり値を書き換えたり関数を実行したりするツールが必要だったので作った。
なお、Androidのブラウザにはwebsocketが無いのでこのツールは動かない。Androidではlogcatで
adb logcat | grep "^./browser" --color=autoすればconsole.log、console.errorの出力は見れるので、それで何とか我慢している。
■セットアップ
MacとiPhoneを用意する。MacとiPhoneは同じ無線LANの下に接続して、互いに通信できるようにしておく。
github.com/shokai/iphone-js-consoleからcloneしてくる。
iphone-js-console.jsをhtmlに読み込ませる。JsConsole.startで自分のMacに接続させるようにする。
<script src='iphone-js-console.js' type='text/javascript' />(あらかじめconsoleを起動するMacのIPアドレスは調べておこう)
<script type='text/javascript'>
JsConsole.start('ws://192.168.1.38:8088'); // Addr of Console Server
</script>
Macで、iphone-js-consoleを起動する
./iphone-js-console
iphone-js-consoleの起動時に、rubygemsが足りないという警告がでたら足りないgemをインストールする。
gem install eventmachine em-websocket多分これで足りる。
あとreadlineを使っているけど、Macの最初から入っているreadlineは腐ってた気がするので、brewかportsで入れるといい。(わからなかったら飛ばしても多分良い)
■使う
Macのiphone-js-consoleで
alert(document.title)と打つと、

このようにiPhoneのSafari上でJavaScriptが実行される。
また、iPhoneのSafariの変数を参照することもできる。
> window.navigator.appVersion
<1> "5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"
中身が複雑なオブジェクトは整形されて表示される。
> location
<1>
{"href"=>"http://192.168.1.38:8080/debug-sample.html",
"hash"=>"",
"port"=>"8080",
"protocol"=>"http:",
"origin"=>"http://192.168.1.38:8080",
"pathname"=>"/debug-sample.html",
"hostname"=>"192.168.1.38",
"host"=>"192.168.1.38:8080",
"search"=>""}
もちろん、エラーも出力される。
> homu
<1> "error : Can't find variable: homu"
> 1+2
<1> 3
> 1+
<1> "error : Parse error"
iPhoneのJSで、あらかじめ
console.log(foo);とか書いておけばもちろんMacのiphone-js-consoleにfooの値が表示される。
一度入力したコマンドは、キーボード上下で履歴を呼び出したりできる。
大変便利ですね。
■技術的なこと
iPhoneとiphone-js-consoleの接続にはWebSocketを使っている。EventMachine::WebSocketが便利だった。
iphone-js-consoleからiphoneへ送信された文字列は、そのままiPhone上でevalで実行させている。
iphoneからiphone-js-consoleへのオブジェクトの送信は、iPhone上でJSON.stringifyでシリアライズして送信して、iphone-js-consoleでparseして適当に整形して表示している。
別に難しいことはしていない。


最近のコメント