オシロスコープの3つめ。諸事情でRubyをつかっていた部分をすべてNode.jsにしました。決してRubyがキライになったからじゃないですよ。
全力で稼働中
ひとつ前と変わらずNode Ninjaさんで動かしています。→こちら←。仕組みの解説をします。
サーバ側
いままではNode WebSocket Serverをつかい、生のWebSocketをつかってブラウザに送っていましたが、今回からSocket.IOをつかうことにしました。なぜか。生WSのときは、Arduinoで読み取った信号の受け口とブラウザ送信の送り口を同じエンドポイントで運用していました。これだと特にKUFUをしない限り、誰でもサーバにメッセージを投げられて、全てのブラウザに送信されてしまいます。いままではサーバ起動後すぐにArduino側のスクリプトを起動しサーバに接続、IDを保存しておいてそのIDから来たメッセージのみブラウザに送信するとしていたのですが、なんとなくスマートじゃない。これを、Socket.IOの名前空間を利用して解決しています。
名前空間(Namespace)とは
ブラウザからSocket.IOを利用してサーバへつなぐ際に、log.niccol.li/hogehogeのようにサーバ名+文字列を指定することができます。スラッシュ以降が名前空間と呼ばれる機能で、指定した文字列ごとにサーバ内で処理を分岐させることができます(詳しくはこちら)。受信用・送信用に名前空間を分け、ブラウザからは送信専用のエンドポイントを指定することで分離を実現させています。
Arduino中継側
「ArduinoがanalogReadの値をシリアル通信で送信、受けたPCがWebSocketでサーバへ送信」の流れは変わっていません。いままではここをRuby/EventMachineで記述していましたが、サーバでSocket.IOを使い始めたのにあわせてNode.js+Socket.io-clientに置き換えました。前述の名前空間をつかい、Arduinoからの信号受信用のエンドポイントを指定しています。
ここでNode.jsに置き換えたことでちょっと変化が。シリアル通信を読むときに、EventMachineではたまに改行を見落とすため、異常な値が送信される問題がありました。これがNode.jsでは起こらないんですね。モジュール内部も含めて、シリアルポートから読み出したあとの処理に差異はみられないため、読む処理そのものの問題なのかなと。違う点といえば、NodeはTTYも含むI/Oをlibuvでまかなっているため、ノンブロッキング処理になっていますが、Rubyのほうはブロッキング処理のよう。改行で文字列を分割するタイミングとTTY読み出しが当たるととぶのかなと思ってはいますが、どうやって確かめたらいいんですかね。