netatmo ウェザーステーションを買ってAPIを叩いてみる
netatmo ウェザーステーションとは
その名の通り気象情報をセンサーで取得するデバイスです。基本構成は2つのセンサーデバイスで、大きいほうが室内用、小さいほうが屋外用となっています。電源は室内用はUSBから、屋外用は単4電池2本で駆動します。それぞれのセンサーから取得できるデータは以下になります。屋外用のセンサーというのは実はありそうで無いので、ベランダなどに設置しておくと今の屋外気温が取得できるので面白いです。
室内用
- 気温
- 湿度
- 気圧
- CO2
- 騒音
屋外用
- 気温
- 湿度
これを設置してユーザ登録してログインすると、PCではこんな画面でデータを見ることができます。
※地図の部分はボカしています
ちなみに、全世界の今の気温もGoogleMap上でみることができます。クリック
また、iPhoneアプリ、Androidアプリもあります。Androidではウィジェットに設定できるのでこれは便利!です。
IFTTTと連携
このデータを元にIFTTTを使って連携しようと考えました。例えばこんな感じのレシピを作れます。
これは「湿度が10%を切ったら、Tweetする」ということになります。とはいえ、本当にやりたかったのは「毎朝8時に、今の屋外の気温をTweetする」のようなことがしたかったのでこれはイマイチです。IFTTTではnetatmoウェザーステーションはトリガーにしか使えない、かつこの場合、3つの事象が含まれるのでIFTTTでは実現できません。
netatmoのAPIを利用
というわけで、netatmo APIを利用して作ることにしました。ここにアクセスして、「MY APPLICATIONS」を登録することでAPIを叩くことができるようになります。
APIの取得の仕方等はNetatmo ウェザーステーションを買ってみたので Node.js でいじってみたを参照して下さい。
今回はVPSを使わず、手元にあったRaspberry Piを使用して、下記のような構成を作ってみました。
- Raspberry Pi + Ubuntuを使用
- netatmo-api-pythonを使ってPythonスクリプトを作成
- TwitterのOAuthはrequests_oauthlibを使用
- cronを設定して毎朝8時にPythonスクリプトを実行し、最新データを取得してTwitterに投稿する
- 屋外は「温度」「湿度」のみが取得しかできないので、ここにある不快指数の計算式を使って、不快指数を同時にTweetしています
結果
気温: 19℃ 湿度: 68% 不快指数: 65 @さいたま 2014-05-02/07:59 #netatmo
— 繋がれたひよこ (@tomo_watanabe) 2014, 5月 1
これはこれで簡単にできるので、もう少し色々連携させたくなってきました\(^o^)/ Raspberry Pi上でMQTTのブローカーを導入して、周辺デバイスと連携とか
【日本正規代理店品・保証付】Netatmo ウェザーステーション NET-OT-000001
- 出版社/メーカー: Netatmo
- 発売日: 2013/10/10
- メディア: エレクトロニクス
- この商品を含むブログ (1件) を見る
インターネットとハードウェア
組込みプログラミングの必要性
プログラミングというとPC上でのプログラムが普通ですが、最近感じているのは組込み系のプログラミングの重要性です。単に組込みプログラミングというだけではなく、デバイスとネットワークを扱うためのプログラミングと言ったほうがいいかもしれません。
理由は下記の通り
- 身近なものがインターネットに繋がる、モノのインターネットではデバイスを扱うことが必須
- 子供の頃から見たり触れたりするのは実体のあるデバイスであり、プログラミングは実体のあるデバイスを動作させることで興味を持つことができる
- 組込み系のデバイスのプログラムが書けるのは、おっさんばかり。若い人はこれが出来ると需要がありそう
- ハンダ付けや簡単な電子回路の知識もついでに身につく
とはいえ、最近のデバイスはそこまでの知識が必要なくてもハードウェアを叩けるようになってきているので、まずはそこから始めるのがいいでしょう。
何から始めるか?
Arduino
言わずと知れたプロトタイピング用デバイス。IDEもありC言語ライクに書ける。情報も圧倒的に多くとりあえず始めるならコレ。ただしネットワーク周りはやや貧弱で、イーサネット対応しようとするとコストが高く、別の選択もあり
Raspberry Pi
最近流行りの小型PCボード。拡張性は低いけれどもGPIO周りは多くの情報があり、Linux扱える人ならなら敷居が低い。ネットワークも普通に使える(実際には組み込みボードとは言い難い)
Espruino
JavaScriptで書けるデバイス。Web系の人が入るには良さそう。KICKSTARTERで募集中(2013/9/1現在調達達成)。ポチった
TESSEL
こちらもJavaScriptで書ける。WiFIを搭載し、Node.jsも動く。こちらも購入予定
「モノのインターネット」を考えると、今流行のArduinoでは限界が見えている気がします。もう少しリッチなデバイスで、かつArduinoの手軽さでネットワークが扱える。というのが求められているのでしょう。後者の2つはそこを狙っているように思います。ルネサスからSAKURAボードというArduino互換に近いボードが出ているのですが、僕が使った感じではTCPライブラリに問題があるようで(TCPをクローズしてくれない)、ネットワークを扱うのは避けたほうがよさそうです。
ARMマイコンを使えるように
もっと簡単にレゴロボットでプログラムを学習しよう。とかいうのも導入的にはありだと思いますが、やはりゴールはCPUアーキテクチャやメモリマップ、レジスタ制御などをきちんと理解してプログラムが書けるようになっておきたいものです。というわけで、個人的に最近使っているArduinoに限界を感じたためARMマイコンの勉強を始めました。ゴールはCortex-Mシリーズを使えるようになること。昔はSHマイコンでμITRONとかやっていたのですが、すっかり錆びついているため思い出しながら始めます。
- ARM32ビットマイコン電子工作キット まずはこれから。DIPタイプのARMマイコンが付属している。アーキテクチャなどの記述もあるので、再入門に良さそうなので購入済
- LPC1768-Xplorer Cortex-M3マイコン。上記セットを学習した後購入予定
おまけ
ThinkITさんで、「Raspberry PiとNode.jsで作る独立稼働モバイルサーバ」という記事を書きました。Raspberry Piを使ってNode.js + ハードウェアでサーバ型カーナビを作る。というものです。
AndroidやiPhoneがもたらしたのはスマートフォンだけではなく、32bit組込みマイコンのコストが下がり、LinuxなどのリッチOSが載るようになりました。Arduino, Raspberry Piそしてこれから出るであろう様々なデバイス。インターネットとハードウェアの融合はこれからが楽しい時になりそうです\(^o^)/
node-serialportを使ってNode.jsでArduinoと通信する
node-serialportとは
Node.jsでシリアルポートを制御できるようにしたライブラリ。今回はこれを使ってNode.jsとArduinoをシリアル通信で接続します。今回のターゲットは2種類。まずはMac + Arduinoで動作を確認した後、Raspberry Pi + Arduinoで動作させてみます
※2013/3/30 データ受信取りこぼしの件で、修正パッチを頂きました。 @kei_os さんありがとうございます
node-serialportのインストール
まずはMacの方でインストールします。ここを参考にexpressをインストールし、Socket.ioもインストールしておきます。node-serialportのインストールはnpmを使います。
$ npm install serialport
サーバの記述
serialportの使い方だけ抜粋します。
serialportの宣言をしておきます。
var express = require('express') , routes = require('./routes') , path = require('path') , serialport = require('serialport');
MacでArduinoを接続した時のシリアルポートを調べておき、portNameに指定します(接続時に毎回変わる場合もある)通信設定はよくあるパターンですね。パースの単位を改行で行うように設定し、ArduinoからのJSON形式の送信データの末尾に改行を付加するようにします。今回は通信速度を115200にしていますが、なぜか9600だとデータ受信で取りこぼす確率が高く使い物になりませんでした。ただし115200にしてもデータを取りこぼすことが結構あり、どうしてこうなるのか原因調査等した方がいらっしゃいましたら教えて下さい。(正直言って信頼性に欠けるので、プロトタイプ以外には全然ダメ)※2013/3/30修正パッチでbugfixしました
// Serial Port var portName = '/dev/tty.usbmodemfd13431'; // Mac環境 var sp = new serialport.SerialPort(portName, { baudRate: 115200, dataBits: 8, parity: 'none', stopBits: 1, flowControl: false, parser: serialport.parsers.readline("\n") // ※修正:パースの単位を改行で行う });
Arduino → Node.jsの受信の部分です。データ列として受信するので、一旦Bufferで受けておいてJSONでパースしています。データ列が正常に完全な形で受信できなかった場合は、無視するようにしています。
// data from Serial port sp.on('data', function(input) { var buffer = new Buffer(input, 'utf8'); var jsonData; try { jsonData = JSON.parse(buffer); console.log('temp: ' + jsonData.temp); console.log('led: ' + jsonData.led); } catch(e) { // データ受信がおかしい場合無視する return; } // つながっているクライアント全員に送信 io.sockets.json.emit('message', { value: jsonData }); });
Arduino側の実装
Arduinoには温度センサー(LM35Z)とLEDを載っけてあるので、それを制御してみます。loop()を5秒で回して、温度とLEDのON/OFFをJSON文字列としてシリアル送信します。Node.js側では受信した温度の表示を行い、ブラウザを通してArduino上のLEDのON/OFFを行えるようにしました。 コードはここ
Macで動かしてみる
気温が表示され、LEDのON/OFFコントロールがブラウザ上からできるようになっています。ただし、Arduinoのループ周期が5秒に設定してあるので、LEDのコントロールは最大5秒待たされることになります。
Raspberry Piで動かしてみる
同じコードをRaspberry Piで動かしてみます。コードはGithubで管理しているので、Raspberry Piにログインしてから、git cloneしてコードを取ってきます。ここでは、すでにRaspberry Piにはnvm, npmおよびNode.jsがインストールされているものとします。ArduinoをUSBでRaspberry Piに接続してlsするとそれっぽいのが見つかります。ArduinoはttyACM0になりますので、app.jsのportNameを書き換えます。(ttyAMA0はRaspberryPiの内蔵シリアルポート)
$ ls /dev/tty* /dev/ttyACM0 /dev/ttyAMA0
なにはともあれ動かしてみます(えいやっ
$ node app.js /home/pi/work/Node-SerialPort/NodeServer/node_modules/serialport/node_modules/bindings/bindings.js:77 throw e ^ Error: /home/pi/work/Node-SerialPort/NodeServer/node_modules/serialport/build/Release/serialport.node: invalid ELF header at Object.Module._extensions..node (module.js:485:11) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.require (module.js:362:17) at require (module.js:378:17) at bindings (/home/pi/work/Node-SerialPort/NodeServer/node_modules/serialport/node_modules/bindings/bindings.js:72:15) at Object.<anonymous> (/home/pi/work/Node-SerialPort/NodeServer/node_modules/serialport/serialport.js:7:44) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32)
さすがにnode-serialportはmacと同じ環境ではないのでダメなようです。一旦serialportをアンインストールして、再インストールします。Raspberry Piではnode-serialportをグローバルインストールしてリンクを作成して使うようにしました(他でも使うかもしれないので)
$ npm uninstall serialport $ npm install -g serialport $ npm link serialport
これでもう一度起動してみます。
先ほどのMacと同じように動きました。
今回のコードはGithubに置いてあります。コードはMacで動作するコードなので注意して下さい。 ※2013/3/30 データ取りこぼしの件bugfixしました
Raspberry Piにリバースプロキシを導入する
Raspberry PiにNode.jsを入れて動かしていましたが、Raspberry Piにリバースプロキシを導入して、サブドメイン名でApacheとNode.jsの切り替えをしてみます。リバースプロキシにはWebSocketを透過するnode-http-proxyを導入します。できるだけ手順をそのまま書いたつもりですが、何か不必要な部分があったり、間違ってる箇所があるかもしれません。ネットワーク周りは勉強中なので備忘録代わりに書き残しています。(そもそもリバースプロキシ自体初めて知った...)
Apachをインストールして、デフォルト80でリッスンするのを8080でリッスンするように変更します。リバースプロキシは80をリッスンして、サブドメイン名によってApacheの8080とNode.jsが動いている3000へ振り分けるようにします。
Apacheのインストール
$ sudo apt-get install apache2
きちんと動作しているか、Rasberry Piにアクセスして確認します(ここでは192.168.0.7になっています)
Raspberry Piのデフォルトのランレベルは
$ less /etc/inittab
で見てみると
# The default runlevel. id:2:initdefault:
Apacheをインストールすると自動起動になるようなので確認します。
$ ls /etc/rc2.d/ K01lightdm README S01motd S01triggerhappy S03dbus S03pulseaudio S05plymouth K05nfs-common S01bootlogs S01rsyslog S02apache2 S03dphys-swapfile S03rsync S05rc.local K05rpcbind S01ifplugd S01sudo S03cron S03ntp S03ssh S05rmnologin
"S02apache2"というのがあるので、起動時にapacheが自動起動します。自動起動させたくない場合は
$ sudo update-rc.d apache2 remove
とします。自動起動に再設定するには
$ sudo update-rc.d apache2 defaults
Apacheのリッスンポートを8080に変更
デフォルトでApacheは80をリッスンするので、これを8080に変更します。viやemacsのエディタでルートユーザ権限で編集します。
$ sudo emacs /etc/apache2/apache2.conf // 以下を追記 <VirtualHost *:8080> DocumentRoot /var/www/ ServerName web.raspberry.pi </VirtualHost> $ sudo emacs /etc/apache2/ports.conf // 以下を修正 NameVirtualHost *:8080 <-- 80から8080 Listen 8080 <-- 80から8080
修正したら、Apacheを再起動して8080で接続できるか確認します。
$ sudo service apache2 restart // 80ではエラー $curl http://localhost:80 curl: (7) couldn't connect to host // 8080で接続OK $ curl http://localhost:8080 <html><body><h1>It works!</h1> <p>This is the default web page for this server.</p> <p>The web server software is running but no content has been added, yet.</p> </body></html>
これでApacheは8080で接続できるようになりました。
リバースプロキシのインストール
今回はWebSocketに対応したリバースプロキシを導入したいので、node-http-proxyをインストールします。グローバルでインストールします。参考サイト
$ npm install -g http-proxy
どこかに作業用ディレクトリを作成して、グローバルインストールしたモジュールのリンクを作成します
$ mkdir reverse_proxy $ cd reverse_proxy $ npm link http-proxy /home/pi/work/reverse_proxy/node_modules/http-proxy -> /home/pi/.nvm/v0.8.16/lib/node_modules/http-proxy
proxy.jsを作成します。
/** * node-http-proxy */ var port = 80; var httpProxy = require('http-proxy'); var options = { hostnameOnly: true, router: { 'web.raspberry.pi': '127.0.0.1:8080', 'node.raspberry.pi':'127.0.0.1:3000' } }; var proxyServer = httpProxy.createServer(options); proxyServer.listen(port); console.log('It Works!');
これで、
- web.raspberry.pi → Apache
- node.raspberry.pi → Node.js
へ振り分けできるようになるはずです。
hostsファイルの追記
今回はローカルネットワークで動作させるので、クライアントのブラウザの設定とhostsファイルの書き換えが必要になります。
hostsファイルにはRaspberryPiのIPアドレスと設定したいサブドメインとセットで追記します。ブラウザの設定にも下記のアドレスの場合はプロキシ設定を行わない等の設定が必要になります
# hostsファイルに下記のようにRaspberryPiのIPを追加 192.168.0.7 web.raspberry.pi 192.168.0.7 node.raspberry.pi
リバースプロキシの起動
80ポートをリッスンするにはスーパユーザじゃないとできないので、
$ sudo node proxy.js sudo: node: command not found
nodeコマンドが無いと怒られてしまいます。仕方ないのでちょっと強引に起動させますw
$ sudo su # source /home/pi/.nvm/nvm.sh # nvm use v0.8.16 Now using node v0.8.16 # node proxy.js
この状態でクライアントブラウザから"web.raspberry.pi"へアクセスしてみて"It Works"と出れば、無事リバースプロキシとして動作しています。
Apache(8080)へアクセス
では以前に動かしたNode.jsのプログラムをポート3000で動作させて、最終的にリバースプロキシとしての動作を確認します。
Node.js(3000)へアクセス
まとめ
Raspberry Piでリバースプロキシを動かしてみました。Apache上ではPukiWikiを動かしたり、Node.js側で動作するプログラムの設定を変更したりということができるかもしれません。ルーターとかでは、設定を特定のアドレスで行ったりしていますが、あんな感じでしょうか。Linuxの組込み機器系ではよくありそうな構成なのかもしれません(組込みLinuxの開発経験ナシ)今回のWebSocketを透過するリバースプロキシは、リアルタイムWebデバイスとしての実装には有効な気がします。
Raspberry Piに接続したフルカラーLEDをNode.jsから制御する
Raspberry PiのGPIOの制御方法がわかったので、Node.jsからGPIOをコントロールできるようにします。
Node.jsからGPIOを叩く
前回のGPIO制御のコマンドをそのまま使うような書き方をします。
var exec = require('child_process').exec; exec('gpio -g mode 23 out');
こんな感じで設定をして
exec('gpio -g write 23 1');
とすれば、23がHiになります。
Node.jsからフルカラーLEDを制御する
これだけでは面白く無いので、ブレッドボードにフルカラーLEDを接続してPWM使って色を変えるようにしてみます。PWMはアナログ出力で、Raspberry Piは18番のみがPWMが使えるようになっているので、RGBのBを18に接続して、RとGを普通のGPIOに接続しました。
GPIO Peripheral Full Color LED R - GPIO4 : 23 G - GPIO3 : 24 B - GPIO1 : 18 : PWM
ブラウザクライアントはexpress + Node.js + Socket.IOで作成しました。(以前のエントリを参照)LEDコントロールUIにはjQuery Knobを使っています。ブラウザでノブの値を変化させたら、その値を元にLEDの色を変化させるようになっています。
以下サーバ側(app.js)コード抜粋
// メッセージを受けた時の処理 socket.on('message', function(data) { // 接続しているクライアントに全てに送信 socket.broadcast.emit('message', { value: data.value }); // B exec('gpio -g pwm 18 ' + data.value % 1024); // R if ((1024 <= data.value && data.value < 2047) || (3072 <= data.value && data.value < 4095) ) { exec('gpio -g write 23 1'); } else { exec('gpio -g write 23 0'); } // G if ((2048 <= data.value && data.value < 3071) || (3072 <= data.value && data.value < 4095) ) { exec('gpio -g write 24 1'); } else { exec('gpio -g write 24 0'); } });
回路例は以下(LEDはカソードコモン:GND共通を使用)
これでノブをぐりんぐりんすれば、フルカラーLEDの色が変化します(^^)/
しかし・・・予想してたとはいえ追従性能がかなり悪い...orz
まとめ
リアルタイムWebとリアルデバイスを接続してみるという実験でしたが、Socket.IOのログレベルを下げてるのですが、実際の動作としては変化の追従がかなり遅いです。クリックだとパッパッと変化するのですが、アナログ的に変化させるとキツイです。今回の変化量は 0 〜 4096の間で変化量を都度送信しているのですが、Node.jsの処理が追いついていないのか、GPIOを叩くコードの部分がネックなのか切り分けできていません。いずれにしてもこの程度の処理でログが目で追えるような速度ではハードリアルタイムは無理です。やはりリアルタイムWebといえども、ハードリアルタイムを期待するのはかなり厳しいようです...(^^; 改善方法をご存知の方はぜひ教えて下さい
WebSocket系を使ったリアルタイムWebと、リアルデバイスとの接続させた場合のネックは見えました。ネックを解消し、あくまでハードリアルタイムを求める、あるいはWebSocketの性能レベルとハードリアルタイムを別々に考えシステムを設計する。という2通りの方法があります。普通に考えれば後者で、よくある電源のON/OFFくらいのレベルであれば十分対応可能ですが、もっと違うことを考えて行かないと面白くないですよね...
今回のコードはgithubに置いてあります。
Raspberry PiでGPIO制御
Raspberry PiのGPIOをライブラリを使って制御します。またライブラリを使うことでJavaScriptからでもGPIOの制御ができるようになります。まずはGPIOを叩いてみるところと、ハマるポイントを書いておきます。
Raspberry PiのGPIOの情報
ここがまとまってるような。 今回はsu無しで制御したいのと、JavaScript経由でアクセスしたかったので、Cなどのライブラリ経由ではなく、WirinigPiというコマンドレベルのライブラリを使います。これをインストールするだけでもコンソールからGPIO制御可能なので、簡単な動作確認にも便利です。
Wiring Piのインストール
この通りにやれば問題ありません。
$ git clone git://git.drogon.net/wiringPi
で、
$ cd wiringPi $ ./build
とすればインストール完了です。
$ man gpio
で使い方の説明が参照できます。
GPIOの取得
まずはGPIOの状態を取得してみましょう。
$ gpio readall +----------+------+--------+-------+ | wiringPi | GPIO | Name | Value | +----------+------+--------+-------+ | 0 | 17 | GPIO 0 | Low | | 1 | 18 | GPIO 1 | Low | | 2 | 27 | GPIO 2 | Low | | 3 | 22 | GPIO 3 | Low | | 4 | 23 | GPIO 4 | Low | | 5 | 24 | GPIO 5 | Low | | 6 | 25 | GPIO 6 | Low | | 7 | 4 | GPIO 7 | Low | | 8 | 2 | SDA | High | | 9 | 3 | SCL | High | | 10 | 8 | CE0 | Low | | 11 | 7 | CE1 | Low | | 12 | 10 | MOSI | Low | | 13 | 9 | MISO | Low | | 14 | 11 | SCLK | Low | | 15 | 14 | TxD | High | | 16 | 15 | RxD | High | +----------+------+--------+-------+ | 17 | 28 | GPIO 8 | Low | | 18 | 29 | GPIO 9 | Low | | 19 | 30 | GPIO10 | Low | | 20 | 31 | GPIO11 | Low | +----------+------+--------+-------+
こんな感じで各GPIOの状態が取得出来ます。 ここで、"GPIO"と"Name"の関係がわかりにくく、ハマるポイントでした。
先の参考ページの配置図ですが、これとの対比が取れてない・・・と思ったら、Raspberry Piのピン名とCPUのBroadcomのピン名があってこれが混乱する元になっている模様です。 出展 #ちなみに右図の12pin GPIO1はGPIO18の間違い
というわけで"Name"は左図との対比(GPIO8-11は無し)となってます。GPIOの制御は"GPIO"番号で行うため基本的には右図でいいのですが、混乱する元になりますね。
GPIOを制御
では、実際にGPIOに出力してみます。
| 6 | 25 | GPIO 6 | Low |
この、GPIO6 : 25にLEDを接続して1を書き込みます。
$ gpio -g mode 25 out $ gpio -g write 25 1
これでLEDが点灯します。ここで再度
$ gpio readall +----------+------+--------+-------+ | wiringPi | GPIO | Name | Value | +----------+------+--------+-------+ | 0 | 17 | GPIO 0 | Low | | 1 | 18 | GPIO 1 | Low | | 2 | 27 | GPIO 2 | Low | | 3 | 22 | GPIO 3 | Low | | 4 | 23 | GPIO 4 | Low | | 5 | 24 | GPIO 5 | Low | | 6 | 25 | GPIO 6 | High | | 7 | 4 | GPIO 7 | Low | | 8 | 2 | SDA | High | | 9 | 3 | SCL | High | | 10 | 8 | CE0 | Low | | 11 | 7 | CE1 | Low | | 12 | 10 | MOSI | Low | | 13 | 9 | MISO | Low | | 14 | 11 | SCLK | Low | | 15 | 14 | TxD | High | | 16 | 15 | RxD | High | +----------+------+--------+-------+ | 17 | 28 | GPIO 8 | Low | | 18 | 29 | GPIO 9 | Low | | 19 | 30 | GPIO10 | Low | | 20 | 31 | GPIO11 | Low | +----------+------+--------+-------+
GPIO6:25が"High"になっています。消灯させる場合は
$ gpio -g write 25 0
ブレッドボードで確認しましたがこんな感じに点灯します。
回路はざっくりこんなんで
追記:50Ωでは小さいんじゃない?と言う指摘を頂きました。確かに100Ωくらいの方が安全だと思います(^^;
Raspberry Pi + Socket.IOでチャットアプリ
このエントリは前回の続きです。
Socket.IOを使ったチャットアプリの作成
Socket.IOをインストールとして簡易チャットアプリを作成します。といっても、このサイトのサンプルを移植しただけです、はい…
Socket.IOのインストール
まずは作業フォルダを用意します。前回同様、express + EJSでひな形を作成します。
$ express -e socketio create : socketio create : socketio/package.json create : socketio/app.js create : socketio/public create : socketio/public/javascripts create : socketio/public/images create : socketio/public/stylesheets create : socketio/public/stylesheets/style.css create : socketio/routes create : socketio/routes/index.js create : socketio/routes/user.js create : socketio/views create : socketio/views/index.ejs install dependencies: $ cd socketio && npm install run the app: $ node app $ cd socketio && npm install
Socket.IOをインストールします。
$ npm install socket.io
現時点ではSocket.IO ver0.9.13がインストールされました。
アプリの作成
アプリの作成のため、下記のファイルを作成・修正します。
- app.js
- views/index.ejs
- public/javascripts/jquery-1.8.3.min.js (追加)
- public/javascripts/chat.js (追加)
- routes/index.js
サーバサイド(app.js)
/** * Module dependencies. */ var express = require('express') , routes = require('./routes') , http = require('http') , path = require('path'); var app = express() , http = require('http') , server = http.createServer(app) , io = require('socket.io').listen(server); app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'ejs'); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(path.join(__dirname, 'public'))); }); app.configure('development', function(){ app.use(express.errorHandler()); }); app.get('/', routes.index); // ソケットを作る var socketIO = require('socket.io'); // クライアントの接続を待つ server.listen(3000); // クライアントが接続してきたときの処理 io.sockets.on('connection', function(socket) { console.log("connection"); // メッセージを受けた時の処理 socket.on('message', function(data) { // 接続していクライアントに全てに送信 console.log("message"); socket.broadcast.emit('message', { value: data.value }); }); // クライアントが切断した時に処理 socket.on('disconnection', function() { console.log("disconnection"); }); });
クライアントサイド(index.ejs)
クライアントサイドでは、jQueryを使うのでダウンロードしてローカルに配置します。public/javascriptsディレクトリで
$ wget http://code.jquery.com/jquery-1.8.3.min.js
そしてメインのchat.jsをpublic/javascriptsディレクトリに作成します。
var socket = io.connect(); // WebSocketでの接続 socket.on('connect', function(msg) { console.log("connet"); $('#connectId').html('あなたの接続ID::' + socket.socket.transport.sessid); $('#type').html('接続方式::' + socket.socket.transport.name); }); // メッセージを受信 socket.on('message', function(msg) { // メッセージを画面に表示する $('#receiveMsg').prepend(msg.value + '<br>'); }); // メッセージを送信する function SendMsg() { var msg = $('#message').val(); // メッセージを送信 socket.emit('message', { value: msg }); $('#message').val(''); } // 切断する function DisConnect() { var msg = socket.socket.transport.sessid + "は切断しました"; // メッセージを送信する socket.emit('message', { value: msg }); // socketを切断する socket.disconnect(); }
views/index.ejsを修正してjQueryやchat.jsを読み込むように設定し、簡単なUIを作成します。
<!DOCTYPE html> <html> <head> <title><%= title %></title> <script src="/javascripts/jquery-1.8.3.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script src="/javascripts/chat.js"></script> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1>socket.ioのサンプル</h1> <div id="connectId"></div> <div id="type"></div> <br> <input type="text" id="message" value=""> <input type="button" value="メッセージを送る" onclick="SendMsg()"> <input type="button" value="切断する" onclick="DisConnect()"> <div id="receiveMsg"></div> </body> </html>
最後にタイトルを修正しておきます。routes/index.jsを修正します。
/* * GET home page. */ exports.index = function(req, res){ res.render('index', { title: 'Socket.IOサンプル' }); };
これでnodeを実行してブラウザを複数起動してチャットできればOKです。
$ node app.js
普通のPCと同じ手順でできちゃいますね...
次はGPIOとかをコントロールしてWebと繋ぎたいですね。