はりうすブログ (のすけのメモ)

湘南にある小さな会社 代表 ”のすけ”のブログです

Nodeでサーバ作ってPOSTデータ受け取ってLEDを遠隔チカチカさせる(仮想編)

こんにちは、のすけです。

最近は毎週朝に、カフェでもくもく作業しています。

そんなもくもくの成果を一つ書いておきます。

NodeでLEDを遠隔チカチカさせる(仮想編)

やってみたいじゃないですか。遠隔チカチカ。

最近はクラウドのIoTサービスなんかもあって便利なんですが、その前に自分でサーバを作ってやってみないことには IoTサービスの便利さを体感できないと思います。

というわけで、最近はまっているNodeを利用してサクッとサーバを立てて、それからLEDチカチカへ移りたいと思います。 チカチカさせるマイコンとしては、Rasberry pi2を利用します。

POSTデータを受け取るサーバ作成

まず、POSTデータを受け取るサーバプログラムはこちら

var http = require('http');
var querystring = require('querystring');
var util = require('util');
var fs = require('fs');
var form = fs.readFileSync('./public/form.html');

http.createServer(function (req, res){
    if(req.method === 'GET'){
        res.writeHead(200,{'Content-Type': 'text/html'});
        res.end(form);
    }
    if(req.method='POST'){
        var postData = '';
        req.setEncoding('utf8');
        req.on('data',function (chunk){
            // per request
            postData += chunk;

        }).on('end',function(){
            // response data
            var respose_data = '';

            // end request
            if(!postData){
                res.end();
                return;
            } // if postData is empty.

            var postDataObject = querystring.parse(postData);
            console.log('user posted following data:' + postData);
            console.log(postDataObject.userinput1);
            respose_data += 'your poted data is:\n' + util.inspect(postDataObject)+'\n';

            res.end(respose_data,"utf8");
        });
    }
}).listen(8080);

基本的なサーバ機能を提供するhttp、クエリストリングをいい感じに読んでくれるquerystring、POSTデータを簡単に文字列に変えることができるutil、ファイルを読み込めるfsのライブラリを使っています。

form用のHTMLは別ファイル./public/form.htmlに置いておいて。それをfsで読み込みます。 f:id:hollywis:20160218085231p:plain

<form method="post">
    <input type="text" name="userinput1"><br><br>
    <input type="text" name="userinput2"><br><br>
    <input type="submit">
</form>

単純にHTMLでform作ってmethodをpostにします。 input要素を2つくらいとsubmitをつけただけ。

サーバの方に戻ります。 req.methodがGETの時はform.htmlを表示させ、POSTの時は処理を挟みます。

req.setEncoding('utf8'); を入れているのは近年のブラウザはutf8で処理しているのですが、これの設定入れないと違うエンコーディングで読んだりして文字化ける可能性があるそうです。

