まりぴよこのブログ

日々の日記。技術ネタでまとまりきってないものの記録、伝わる文章の書き方を練習とか。

Arduinoで計測したセンサー値をNode.jsのサーバーで受け取る

Arduinoから計測値をサーバーに送りたい

野望

電子工作の知識ゼロで、Arduinoから計測した値を元に、チャットに有益な情報を流す!

小さないっぽ

とりあえず、Arduinoで明るさセンサーを使って、部屋の明るさを計測し、刻々とサーバーに送り続けるものを作る。

受け取った値をブラウザで確認したい(しかも刻々と送られるので、いちいちブラウザリロードとかしたくない)ので、Node.jsでSocket.ioサーバーを立てて、値を確認したい。

今回は実験的データなので、別にDBとかに格納する気なし。。 送られた値をチャットみたいにブラウザにつらつら表示出来れば良い。

完成図(略)

f:id:mpiyok:20141129230249p:plain

Arduino側の壁

参考ページ:XBee Wi-FiをWebに接続する - Qiita

↑正直ここの情報がなかったら、頓挫していた・・ ほんとうにありがとうございます。。

回路を用意、センサーで値を計測

本の丸写しで回路とスケッチを用意する。 ここで余計なことは書かない・・ 電気への理解はホント幼稚園児並みなので、気がついたらまったくでたらめの値を送信していたりしてた。。(抵抗がちゃんとGNDに繋がってないとか・・) 電気のことは折を見て0から勉強し直したい。。

値を送信する

もちろんはんだづけも出来ないので、完成系の部品を集める。。

Xbee WifiArduinoを接続するためにコレを購入。

Arduino ワイヤレスSDシールド - スイッチサイエンス

このシールド上にあるちっこいスイッチを切り替えると、Arduinoのシリアル通信がUSB側に行くのか、Wifi側に行くのか切り替えられるらしい。

スイッチをMICRO側にすると、Arduino

Serial.println(data);

が、Wifiにのって、お外のサーバーに送られるのだ。

ネットワーク系のプログラムだと思って、ふつーのクラサバでのアプリを元に想像していたので、びっくりです。。 IPもポートも指定しないなんて・・・ というか、Xbee Wifiは専用コマンド(AT)で接続先を設定しておいて、後はそこにひたすら接続するようです。 シリアル通信プログラムがWifiになったイメージなんですね。。

xbee_wi-fi Arduino Freaks - マイコンボードArduinoの情報

このページがめっちゃ参考になった。 しかし内容を理解出来たのは7回目くらいに読み返した時だったかも・・・

Arduino側まとめ

  • Arduinoのどんな本にでも載っているであろう、Cds cellから読み取った値を、Serial.println(val);するだけ(なのでスケッチ載せません・・)
  • Xbee Wifiを乗っけるだけで、1週間以上もがき苦しんだ・・

面倒なことは全てサーバー側でクリアすることにした・・・

というわけで、Arduinoからは単に数値がポツポツと送られてくるのみ。

後の全てはサーバー側でなんとかする方針になりました。。

Socket.ioで受け取った値をリアルタイム通知したい

Socket.ioといえばNode.js。Node.jsといえばSocket.io(←・・そう?)というくらいなので、サーバーサイドは迷うこと無くNode.jsにします。 ・・が別にNodeが得意な訳ではありません!

まずはどんなNode.js本やサイトにも山ほど載っている、Socket.ioを使ったチャットWebアプリの構築です。 (これまた幾らでも参考があるのでコード載せない気・・)

こんな感じの最小構成で用意。

Node.js + Socket.IO + jQuery で最小構成チャット - Qiita

ArduinoからSocket.ioにつなげない(私の力では・・)

さて。Socket.io動くぜ〜(ブラウザから確認した) Arduinoからつなげるぞ!

・・・って無視されてる〜〜 Arduinoから送信した数値は受け取ってもらえませんでした・・・

何故だ・・困った・・

そんなときは同じくprimitiveなアイツ、telnetさんで試してみる! (Socket.ioのサーバーをポート3000にした想定)

telnet localhost 3000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
123   # ←ここ私入力したとこ
Connection closed by foreign host.

数値入力・・Enter!でいきなり接続切られた・・

しーん・・・ な・・なんで・・そういうもんなの? と思って調べた結果・・

MeSH日記: WebSocketを試す

ただし、telnetコマンドではWebSocketサーバと通信できません。
いや、正確には可能なのですが、繋がった後に渡すパラメータが複雑なので現実的ではありません。

・・そ・・そうなんですか・・??

さあ、どうする・・諦めるか?WebSocket・・・(涙)

Node.js の Tcp serverで値を受け取る

なんとかこのプリミティブな感じで受け取ってくれるサーバーは無いものか・・ 最悪HTTP POSTするのだろうか・・くそ〜と思っていたところ、解決策の光明が!

そうだ!TCP server!!

解決策にであったのは買ったばかりのこの本。 いきなり後ろの方のTCP serverのところから役立ったけど、全体的に非常に良さそうです。 (これからゆっくり読みます・・)

数時間前にやったSocket.ioのコードとほんとそっくり。 でも今度はちゃんとtelnetでも値を受け取ってくれました。 やった〜

Arduinoからのシリアル通信もバッチリNodeのコンソール出力に出た!やった〜やった〜〜

ここで一カ所だけ頑張ったところ・・

tcp serverの受け取るdataはバイナリなので、そのまま出力すると読めない。。 toStringで文字変換すると、送った数値が取れます。

socket.on('data', function(data) {
  var line = data.toString();
  console.log('got "data"'+line);
});

Tcp serverからSocket.io serverに値を送る

後はこの2つのNode.jsのコードをつなげて一緒に使えればOK・・なんですが、ここでめちゃくちゃつまづきました・・ 全ては私のNode力の無さから。。

tcp serverのdataを受け取ったところから、どうやってSocket.ioのイベントを呼べば良いのかわからず、半日苦戦してた・・ 別に普通に呼べば良いだけだった・・・・

別々に書いていたSocket.io部分とTcp部分をがっちゃんこして一緒のファイルに書いて、呼び出したいところでio.socets.emitで良かった。。

もしかしてhttpとsocket.ioが一緒のポート使ってるみたいに、うまく連結してpipeとか出来るのだろうか?と思って散々サンプル探しまわったけど、それらしいものを見つけられず・・・ tcpとsocket.ioサーバーで2個別々のポート使う状態にしてしまったので、改善方法がある様な気がする・・・ 同じSocketなんだし・・・

いつかNodeレベルアップしたら戻ってきたい。。(遠い目)

完成

Node.jsの完成コードだけ。

次なるステップ

これでやっと対象の部屋の明るさをブラウザで確認できるようになった。。 D3.jsとかでグラフ表示できたらいい感じなんだけどな〜〜