概要
前回記事の続きになります。これは、8/29から9/2にかけて行われたインターンにおいて製作したプロダクトの抜粋となります。開発に使用したリポジトリはコチラ(github)。今回はその中でも、raspberryディレクトリ内の、pi_1.jsとpi_2.jsの話になります。nodeで起動するタイプです。node_modulesの中身はbody_parser、express、requestの3つ。pi_1.jsは、データを受け取ったらそれをIFTTTに転送するコード。pi_2は、データを受け取ったらpi_1.jsが動いているノードにそれを転送するコードです。
以下は、今回参考にさせて頂いた記事です。
IFTTTのMaker Channelとシンプルに接続するHeroku NodeJSのメモ
今回は、IFTTTのMaker Channelに投げます。Maker Channelの設定方法については、参考記事様に記載されているので割愛。
概要図
インターンの最終発表のデモに使った図をそのまま流用しています。これを使ったスライドはコチラ。POST元の機器及び中継器となるRaspberry Piを任意の数だけ、同一のad-hocネットワークに接続し、続いて、前回記事にて示した手順でメッシュネットワークを構築します。そのうち、pi_1.jsを起動する予定のRaspberry Piとルータを有線で接続します(以下、ethPi)。Raspberry Pi 3にて使用されている、無線用のインタフェースwlan0は、ad-hocネットワークへの接続に使用しているため、ルータとは有線で接続する必要があります。有線のインタフェースはeth0です。POST元の機器が、いずれかのRaspberry PiにデータをPOSTすると、受け取ったRaspberry Piは、ethPiまでデータを転送させます。これは、図では緑の矢印で示されています。中継を経てデータを得た、ethPiは、届けられたデータをIFTTTに投げます。これは、オレンジの矢印で示されています。
コード
var express = require('express'); var _request = require('request'); var app = express(); var bodyParser = require('body-parser'); var key = require("./config.json"); app.set('port', (process.env.PORT || 5000)); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); // 8番のGPIOピンを出力として登録 var fs = require('fs') fs.writeFileSync('/sys/class/gpio/unexport', '8'); fs.writeFileSync('/sys/class/gpio/export', '8'); fs.writeFileSync('/sys/class/gpio/gpio8/direction', 'out'); function blink(){ console.log("blink!"); fs.writeFileSync('/sys/class/gpio/gpio8/value', '0'); fs.writeFileSync('/sys/class/gpio/gpio8/value', '1'); setTimeout(function(){ fs.writeFileSync('/sys/class/gpio/gpio8/value', '0'); },5000); } // IFTTTへ送信 app.post('/', function(request, response) { blink(); console.log(request.body); if(request.body.Kim == "true"){ console.log("send to Kim"); sendMessage(request.body.message,"Kim"); } if(request.body.Ohashi == "true"){ console.log("send to Ohashi"); sendMessage(request.body.message,"Ohashi"); } if(request.body.Kobayashi == "true"){ console.log("send to Kobayashi"); sendMessage(request.body.message,"Kobayashi"); } }); function sendMessage(message,target){ targetURI = 'http://maker.ifttt.com/trigger/IoT_Intern_' + target + '/with/key/' + key.iftttKey; console.log(targetURI) console.log(target); console.log(message); var options = { uri: targetURI, form: { value1:message }, json: true }; console.log('---------- [output]'); console.log(options.uri); _request.post(options, function(error, response, body){ if (!error && response.statusCode == 200) { console.log(body); } else { console.log('error: '+ response.statusCode); } }); }; app.listen(app.get('port'), function() { console.log('Node app is running on port', app.get('port')); });
//2は1へ var targetURL = 'http://192.168.12.1:5000'; // 8番のGPIOピンを出力として登録 var fs = require('fs'); fs.writeFileSync('/sys/class/gpio/unexport', '8'); fs.writeFileSync('/sys/class/gpio/export', '8'); fs.writeFileSync('/sys/class/gpio/gpio8/direction', 'out'); function blink(){ console.log("blink!"); fs.writeFileSync('/sys/class/gpio/gpio8/value', '0'); fs.writeFileSync('/sys/class/gpio/gpio8/value', '1'); setTimeout(function(){ fs.writeFileSync('/sys/class/gpio/gpio8/value', '0'); },5000); } var express = require('express'); var bodyParser = require('body-parser'); var app = express(); var http = require('http'); var port = 5000; var server = http.createServer(app); var request = require('request'); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); function relaySend(data){ console.log("relaySend!"); console.log("data",data); request.post({url:targetURL, form: data}, function(err,httpResponse,body){ console.log(err); }); } app.post('/', function(req, res) { console.log("post"); if(req.body){ blink(); relaySend(req.body); } }); server.listen(port,function(){ console.log("server listening on port : ", port) });
デモ用にGPIO8 Pinに出力をしていますが、無くても大丈夫です。pi_2.jsは、データをjson形式で受け取ると、それをそのまま別のRaspberry PiにPOSTするように動作します。このコードでは、ethPiのad-hocネットワーク内でのプライベートIPアドレスである192.168.12.1を指定しています。ポートは5000番を使います。今回のインターンでは、Makerのイベントを3つ作成し、jsonに入っていたデータの内容によって、叩くイベントを変えています。したがって、pi_1.jsでは、
// IFTTTへ送信 app.post('/', function(request, response) { blink(); console.log(request.body); if(request.body.Kim == "true"){ console.log("send to Kim"); sendMessage(request.body.message,"Kim"); } if(request.body.Ohashi == "true"){ console.log("send to Ohashi"); sendMessage(request.body.message,"Ohashi"); } if(request.body.Kobayashi == "true"){ console.log("send to Kobayashi"); sendMessage(request.body.message,"Kobayashi"); } });
のような処理形態となっていますが、たたくイベントが一つなら、if文は必要ありませんし、sendMessage()は一回呼び出せば大丈夫です。
起動
では、立ち上げてみましょう。まず、ルータと直接有線でつながっているethPiで
[plain]
$ sudo node pi_1.js
[/plain]
そのほかの中継器となるRaspberry Piで
[plain]
$ sudo node pi_2.js
[/plain]
を実行して受信待機状態にします。テストをしたいときは、pi_2.jsを起動しているRaspberry Piに適当にcurlを投げましょう。そいつのIPアドレスを仮に192.168.12.2とします。
[plain]
$ curl -d message=test -d Ohashi=true 192.168.12.2:5000
[/plain]
みたいな感じで投げましょう。そうすると、ethPi(192.168.12.1)側のターミナルでは、
[plain]
blink!
{ message: ‘test’ }
blink!
{ message: ‘test’, Ohashi: ‘true’ }
send to Ohashi
http://maker.ifttt.com/trigger/IoT_Intern_Ohashi/with/key/xxxxxxxxxx
Ohashi
test
———- [output]
http://maker.ifttt.com/trigger/IoT_Intern_Ohashi/with/key/xxxxxxxxxx
Congratulations! You’ve fired the IoT_Intern_Ohashi event
[/plain]
console.logしすぎてよくわからないですね…。記事書く前に整理しておけばよかったですが、まあつまりは、他のRaspberry Piから中継されたデータをhttp://maker.ifttt.com/trigger/IoT_Intern_Ohashi/with/key/xxxxxxxxxxにPOSTしたらCongratulations! You’ve fired the IoT_Intern_Ohashi eventと帰ってきますということです。xxxxxxxxxの部分はIFTTTで配布される個人のキーですね。
結果
Raspberry PiがPOSTを中継、Makerを無事叩くことができました。IoT_Intern_Ohashiイベントでは、私のgmailにメールが来ることになっているので見てみましょう。
来てますね。タイトルは救援要請で固定してあるのでその通りに、curlコマンドでmessageにtestを渡したので本文はtestになってます。
効果
pi_1.jsを改造すれば、別にIFTTTに投げるとかじゃなくても、いろいろできると思います。IFTTTのthen部分の設定を変えて、twitterで呟かせたりEvernoteに投げたりとかも簡単に出来ますね。WebページをPOST元のブラウザとかに引っ張ってこられるといいんですが、出来るかどうかは僕の現時点での知識ではなんとも…。まあ、いろいろ出来そうなので、今後もちょいちょいいじってみたいですね。
追記
ご指摘があったので追記いたします。今回お見せしたのはインターンでの最終発表デモ用に組まれたコードであり、すべてのRaspiが同一のネットワークに属していることの証明として隣のRaspiにバケツリレーするコードとなっております。これはメッシュネットワークの例としてはやや不適切です。ごめんなさい。実際には、間接的につながっているノードのIPアドレスを指定できるので、WANにつながっているRaspiのIPを指定してデータを転送するプログラムと、WANにデータを転送するプログラムの二つがあれば正常に機能します。明記することは大切ですね。以後気を付けます。