netatmo ウェザーステーションを買ってAPIを叩いてみる

netatmo ウェザーステーションとは

netatmoウェザーステーション

公式HP ※公式のJPは死んでるっぽいので、USサイト

その名の通り気象情報をセンサーで取得するデバイスです。基本構成は2つのセンサーデバイスで、大きいほうが室内用、小さいほうが屋外用となっています。電源は室内用はUSBから、屋外用は単4電池2本で駆動します。それぞれのセンサーから取得できるデータは以下になります。屋外用のセンサーというのは実はありそうで無いので、ベランダなどに設置しておくと今の屋外気温が取得できるので面白いです。

  • 室内用

    • 気温
    • 湿度
    • 気圧
    • CO2
    • 騒音
  • 屋外用

    • 気温
    • 湿度

これを設置してユーザ登録してログインすると、PCではこんな画面でデータを見ることができます。

※地図の部分はボカしています

f:id:tomo_watanabe:20140501213157p:plain

ちなみに、全世界の今の気温もGoogleMap上でみることができます。クリック

また、iPhoneアプリAndroidアプリもあります。Androidではウィジェットに設定できるのでこれは便利!です。

f:id:tomo_watanabe:20140501214917p:plain

IFTTTと連携

このデータを元にIFTTTを使って連携しようと考えました。例えばこんな感じのレシピを作れます。

f:id:tomo_watanabe:20140501213757p:plain

これは「湿度が10%を切ったら、Tweetする」ということになります。とはいえ、本当にやりたかったのは「毎朝8時に、今の屋外の気温をTweetする」のようなことがしたかったのでこれはイマイチです。IFTTTではnetatmoウェザーステーションはトリガーにしか使えない、かつこの場合、3つの事象が含まれるのでIFTTTでは実現できません。

netatmoのAPIを利用

というわけで、netatmo APIを利用して作ることにしました。ここにアクセスして、「MY APPLICATIONS」を登録することでAPIを叩くことができるようになります。

APIの取得の仕方等はNetatmo ウェザーステーションを買ってみたので Node.js でいじってみたを参照して下さい。

今回はVPSを使わず、手元にあったRaspberry Piを使用して、下記のような構成を作ってみました。

結果

これはこれで簡単にできるので、もう少し色々連携させたくなってきました\(^o^)/ Raspberry Pi上でMQTTのブローカーを導入して、周辺デバイスと連携とか

インターネットとハードウェア

組込みプログラミングの必要性

プログラミングというとPC上でのプログラムが普通ですが、最近感じているのは組込み系のプログラミングの重要性です。単に組込みプログラミングというだけではなく、デバイスとネットワークを扱うためのプログラミングと言ったほうがいいかもしれません。

理由は下記の通り

  • 身近なものがインターネットに繋がる、モノのインターネットではデバイスを扱うことが必須
  • 子供の頃から見たり触れたりするのは実体のあるデバイスであり、プログラミングは実体のあるデバイスを動作させることで興味を持つことができる
  • 組込み系のデバイスのプログラムが書けるのは、おっさんばかり。若い人はこれが出来ると需要がありそう
  • ハンダ付けや簡単な電子回路の知識もついでに身につく

とはいえ、最近のデバイスはそこまでの知識が必要なくてもハードウェアを叩けるようになってきているので、まずはそこから始めるのがいいでしょう。

何から始めるか?

Arduino

Arduino Uno

言わずと知れたプロトタイピング用デバイス。IDEもありC言語ライクに書ける。情報も圧倒的に多くとりあえず始めるならコレ。ただしネットワーク周りはやや貧弱で、イーサネット対応しようとするとコストが高く、別の選択もあり


Raspberry Pi

Raspberry Pi

最近流行りの小型PCボード。拡張性は低いけれどもGPIO周りは多くの情報があり、Linux扱える人ならなら敷居が低い。ネットワークも普通に使える(実際には組み込みボードとは言い難い)


Espruino

Espruino

JavaScriptで書けるデバイス。Web系の人が入るには良さそう。KICKSTARTERで募集中(2013/9/1現在調達達成)。ポチった


TESSEL

TESSEL

こちらもJavaScriptで書ける。WiFIを搭載し、Node.jsも動く。こちらも購入予定


