1

NodeにArduinoのコードを埋め込む arduino-firmata npm

作った。

インストール

% npm install arduino-firmata

https://npmjs.org/package/arduino-firmata


以前作ったruby版android版と同じ実装なのと、coffee-scriptがほとんどRubyなので一瞬でできた。
JSのビット演算子の優先順位がrubyなどより低いらしくて、より過剰にカッコつける必要があった。


既存のライブラリとの違い

johnny-fiveが有名だけど、より普通のfirmata(proce55ing版のオリジナルのやつ)っぽい書き方ができるようにした。関数名がarduinoと同じなので学習コストが低い。
firmataはdigitalRead/analogReadがコールバック返してくるけど、それは使いにくいので(例えばピン1がHIでピン2がLOWの時〜という条件式が書きにくい)値を返す普通の関数として実装した。

ようするにarduino使ったことがあるならすぐ使えるようにした。


使い方


まず
Arduino IDE -> [File] -> [Examples] -> [Firmata] -> [StandardFirmata]
をArduinoに書き込む。これでnodeからの命令を受けて動くarduinoになる。

くわしくは
https://github.com/shokai/node-arduino-firmata#readme


12, 13番ピンのLEDを点滅させる例
ArduinoFirmata = require 'arduino-firmata'
arduino = new ArduinoFirmata().connect()

arduino.on 'connect', ->
stat = true
setInterval ->
console.log stat
arduino.digitalWrite 13, stat
arduino.digitalWrite 12, !stat
stat = !stat ## blink
, 500

なおconnectはArduinoっぽいデバイスを適当に探して接続するが、引数にデバイスへのパスを入れて指定もできる。connect(“/dev/tty.usb-device”)

他にdigitalRead, analogRead, analogWrite, servoWrite, sysex、入力が変化した時のanalogChange, digitalChangeなどが実装してある。
https://github.com/shokai/node-arduino-firmata#io



socket.ioと一緒に使う例

samples/serverに入れておいた物の抜粋

  • センサー読んで値が変わったらsocket.ioでクライアントに送る
  • クライアント側でボタン押したらLED点灯/消灯

server.js
var io = require('socket.io').listen(app);

var ArduinoFirmata = require('arduino-firmata');
arduino = new ArduinoFirmata().connect();


// センサー(A0)の値が変化していたらHTML側に送る
arduino.on('analogChange', function(e){
if(e.pin != 0) return;
console.log(e);
io.sockets.emit('analogRead', e.value);
});

io.sockets.on('connection', function(socket) {

// 初回接続してきたクライアントに最新のセンサーの値を送る
socket.emit('analogRead', arduino.analogRead(0));

// HTML側のボタンをクリックしたら、LED点灯/消灯
socket.on('digitalWrite', function(stat) {
console.log("pin13:"+stat);
arduino.digitalWrite(13, stat);
});

});

0

HTML内のJavaScriptへのJSON埋め込み

Jadeでこういう風に書いている箇所があった


http://node-linda-base.herokuapp.com/test?a=%3C/script%3E%3Cmarquee%3E

script.
var name = "#{name}";
var tuple = !{JSON.stringify(tuple)};
script(src='/socket.io/socket.io.js')
ユーザーからの入力によって生成されたサーバー側の変数tupleをjsonにしてから、ブラウザ側のjsの変数に渡している

こういうHTMLが出力される


ただし</script>という文字列がjson中に現れるとそこでscriptタグが終わって、なんでも出来てしまい

こうなる

もちろんmarqueeではなくscript src=も埋め込める


最終的にこう書いた

script.
var name = "#{name}";
var tuple = JSON.parse(unescape("!{escape(JSON.stringify(tuple))}"));
script(src='/socket.io/socket.io.js')
サーバー側の変数tupleをescape済みのjson文字列にしてブラウザに渡し、ブラウザ側でunescape後にJSON.parseしてJSの変数にした。

こういうHTMLが出力される。


これで正しいのかな?

0

Ruby版socket.io用クライアント 自動再接続機能付けた

node版にもともとある機能だけど、切断されたら自動的に再接続する機能をv0.0.3から付けた。
あとTravis CIでテストするようにした。

https://github.com/shokai/ruby-socket.io-client-simple