req.on('data',function (chunk){
            // per request
            postData += chunk;

        }

リクエストのデータは複数回に分かれて細切れに飛んできます。dataイベントが複数回発生しますので、これを結合して一つのデータにしています。

on('end',function()

データの受信が終わったらendイベントが発生するため、ここから主処理を開始できます。

querystring.parseでpostDataを扱いやすいようにオブジェクトに変換しています。

util.inspect(postDataObject)でオブジェクトを文字列に変換しています。

res.end(respose_data,"utf8");ではレスポンスに文字列response_dataを返却しています。ここでエンコーディングタイプutf8を指定しないと、日本語を返した場合にブラウザがどんなエンコーディングタイプで読めば良いかわからないため文字化けします。

LED点灯できるコマンド実行できるようにする

nodeではコンソールで実行するようなコマンドを発行することができます。

具体的にはrequire('child_process').execを利用します。

var exec = require('child_process').exec, cmd;

cmd_ledon = 'echo "LED ON!!"';
cmd_ledoff = 'echo "LED OFF!!"';

led_onoff = function(cmd) {
    return exec(cmd, {timeout: 1000},
        function(error, stdout, stderr) {
            console.log('stdout: '+(stdout||'none')); // 標準出力
            console.log('stderr: '+(stderr||'none')); // 標準エラー出力
            if(error !== null) {
                console.log('exec error: '+error);
            } // errorの時
            else{
                console.log('exec: '+cmd);
            } // errorなしの時
        }
    )
};
led_onoff(cmd_ledon);
led_onoff(cmd_ledoff);

最後の2行でLED点灯、LED消灯を実行しています。led_onoff関数を作成し、そこにコマンドを渡してあげると実行してくれます。

今回は(仮想編)ですので実際にLEDを点灯するコマンドではなくecho "LED ON!!"echo "LED OFF!!でLEDが点灯、消灯したということにします。

上記プログラムを合体して、POSTデータによってLEDの点灯、消灯を切り替える

var http = require('http');
var querystring = require('querystring');
var util = require('util');
var fs = require('fs');
var form = fs.readFileSync('./public/form.html');

var exec = require('child_process').exec, cmd;

cmd_ledon = 'echo "LED ON!!"';
cmd_ledoff = 'echo "LED OFF!!"';

led_onoff = function(cmd) {
    return exec(cmd, {timeout: 1000},
        function(error, stdout, stderr) {
            console.log('stdout: '+(stdout||'none')); // 標準出力
            console.log('stderr: '+(stderr||'none')); // 標準エラー出力
            if(error !== null) {
                console.log('exec error: '+error);
            } // errorの時
            else{
                console.log('exec: '+cmd);
            } // errorなしの時
        }
    )
};

http.createServer(function (req, res){
    if(req.method === 'GET'){
        res.writeHead(200,{'Content-Type': 'text/html'});
        res.end(form);
    }
    if(req.method='POST'){
        var postData = '';
        req.setEncoding('utf8');
        req.on('data',function (chunk){
            // per request
            postData += chunk;
        }).on('end',function(){
            // response data
            var respose_data = '';

            // end request
            if(!postData){
                res.end();
                return;
            } // if postData is empty.
            var postDataObject = querystring.parse(postData);
            console.log('user posted following data:' + postData);
            console.log(postDataObject.userinput1);
            respose_data += 'your poted data is:\n' + util.inspect(postDataObject)+'\n';

            if(postDataObject.userinput1 == '1'){
                led_onoff(cmd_ledon);
                respose_data += 'LEDが点灯しました !!';
            } // if userinput1で1がPOSTされたならledon
            if(postDataObject.userinput1 == '2'){
                led_onoff(cmd_ledoff);
                respose_data += 'LEDが消灯しました!!';
            } // if userinput1で2がPOSTされたならledoff

            res.end(respose_data,"utf8");
        });
    }
}).listen(8080);

LEDの点灯、消灯はpostDataObject.userinput1のみを見て判断しています。

1がPOSTされれば点灯、2がPOSTされれば消灯です。それ以外ならPOSTされた値が表示されるだけです。なお、postDataObject.userinput2は何も意味がありません。飾りです。

やってみる

まず、formに1を入力して送信すると・・・

f:id:hollywis:20160218093731p:plain

f:id:hollywis:20160218093738p:plain

LEDが点灯!!と表示され、コンソールを見てみると

f:id:hollywis:20160218094140p:plain

次に、formに2を入力して送信すると・・・

f:id:hollywis:20160218093549p:plain

f:id:hollywis:20160218093557p:plain

LEDが消灯!!と表示され、コンソールを見てみると

f:id:hollywis:20160218094205p:plain

実際にコマンドが発行されているのが確認出来ました。これでLEDを点灯させる準備が出来たとこになります。

まとめ

Nodeを利用してPOSTデータを受け取り、送信されるデータに従ってLEDを点灯・消灯させることが出来ました。

今回は仮想的にやりましたので、次回はRasberry pi上にNodeサーバを立ち上げて実際に遠隔からLEDをチカチカ制御してみたいと思います。

ではまた!