0

Rubyでシリアルポートを使う(最新版)

■先にまとめ

gem install serialport
でインストールして、
require 'rubygems'
gem 'serialport','>=1.0.4'
require 'serialport'
必ずバージョン1.0.4以上をロードするように指定して使いましょう。


基本的なserialportの読み書きはこうやる。
実運用ではgetsは改行がくるまでブロックされるのでloopで回して待てばいい。
sp = SerialPort.new('/dev/tty.usb-serialdevice', 9600, 8, 1, 0) # 9600bps, 8bit, stopbit 1, parity none

line = sp.gets # read
sp.puts "echo:#{line}" # write



■詳しいこと
rubyでserialportを使う場合、/dev/ttyのデバイスファイルを直接読むか、それともruby-serialportというのを使うかの2通りの方法がある。
serialportのインストール方法は以前書いた。


で、この頃(2010年初頭)まではserialportのバージョン0.6を使うのが良かった。0.7が最新だったけど関数のインタフェースが変わったのにドキュメントが追いついてなくて使い方がわからなかった為。

でもこのserialport 0.6はrubygemsからインストールができなくて、適当にzipで拾ってきてインストールするしかなかった。


最近はserialport 1.0.4がrubygemsからインストールできて、MacとUbuntuで普通に使えるようになった。Windowsでもちゃんと動くらしい。
インタフェースも0.6と同じものになっている。

ただし、古いserialport 0.6がインストールされている環境では注意が必要で、なぜかgemをバージョン指定してrequireしないと0.6の方が読み込まれる。
しかも0.6のアンインストール方法がよくわからないので、
ぜひ皆様プログラムはこのように
require 'rubygems'
gem 'serialport','>=1.0.4'
require 'serialport'
書いてくれるといちいち修正して使う手間が省けるのでよろしくお願いします。


**********
こないだかず助に行ったときに、2ヶ月ぐらいめんどくさくてこのblog書いてなくてネタたまりすぎてヤバイという話をしたら、@ykfに毎日テーマを送って、書かなかったら怒られて消化していこうという事になったのでしばらく毎日書くことになった。毎日書けば1週間ぐらいで全部書ききれる。

0

SFCが使えるか確かめる

SFCが計画停電グループ1なのでしょっちゅう停電している。
ほぼ1日1回停電するし、停電するとサーバーで長い処理をしている人や3Dプリンタを使っている人はレジュームができなくて大変らしいので簡単にSFCの状況を調べられるツール作った。

gem install sfc_ikiteru
して(適宜sudoつける)

sfc_ikiteru

すると

というふうにどれぐらい生きてるかわかる。
物理的に離れてそうなサーバーがいくつか入っているので、これでどの建物が停電しているかもなんとなく察しがつくはず。


もちろん、gemなのでmoduleとしても使える。返り値はtupleで受け取る
require 'rubygems'
require 'sfc_ikiteru'
per, details = SfcIkiteru.ikiteru
p per
p details
perは1.0〜0.0の少数が返ってくる。生きているサーバーの割合。
detailsはhashで、詳細な値が入っている。


ソースはここにある https://github.com/shokai/sfc_ikiteru

作るうえでいくつか学んだこと

■binフォルダ
rubygemにbinというフォルダを作っておくと、gem installした時に適当にパスを通してくれる。
bin/sfc_ikiteru作ってchmod +xしておいた。


■terminal出力に色をつける
rainbow使った。
require 'rainbow'
puts "正常です".color(:green)
puts "応答なし".color(:red)
のように使う


■ping
rubyの標準ライブラリでpingがうてる
require 'ping'
Ping.pingecho('shokai.org', 5, 'echo') # timeout5秒
Ping.pingecho('shokai.org', 5, 'http') # timeout5秒、httpで

第三引数はechoを返さないサーバーならhttpとか適当な外向きに動いてるportを使うといい
でも1.9.2ではpingそのものが無くなってた。jrubyでは動くけどエラーがたくさんでる。


■newgemのエラー
newgemでgemの雛形を作っているんだけど、newgemはactive_support2系を使っている。
newgemもactivesupport2系も地味アップデートされていて、しかしactive_support3系が既に俺のマシンに入っているのでgem updateでも2系がアップデートされずよく依存のエラーがでる。よくある。


いつも適当に新しいバージョンのactivesupport2系を入れるとなんとかなる。
gem install activesupport --version=2.3.11

0

serial-http-gateway作った

