3月 212013
Sinatra RocketIOで家のRaspberry PiのArduinoをリアルタイムで見る
Category: 未分類 | Tags: Arduino, arduino_firmata, RaspberryPi, RocketIO, Ruby, Sinatra | Author: shokai
RocketIOのサンプルとして、それなりに激しい処理が低スペックマシンで動くかテストするために作った。
http://status.shookai.org
ソースコード
https://github.com/shokai/rocketio-arduino-sample
こういうのが表示されてるはず
物理的な意味ではこうなってる
Arduino Firmata on Rubyで、ADコンバータに温度センサと明るさセンサを付けたArduinoを読んで0.3秒毎にSinatra RocketIOでブラウザにpushしている。
5秒毎にCPUとメモリ使用量もpushしてる。
あと新規接続/切断がある度に全クライアントに接続数を通知してる。
60行ぐらいのSinatraと40行ぐらいのJavaScriptでできてる。
JavaScript側を抜粋すると、こんな感じでそれぞれイベント待ちしておいて
io.on("arduino", function(data){
$("#temp").text("気温:"+data.temp+"度");
$("#light").text("明るさ:"+data.light);
});
io.on("stat", function(data){
$("#cpu").text("CPU:"+data.cpu+"%");
$("#mem").text("メモリ:"+data.mem+"%");
});
io.on("clients", function(data){
$("#websocket").text("websocket:"+data.websocket);
$("#comet").text("comet:"+data.comet);
});
サーバー側はsinatraの中にArduinoでセンサーを読むEventMachineのタイマーをベタ書き。
io = Sinatra::RocketIOCPUとメモリは同じ要領で、psコマンドの結果をparseして送ってる。
## Arduino sensors
io.once :start do
begin
arduino = ArduinoFirmata.connect ENV['ARDUINO'], :eventmachine => true
rescue => e
STDERR.puts "#{e.class} - #{e}"
next
end
EM::add_periodic_timer 0.3 do
light = arduino.analog_read 0
$logger.debug "light : #{light}"
temp = arduino.analog_read(1).to_f*5*100/1024
$logger.debug "temperature : #{temp}"
io.push :arduino, :temp => temp, :light => light
end
end
Sinatra側で定期的に行う処理は、 Sinatra::RocketIO.once :start の中で登録すると良いです。
“start”はeventmachineとwebsocketサーバーの準備が整ったら発火するイベント。
onではなくonceなのは1回目だけ呼ばれるという意味。
あと、Arduino Firmataの最近のバージョンからeventmachine用の起動オプションを付けた。
ArduinoFirmata.connect "/dev/tty.usbデバイス名", :eventmachine => trueEM::runの中でこうやって起動するとThreadのかわりにeventmachineで動くようになった。
Sinatraの中で動かすときはこうしないと、タスク切り替えがうまくいかない。