ラズパイ+ 3GPIシールドで遠隔地からECHONET Liteエアコンを操作する

本記事は、ラズパイ＋3GPIを用いてECHONET Liteの家電を宅外から動かす方法を解説します。
実はここまで至る過程が長くて、以下の２つの記事の続きになっております。ご容赦を。

「[RaspberryPi 1 Model B で3GPIを使うにはニッパーが必要だって話](http://qiita.com/sgrowd/items/7050ce8ea5baf850ab36)」
「[ラズパイからnode.jsを使ってECHONET Liteエアコンの操作をする](http://qiita.com/sgrowd/items/b0e20e8cc0fb57d6f79c)」

上記２つの内容によって、ラズパイに3GPIがつき、Ethernetと3Gの優先順位を変更でき、宅内のECHONET Liteエアコンが操作できたことになります。
それらの内容は前提として、今回はこれに、インターネット上のサーバーを介することで宅外からECHONET Lite対応家電を操作できる機能を実現してみたいと思います。

# 今回使用するもの

・RaspberryPi 1 Model B Rev.2
・3GPI  (http://www.mechatrax.com/products/3gpi)
・SORACOM Air SIM
・node.js
・ECHONET Liteのnpmパッケージ　(https://www.npmjs.com/package/echonet-lite)
・ECHONET Liteエアコンまたは[エアコンのエミュレータ](http://kadecot.net/blog/1479/)

に加え、新たに

・さくらのVPS （CentOS 6.6）
・Webブラウザ

を用います。ラズパイ周りの見た目はこんな感じになります。

![6.jpg](https://qiita-image-store.s3.amazonaws.com/0/125904/575fd5a8-04bd-2fbb-e651-1c4bfc865fcc.jpeg)

# 計画
遠隔操作を実現するにはいくつかの可能性が考えられますが、今回はそのうち最もナイーブな方法を用います。

　　![Plan.png](https://qiita-image-store.s3.amazonaws.com/0/125904/03a8c6b1-eef1-b090-f76b-5eda7c2cbba9.png)

この図のようにグローバルIPを持ったところに仲介サーバーを立て、宅内のラズパイと宅外のブラウザの両方からそこにアクセスして、室内外のメッセージ交換をしてもらいます。仲介サーバーは、単に二つの接続をつないで、片方から来た情報をもう片方に流すだけの役割を持っています。この働きはまさにチャットサーバーです。そして、[socket.io](http://socket.io/)を使ってチャットを実現するサンプルはネットにたくさんあるので、それに沿った実装にしようと思います。
自分で作ったほうが早いと思ってしまったためそこも作りましたが、自分のお好きなチャットサーバーを用いてもいいんです。[懐かしの（？）IRC](https://ja.wikipedia.org/wiki/Internet_Relay_Chat)なんか枯れてて使いやすいかもしれません。

# グローバルIP上に仲介サーバーを作る

私はさくらのVPSサーバーを使っているので、その上に構築することにしました。OSはCentOS 6.6です。npmはすでに入っていました。

適当なフォルダで、socket.ioを導入します。コードを短くしたいので、expressも入れておきます。

`npm install socket.io`
`npm install express`

そして、同じフォルダでserver.jsとindex.htmlの２つのファイルを作り、それぞれの内容をこのようにしてください。


```lang:server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

// httpアクセスの返答を作っているところ
app.get("/*",function(req,res,next){
        res.sendFile(__dirname+'/'+req.params[0]);
}) ;

var socks = [] ;

// WebSocketアクセスの返答を作っているところ
io.on('connection', function(sock){
        socks.push(sock) ;

        sock.on('msg', function(text){
                socks.forEach(function(s){
                        if( s != sock ){
                                s.emit('msg',text) ;
                        }
                }) ;
        });

        sock.on('disconnect',function(sd){
                socks = socks.filter(function(s){return s != sock;}) ;
        }) ;
});

http.listen(3000);
```

```lang:index.html
<!DOCTYPE html>
<html>
<body>
<input type='text'  onkeydown='if(window.event.keyCode==13) socket.emit("msg",this.value);' ></input>
<script src='/node_modules/socket.io/node_modules/socket.io-client/socket.io.js'></script>
<script>
var socket = io() ;

onload = function(){
        socket.on('msg',function(re){
                var li_elem = document.createElement('div') ;
                li_elem.innerHTML = JSON.stringify(re)+'<br />' ;
                document.body.appendChild(li_elem);
        }) ;
} ;
</script>
</body>
</html>
```


このserver.jsはいわばチャットサーバであり、index.htmlはチャットクライアントです。ブラウザからのリクエストに応じてserver.jsがindex.htmlを読み込んでブラウザに内容を送るという関係です。

`node server.js`

のようにしてサーバーを立ち上げると、3000番ポートでブラウザからクライアントにアクセスできるようになります。このサーバーが立っているマシンのグローバルIPを、例えば12.34.56.77とすると、

`http://12.34.56.77:3000/index.html`

をブラウザで開けばOKです(URL末尾の`index.html`は省略できません)。仲介サーバーにはいくつでもクライアントが接続し、どれかがメッセージを送ると、それを送信元以外のすべてのクライアントに転送するようになっています。セキュリティ的には誰でもつなげてしまうので大きな問題ですが、プロトタイプということで許してください。

複数のブラウザで開くと、相互にメッセージをやり取りできますので試してみてください。テキストボックスに文字を入れ、Enterキーを押すと送信となります。

![cap2.png](https://qiita-image-store.s3.amazonaws.com/0/125904/697ca937-bd4e-ac3d-87c6-e6b3fb2f02f6.png)

手前のウィンドウから奥のウィンドウにHelloという文字列を送信しています。まさにチャットですね。

# ラズパイから仲介サーバーへの接続

今回はラズパイからもこの仲介サーバーにアクセスし、流れてくる文字列をコマンドと解釈して実行することにします。

そのために、今度はラズパイの方でもsocket.ioのクライアント側を使えるようにしましょう。こちらはsocket.ioのサーバーを作りたいわけではなくあくまでクライアントなので、socket.ioではなく、socket.io-clientをインストールします。

`npm install socket.io-client`

前回の記事「ラズパイからnode.jsを使ってECHONET Liteエアコンの操作をする」で作成したrun0.jsというECHONET Lite用サーバに、グローバルIPの仲介サーバーへの接続機能と受け取った文字列を実行するロジックを足します。

```lang:run.js
var socket = require('socket.io-client')('http://12.34.56.77:3000');

// 接続完了
socket.on('connect',function(){ console.log('connected'); }) ;

// メッセージ受信
socket.on('msg',function(msg){
        console.log(msg) ;
        try{
　　　　　　　　　// 仲介サーバーからメッセージを受け取ったら"EL."という文字列を最初に追加してからevalする。
                eval('EL.'+msg) ;
        } catch(e){
                socket.emit('msg','Error:'+JSON.stringify(e));
        }
}) ;

// 初期設定
var EL=require('echonet-lite');
var objList=['05ff01'];
var elsocket=EL.initialize(objList,function(rinfo,els){
        // ECHONET Liteのメッセージを受け取ったら、仲介サーバーに向けてメッセージ送信
        socket.emit('msg',{rinfo:rinfo,els:els}) ;
});
```

最初の行のIPアドレス`12.34.56.77`は、先ほどのserver.jsが走っているグローバルIPアドレスに適宜変更してください。

このrun.jsをnode.jsで走らせれば、遠隔操作の準備完了です！

`node run.js`

しばらくしてコマンドラインに`connected`という文字列が出れば、仲介サーバーへの接続が成功しています。もししばらく待っても出ないようなら、デフォルトのネットワークが3Gになっているかどうか確認してください。確認の仕方は、`netstat -r`と打ってみて、Destinationがdefaultになっている行を探し、その行の右端IFaceがppp0以外になっているかどうかを見ます。ppp0ではない場合は以下の二行を実行してください。

`sudo route del default dev eth0`
`sudo route add default dev ppp0`

ここら辺の設定について詳しく書いてくださっている方がいるので、ご興味のある方は是非ご覧ください。
http://qiita.com/dietposter/items/ac9108b8eaebb90e8050

# ブラウザからの遠隔操作

さて、`connected`と表示されたら、あとはエアコンを動かすコマンド、前回ローカルで打ちこんだ魔法の関数呼び出しを、宅外のブラウザ側から行えばよいのです。このパラメータの意味については、前回の記事「ラズパイからnode.jsを使ってECHONET Liteエアコンの操作をする」をご参照ください。

`sendOPC1('192.168.0.148',[0x05,0xff,0x01],[0x01,0x30,0x01],EL.SETI,0x80,[0x30]);`

とテキストボックスに入力の上Enterキーを押します。

![cap3.png](https://qiita-image-store.s3.amazonaws.com/0/125904/e4ff5f4a-245d-79cc-96dc-6519368a0ee5.png)

（sendOPC1はELオブジェクトのメソッドですが、ラズパイ上でevalが実行される時に"EL."という文字列が最初に補われるので、チャットクライアントでは打ちこむ必要はありません）

結果はこのようになりました。（クリックするとYouTube動画が開きます）
[![ビデオが開けません](http://img.youtube.com/vi/YhggViVnKLg/0.jpg)](http://www.youtube.com/watch?v=YhggViVnKLg)
※ちなみに、ECHONET Lite経由で操作すると、赤外線リモコンで操作したときと異なり「ピッ」という操作音がしないことが多いです。
寝ているときに自動操作で起こさないための気づかいかもしれません。

ブラウザとしては、私が愛してやまないシャープのガラホ「Aquos K」の標準ブラウザを用いています。3Gでインターネット接続していますので、エアコンの目の前にありますが実際にはインターネット経由で遠隔操作しています。

エミュレータだとこのようになります。最初は電源が入っていないエアコンが…

![cap2.jpg](https://qiita-image-store.s3.amazonaws.com/0/125904/13c6dcc5-48c4-209b-c9d3-be92c315071c.jpeg)

青い風を出します（笑

![cap3.jpg](https://qiita-image-store.s3.amazonaws.com/0/125904/19c824ec-7883-90da-94ad-8db50bad49ae.jpeg)

エアコンの電源状態取得もできます。

`sendOPC1('192.168.0.148',[0x05,0xff,0x01],[0x01,0x30,0x01],EL.GET,0x80);`

とすると、しばらくして

> {"rinfo":{"address":"192.168.0.148","family":"IPv4","port":3610,"size":15},"els":{"EHD":"1081","TID":"0000","SEOJ":"013001","DEOJ":"05ff01","EDATA":"7201800130","ESV":"72","OPC":"01","DETAIL":"800130","DETAILs":{"80":"30"}}}

といった返答がブラウザに表示されます。注目すべきはDETAILsです。"80":"30"とありますが、これはプロパティID　0x80が、0x30という値だったという回答です。0x80は電源、0x30はONですから、エアコンの電源が入っていることがわかります。現在状態がこんなに簡単に取得できるなんて、赤外線リモコンにはできない芸当ですね。

ただし、[前回の記事](http://qiita.com/sgrowd/items/b0e20e8cc0fb57d6f79c)で機器一覧を得るために使ったsearch()はうまく働きません。どうやら、echonet-liteパッケージが、デフォルトのネットワークインターフェース（この場合は3G）にしか問い合わせを投げないようになっているようなのです。対処方法がわかったらここに追記します。

# まとめ

今回の遠隔操作実装では、グローバルIPのホスト上に仲介サーバーを立てるという方法でした。他にもWebRTCを使う方法とか、IFTTTを使う方法とか、もっと洗練されたセキュアな方法があると思います。本格実装をされたい方はそういった方法をご検討ください。

とはいえ、ECHONET Liteの家電遠隔操作を簡便に実装することはかなり容易にできることがお分かりいただけたかと思います。ぜひ試してみてください！