シリアルポートをhttpで使えるツールを作った。
ブラウザでhttp://localhost:8783を開くとデータが読める。POSTでデータを送ると書き込める。

webブラウザでロボットを操作する部分がある、OB降臨システムというのを作っているのでその部品として作った。

githubに全部置いた。



■インストールと起動
git clone git://github.com/shokai/serial-http-gateway.git
cd serial-http-gateway
gem install serialport eventmachine eventmachine_httpserver json ArgsParser


Arduino等をMacに接続すると/dev/tty.usb〜〜という名前になる。引数に渡して起動する。
./serial-http-gateway --help
./serial-http-gateway /dev/tty.usbserial-A7006Rqn
port 8783で起動する。引数-portで変更できる。



gemが全て入っていれば実行ファイル単体で動くので、適当なパスが通っている場所にコピーして置くと便利。
sudo cp serial-http-gateway /usr/local/sbin/



■使う
HTTP POSTでシリアルポートに書き込める。
% curl -d 'testtest' 'http://localhost:8783'


HTTP-GETでシリアルポートからのデータが読める。
最近100件の受信データが保存してあって配列で返ってくる。timeに時間が入っている。
curl 'http://localhost:8783'


時間はミリ秒でunixtimeなので、1000で割れば普通のunixtimeになる
[{"data":287,"time":1296767483756},{"data":288,"time":1296767483253},{"data":291,"time":1296767482751},{"data":293,"time":1296767482246},{"data":292,"time":1296767481743},{"data":293,"time":1296767481238},{"data":294,"time":1296767480736},{"data":299,"time":1296767480233},{"data":303,"time":1296767479729},{"data":305,"time":1296767479226},{"data":307,"time":1296767478721},{"data":312,"time":1296767478219},{"data":321,"time":1296767477714},{"data":332,"time":1296767477211},{"data":344,"time":1296767476709},{"data":359,"time":1296767476204},{"data":"\u0000390","time":1296767475701}]


eventmachine_httpserver便利だなー

0

EventMachine::WebSocketでチャットを作る

Ruby & WebSockets: TCP for the Browser – igvita.comを参考にした。

websocketなのでchromeかsafariかiPhoneで動くけど、FirefoxとIEでは動かない。



■サーバー

サーバーはrubyのEventMachine::WebSocketを使った。
まずgemでインストールしておいて
gem install em-websocket


EM::runの中でEM::WebSocket.startするだけ。
1プロセスに複数クライアントつなぎっぱなしにして、全クライアントにまとめてメッセージを送るためにEM::Channelを使った。EM::WebSocketのexamplesの中に入ってたtwitterのstreamを流すサーバーでも使ってた。
EM::Channelにpushで何か入れると、あらかじめsubscribeで登録しておいたブロック全てにそれが渡されて実行される。onopenした時にsubscribeしておくとクライアントを管理できる。
server.rb
require 'rubygems'
require 'em-websocket'

MAX_LOG = 100

EM::run do

puts 'server start'
@channel = EM::Channel.new
@logs = Array.new
@channel.subscribe{|mes|
@logs.push mes
@logs.shift if @logs.size > MAX_LOG
}

EM::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen{
sid = @channel.subscribe{|mes|
ws.send(mes)
}
puts "<#{sid}> connected!!"
@logs.each{|mes|
ws.send(mes)
}
@channel.push("hello <#{sid}>")

# channel登録時のidを使うためにonopen内で他のイベント登録を済ませる
ws.onmessage{|mes|
puts "<#{sid}> #{mes}"
@channel.push("<#{sid}> #{mes}")
}

ws.onclose{
puts "<#{sid}> disconnected"
@channel.unsubscribe(sid)
@channel.push("<#{sid}> disconnected")
}
}
end

EM::defer do
loop do
puts Time.now.to_s
@channel.push Time.now.to_s
sleep 60*60*3 # 3時間ごと
end
end
end
websocketのつなぎっぱなし感を試したかったので、EM::deferも回しておいて3時間ごとにEM::Channelに時刻をpushしてみた。全チャットクライアントに時刻が表示される。


後から接続してきたクライアントのために、メモリ上に配列で100件ログを取っておくことにした。
新しいクライアントが来たらログの中身をまとめてsendする。プロセス自体はforkしないで全クライアントまとめて接続させてるからDBが必要ない。


サーバーは
ruby server/server.rb
でport8080で起動する。



■クライアント

