0

RubyとArduinoとTwitterで天気予報を見る

こういうのを数年おきに、その時の近代的な実装で作りなおしてみるとプログラミング環境の進歩がわかる。


1. 今日傘が必要かどうか表示してくれるてるてる坊主

晴れの時


雨が降る可能性がある時

ウチでは15分おきにその日の天気予報を取得して表示している。うちテレビ無いけどこれのお陰で傘を忘れたりしなくなった。


プログラムはものすごい単純になっている。Rubyのみ。
Macで開発してRaspberry Piにデプロイした。Ruby動くUNIX系ならどこでも動くはず。
require 'rubygems'
require 'arduino_firmata'
require 'weather_jp'

arduino = ArduinoFirmata.connect
weather = WeatherJp.get '東京'
if weather.today.rain > 30 # 降水確率30%以上
arduino.digital_write 13, true ## 青色LED
else
arduino.digital_write 12, true ## 赤色LED
end
taiki45さんのweather_jpと俺のarduino_firmataを合わせると超綺麗に書ける。
MSN天気からデータを取ってきている。
6年ぐらい前に作ったときはPerlのCGI+XPortだったり、4年ぐらい前はRubyからArduinoにシリアル通信したりでもっと行数多かった。


ちなみにzakuniさん作のweather-reportはlivedoor weatherからデータを取ってきていて、降水量情報がない代わりに雨/雪/雹の可能性を示すumbrella?メソッドが在る。
require 'rubygems'
require 'arduino_firmata'
require 'weather-report'

arduino = ArduinoFirmata.connect
weather = WeatherReport.get '横浜'
if weather.today.umbrella? ## 傘が必要な時
arduino.digital_write 13, true ## 青色LED
else
arduino.digital_write 12, true ## 赤色LED
end


地名や降水確率のしきい値を実行時引数に渡せる仕様にして、githubに置いておいた。
ProcfileもあるのでMacやRaspberry Pi等にサービスとしてインストールできる。
shokai/teruteru · GitHub


回路は、昔秋月で買ったRGBフルカラーLEDを使った。
アノード3本/カソード1本のスタンダードな奴。

arduinoのどのピンにRGBが接続されているかはプログラム中に書いてある

こういうシールドにして、その上にティッシュかぶせて顔を書けば完成です。



2. 今日雨が降りそうだったら教えてくれるtwitter bot


雨が振りそうな日の朝に、こういうのが来る

Twを使うとtwitter botが簡単に作れる。
天気botこれだけで書ける。
require 'rubygems'
require 'tw'
require 'weather_jp'

tw = Tw::Client.new
tw.auth 'shokai_log' ## botアカウントで認証
weather = WeatherJp.get '東京'
if weather.today.rain > 30 # 降水確率30%以上
tw.tweet "@shokai #{weather.today}" ## @shokaiにmention送る
else
puts weather.today ## 予報の文章をterminalに表示するだけ
end

降らない時にも「今日の天気は晴れ」とか送ってるとだんだん見なくなるので、雨降る日だけtweetするようにした。

これも多少使いやすくしてgithubにコード置いておいた。
shokai/twitter-weather-alert · GitHub
cronで朝実行するようにしている。

0

Sinatra RocketIOで家のRaspberry PiのArduinoをリアルタイムで見る

RocketIOのサンプルとして、それなりに激しい処理が低スペックマシンで動くかテストするために作った。

http://status.shookai.org

ソースコード
https://github.com/shokai/rocketio-arduino-sample


こういうのが表示されてるはず


物理的な意味ではこうなってる
R0020611


Arduino Firmata on Rubyで、ADコンバータに温度センサと明るさセンサを付けたArduinoを読んで0.3秒毎にSinatra RocketIOでブラウザにpushしている。

5秒毎にCPUとメモリ使用量もpushしてる。
あと新規接続/切断がある度に全クライアントに接続数を通知してる。


60行ぐらいのSinatra40行ぐらいの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::RocketIO

## 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
CPUとメモリは同じ要領で、psコマンドの結果をparseして送ってる。


Sinatra側で定期的に行う処理は、 Sinatra::RocketIO.once :start の中で登録すると良いです。
“start”はeventmachineとwebsocketサーバーの準備が整ったら発火するイベント。
onではなくonceなのは1回目だけ呼ばれるという意味。


あと、Arduino Firmataの最近のバージョンからeventmachine用の起動オプションを付けた。
ArduinoFirmata.connect "/dev/tty.usbデバイス名", :eventmachine => true
EM::runの中でこうやって起動するとThreadのかわりにeventmachineで動くようになった。
Sinatraの中で動かすときはこうしないと、タスク切り替えがうまくいかない。

0

Ubuntu/Debianでarduino_firmata動くようになった

これ → 64bit Ubuntu+Arduino UNOでarduino_firmataが動かないらしい

なおった。Raspberry Piでも安定して動くようになった。

serialport gemの read_nonblockとwrite_nonblockを使っていると、DebianやUbuntuで動かなくなっていたのでデフォルトでnonblock使わないようにした。


今まで通りノンブロッキングIOで使いたい人は接続時に

arduino = ArduinoFirmata.connect "/dev/tty.usb-device-name", :nonblock_io => true
で接続すればいい

Arduino Firmata on Ruby

0

64bit Ubuntu+Arduino UNOでarduino_firmataが動かないらしい

arduino_firmata


Ubuntu日本語フォーラム / arduino_firmataが動作せず 12.04/12.10


Ubuntu+Arduino UNOで

Resource temporarily unavailable

というエラーがでて動かないらしい
Ubuntu12.04の64bit版をVirtualBoxに入れてみたけど、CDC-ACMなArduinoはどれもデバイスとして認識しなかったのでエラーでるとか以前の問題だった。
VMじゃないUbuntuで試さないとならないっぽい・・


ニッチなgemのわりに毎日100インストールぐらいされてるので、すっかりRubyでArduino使うと定番になってるっぽくて嬉しい。

0

on :digital_read / on :analog_read

Ruby用Arduino Firmataライブラリにanalog_readとdigital_readの値が変わった時のイベントつけた


ふつうこうやってアナログ0番ピンをanalog_readするけど

require 'arduino_firmata'

arduino = ArduinoFirmata.connect
puts arduino.analog_read 0 # => 0 ~ 1023


これでアナログ値が変わった時にイベントが起こる
arduino.on :analog_read do |pin, value| # analog_read event
if pin == 0
puts "analog pin #{pin} changed : #{value}"
end
end



同様にdigital_readもHIGH/LOWが切り替わった時のイベントがとれる
arduino.pin_mode 7, ArduinoFirmata::INPUT

arduino.on :digital_read do |pin, status| # digital_read event
if pin == 7
puts "digital pin #{pin} changed : #{status}"
end
end


イベント管理はNode.jsのEventEmitterが便利だったので、それのRuby版を使ってる