メッシュネットワーク側からWAN側の何かにPOSTする

投稿者: | 2016-09-08

概要

前回記事の続きになります。これは、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の設定方法については、参考記事様に記載されているので割愛。


概要図

スクリーンショット 2016-09-02 15.03.48インターンの最終発表のデモに使った図をそのまま流用しています。これを使ったスライドはコチラ。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にメールが来ることになっているので見てみましょう。
pi_1test来てますね。タイトルは救援要請で固定してあるのでその通りに、curlコマンドでmessageにtestを渡したので本文はtestになってます。


効果

pi_1.jsを改造すれば、別にIFTTTに投げるとかじゃなくても、いろいろできると思います。IFTTTのthen部分の設定を変えて、twitterで呟かせたりEvernoteに投げたりとかも簡単に出来ますね。WebページをPOST元のブラウザとかに引っ張ってこられるといいんですが、出来るかどうかは僕の現時点での知識ではなんとも…。まあ、いろいろ出来そうなので、今後もちょいちょいいじってみたいですね。

追記

ご指摘があったので追記いたします。今回お見せしたのはインターンでの最終発表デモ用に組まれたコードであり、すべてのRaspiが同一のネットワークに属していることの証明として隣のRaspiにバケツリレーするコードとなっております。これはメッシュネットワークの例としてはやや不適切です。ごめんなさい。実際には、間接的につながっているノードのIPアドレスを指定できるので、WANにつながっているRaspiのIPを指定してデータを転送するプログラムと、WANにデータを転送するプログラムの二つがあれば正常に機能します。明記することは大切ですね。以後気を付けます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です