次にクライアント。
ごくふつうのjQueryを読み込んだhtmlを書いておいて、
new WebSocketでサーバーに接続してonmessageとonopenとoncloseイベントを登録して、WebSocket.send関数で送信するだけ。
サーバーが再起動した時にそなえてoncloseしたらsetIntervalで定期的に接続しなおすようにすると良さげ。
var ws = new WebSocket("ws://localhost:8080");
ws.onmessage = function(e){
trace(e.data);
};
ws.onclose = function(){
log("ws closed");
};
ws.onopen = function(){
log('connected!!');
};

$(function(){
$('input#post').click(function(){
var name = $('input#name').val();
var mes = $('input#message').val();
ws.send(name+" : "+mes);
$('input#message').val("");
});
});

function log(message){
trace("[log] "+message);
};

function trace(message){
var mes_div = $('<div />').html(message);
$('div#chat').prepend(mes_div);
};



■動作環境

rubyとem-websocketがインストールされてればどこでも動かせる。

websocketは、httpの80番portと別のportで起動しないとならんのでさくらのVPSにubuntu10.04入れたサーバーで動かしてる。
server.rbのプロセスが死んでも復活するようにdaemontools使った。

0

エゴサーチツール feedim

エゴサーチツール feedimを作った。3ヶ月ぐらい使い続けている。
以前はtwitter検索で “shokai” とか検索した結果をRSSリーダーで読んでいたんだけど、最近ビリケン商会とか大塚商会とかキラキラ商会とか、 “shokai” をユーザ名やURLに含むtweetが増えてきたし、邪魔なbotからのtweetも除外したいのでなんとかするツールを作った。

で、feedを吐くのもいいけどせっかくAndroid持っているから、im.kayac.comを使ってAndroidにpush通知するようにした。
im.kayac.comを使っているのでGoogle TalkやiPhoneのpush通知でも受信できる。

主にtwitterで使っているけど、feedなら何でも定期的に監視できる。
ソースはgithubにある github.com/shokai/feedim


先にim.kayac.comでユーザ登録して通知先を設定しておいてください


■インストール

git clone git://github.com/shokai/feedim.git


■必要なもの
mongodb 1.6以上が必要。起動しておく。

必要なrubygemsは、bundlerで入れる。

cd feedim
gem install bundler
bundle install
mongoid2betaとか、俺が以前作ったim-kayacのgemとかがインストールされる。


■設定
config.yamlファイルを作る。

cp sample.config.yaml config.yaml
config.yamlファイルを編集する。上の方でim.kayac.comのユーザ名とか、認証タイプを選ぶ。MongoDBのDB名とかも選ぶ。



監視するfeedを列挙する。除外したい内容をfilterに正規表現で書く。
filterは本文とURL両方にかけるfilterで、description_filterとurl_filterはそれぞれ本文とURLどちらかにかけるフィルタ。
# list of feeds
feeds :
- "http://search.twitter.com/search.rss?q=shokai"
- "http://search.twitter.com/search.rss?q=%E6%A9%8B%E6%9C%AC%E5%95%86%E4%BC%9A"
- "http://search.twitter.com/search.rss?q=%E6%A9%8B%E6%9C%AC+%E7%BF%94"
- "http://search.twitter.com/search.rss?q=%E3%81%8B%E3%81%9A%E5%8A%A9"
- "http://search.twitter.com/search.rss?q=%E3%81%8B%E3%81%9A%E3%81%99%E3%81%91"
- "http://search.twitter.com/search.rss?q=%E3%83%8F%E3%82%B7%E3%83%A2%E3%83%86%E3%82%A3%E3%82%A6%E3%82%B9"

# filter by "url" and "description" property of entries
filters :
- "honeybee-cd"

# filter by "description" property of entries
description_filters:
- "_shokai"
- "shokai_"
- "\-shokai"
- "shokai\-"
- "shokai\.co"
- "shokai\d"
- "\dshokai"
- "キラキラ商会"
- "ビリケン"
- "大塚商会"

# filter by "url" property of entries
url_filters :
- "twitter\.com\/shokai\/"
- "twitter\.com\/shokai_log\/"
- "bot"
- "kirakira"
こんな感じに書くと、ほぼ橋本商会とかshokaiは全部漏らさずに、ビリケン商会とか大塚商会とかキラキラ商会とか、邪魔なbotを除外できる。



■動かす
クロールして、IMとAndroidに送る。
ruby store.rb
ruby publish.rb

crontabで10分おきに実行している。