もともとwebsocket-client-simple gemに切断時のイベントがあるんだけどnode版と同じようにサーバーからのheartbeatのタイムアウトで判定するようにした。

切断されたらランダムに20〜40秒待ってから再接続する。


サンプルコード、rubyのとcoffee-scriptと入れておいた。ほぼ同じ感じで書けてよい。

0

Ruby用のsocket.ioクライアント作った

node.jsのsocket.ioのRubyクライアントライブラリ作った。

rubygems.orgに既に他に2つ実装があるものの、1つは古く、もう一つはruby2.0で動かずプロジェクトが生きてない感じだったので、車輪再発明した。

socket.ioはwebsocketとかajax pollingとかflashとかiframeとかいろいろ使うけど、rubyなのでwebsocketしか実装しないことにした。

昨日のmix-inした関数を上書き定義前にalias_methodで退避するで、event_emitterとwebsocket-client-simpleにほとんど任せてるのでそんなに面倒でもなかった。70行ぐらいで実装できた。


インストール

gem install socket.io-client-simple


ソースコード

https://github.com/shokai/ruby-socket.io-client-simple

不具合などあったら@shokaiかgithubのissueにお願いします


使い方


接続
samples/sample.rb
require 'rubygems'
require 'socket.io-client-simple'

socket = SocketIO::Client::Simple.connect 'http://localhost:3000'

socket.on :connect do ## 接続イベント
puts "connect!!!"
end

socket.on :disconnect do ## 切断イベント
puts "disconnected!!"
end

## サーバーからイベント"chat"がemitされたら、このコールバックが呼ばれる
socket.on :chat do |data|
puts "> " + data['msg']
end

puts "please input and press Enter key"
loop do
msg = STDIN.gets.strip
next if msg.empty?

## サーバーにchatイベントを送る
socket.emit :chat, {:msg => msg, :at => Time.now}
end


サーバー側の実装は普通にsocket.ioのリファレンス実装みたいな感じ。

samples/chat_server.js
// socket.io chat server

var io = require('socket.io').listen(3000);

io.sockets.on('connection', function(socket){
socket.emit('chat', {msg: 'hello world (from server)'});
socket.on('chat', function(data){
console.log(data);
socket.emit('chat', data); // echo
});
});


まだ切断したら自動再接続する機能ないけど、すぐ実装する予定。

0

mix-inした関数を上書き定義前にalias_methodで退避する

用途

Ruby版EventEmitterなどのincludeして既存クラスを拡張するタイプのライブラリを使う時に、mix-inされる関数と自分の関数の名前が衝突してしまう場合に有用。

Ruby用のsocket.io実装を作っているんだけど、EventEmitter gemで定義されているemit関数を__emitに退避してemitを新たに自分で定義するのに使った。


alias_methodで関数名の衝突を回避する

module Fooをclass Barにincludeした時に、FooにもBarにも同じ関数を定義している場合、クラスの方に定義した関数の方が優先される。
モジュールの方の、せっかくincludeでmix-inした関数は消滅してしまう

includeしたmoduleの方の関数fooも使いたい場合、includeしてすぐにalias_methodで別名に退避するとよい。

module Foo
def foo
puts "foo called!!"
end
end

class Bar
include Foo
alias_method :__foo, :foo ## fooを別名(__foo)に退避

def bar
puts "bar called!!"
end

def foo
puts "Bar's foo called.."
end
end


bar = Bar.new
bar.bar
bar.__foo # include後に退避したmoduleの関数が呼ばれる
bar.foo # include後に上書きした関数が呼ばれる


結果
bar called!!
foo called!!
Bar's foo called..


alias_methodのタイミング

関数の上書き定義後にalias_methodを使っても、退避できない。

module Foo
def foo
puts "foo called!!"
end
end

class Bar
include Foo

def bar
puts "bar called!!"
end

def foo
puts "Bar's foo called.."
end

alias_method :__foo, :foo ## 上書き定義した後にエイリアスでの退避を試みる
end


bar = Bar.new
bar.bar
bar.__foo
bar.foo

fooも__fooも、どちらも上書き定義されたメソッドが呼ばれる。
bar called!!
Bar's foo called..
Bar's foo called..

ちなみにもちろんinclude前にalias_methodしても、NameError(undefined method)例外が起こる。