「モノのインターネット」を考えると、今流行のArduinoでは限界が見えている気がします。もう少しリッチなデバイスで、かつArduinoの手軽さでネットワークが扱える。というのが求められているのでしょう。後者の2つはそこを狙っているように思います。ルネサスからSAKURAボードというArduino互換に近いボードが出ているのですが、僕が使った感じではTCPライブラリに問題があるようで(TCPをクローズしてくれない)、ネットワークを扱うのは避けたほうがよさそうです。

ARMマイコンを使えるように

もっと簡単にレゴロボットでプログラムを学習しよう。とかいうのも導入的にはありだと思いますが、やはりゴールはCPUアーキテクチャやメモリマップ、レジスタ制御などをきちんと理解してプログラムが書けるようになっておきたいものです。というわけで、個人的に最近使っているArduinoに限界を感じたためARMマイコンの勉強を始めました。ゴールはCortex-Mシリーズを使えるようになること。昔はSHマイコンでμITRONとかやっていたのですが、すっかり錆びついているため思い出しながら始めます。

おまけ

ThinkITさんで、「Raspberry PiとNode.jsで作る独立稼働モバイルサーバ」という記事を書きました。Raspberry Piを使ってNode.js + ハードウェアでサーバ型カーナビを作る。というものです。

モバイルサーバ

AndroidiPhoneがもたらしたのはスマートフォンだけではなく、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秒待たされることになります。

f:id:tomo_watanabe:20130323204520j:plain

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

これでもう一度起動してみます。

f:id:tomo_watanabe:20130323222525j:plain

先ほどのMacと同じように動きました。

今回のコードはGithubに置いてあります。コードはMacで動作するコードなので注意して下さい。 ※2013/3/30 データ取りこぼしの件bugfixしました

Raspberry Piにリバースプロキシを導入する

Raspberry PiにNode.jsを入れて動かしていましたが、Raspberry Piにリバースプロキシを導入して、サブドメイン名でApacheとNode.jsの切り替えをしてみます。リバースプロキシにはWebSocketを透過するnode-http-proxyを導入します。できるだけ手順をそのまま書いたつもりですが、何か不必要な部分があったり、間違ってる箇所があるかもしれません。ネットワーク周りは勉強中なので備忘録代わりに書き残しています。(そもそもリバースプロキシ自体初めて知った...)

f:id:tomo_watanabe:20130127203110p:plain

Apachをインストールして、デフォルト80でリッスンするのを8080でリッスンするように変更します。リバースプロキシは80をリッスンして、サブドメイン名によってApacheの8080とNode.jsが動いている3000へ振り分けるようにします。

Apacheのインストール

$ sudo apt-get install apache2

きちんと動作しているか、Rasberry Piにアクセスして確認します(ここでは192.168.0.7になっています)

f:id:tomo_watanabe:20130127200517p:plain

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>

f:id:tomo_watanabe:20130127200601p:plain

これで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)へアクセス

f:id:tomo_watanabe:20130127200822p:plain

では以前に動かしたNode.jsのプログラムをポート3000で動作させて、最終的にリバースプロキシとしての動作を確認します。

Node.js(3000)へアクセス

f:id:tomo_watanabe:20130127200829p:plain

まとめ

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の色を変化させるようになっています。

f:id:tomo_watanabe:20130121213903p:plain

以下サーバ側(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共通を使用)

f:id:tomo_watanabe:20130121215824p:plain

これでノブをぐりんぐりんすれば、フルカラーLEDの色が変化します(^^)/

しかし・・・予想してたとはいえ追従性能がかなり悪い...orz

f:id:tomo_watanabe:20130120233345j:plain

まとめ

リアルタイム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"の関係がわかりにくく、ハマるポイントでした。

GPIO概要

先の参考ページの配置図ですが、これとの対比が取れてない・・・と思ったら、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

ブレッドボードで確認しましたがこんな感じに点灯します。

f:id:tomo_watanabe:20130114173732j:plain

回路はざっくりこんなんで

f:id:tomo_watanabe:20130114175533p:plain

追記: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

f:id:tomo_watanabe:20130103160439p:plain

普通のPCと同じ手順でできちゃいますね...

次はGPIOとかをコントロールしてWebと繋ぎたいですね。