夏以降,Node.jsに取り組んでいるがイマイチ進展しない。やりたいことは,流行りのIoT(Internet of Things) …と言うことで,簡単な具体例を探したら身近なところにありました。

娘(@kosamari)のgithubのIoT-Boilerplate
Node.js, Express.js, Soket.io, Johnny-five 等を使ってArduino UNOにつないだLEDとスイッチを制御する例。

まず,これをそのままトレースして見ます。

概念図

IoT-Boilerplateより引用

準備
    1. 配線, IoT-Boilerplateより。
    2. Arduino UNOにStandardFirmataを書き込む。
      1. Arduino IDEのメニューバーから「ファイル」→「スケッチの例」→「Firmata」と進む。
      2. StandardFirmataを開きArduino UNOに書き込む。
    3. ソースコードのダウンロードと展開 (Linux, mac OSX)
      1. https://github.com/kosamari/IoT-Boilerplate のページを開く。
      2. [Download ZIP]ボタンをクリックして「IoT-Boilerplate-master.zip」をダウンロードする。
      3. ZIPファイルを展開するとIoT-Boilerplate-masterフォルダが生成される。
      4. ターミナル・シェルを起動してcdコマンドでIoT-Boilerplate-masterフォルダ(ディレクトリ)に移動する。
      5. lsコマンドでファイル一覧を表示し,package.jsonがあることを確認する。
      6. package.json に記述されているモジュールを自動インストールする
        $npm install [enter]
      7. johnny-five モジュールはpackage.jsonに記述されていないので手動インストールする。
        $npm install johnny-five [enter]
実行
    1. バックグラウンドでserver.jsを実行する。
      $node server.js & [enter]
    2. client.jsを実行する。
      $node client.js[enter]
    3. server.js, client.js を実行しているマシンでブラウザを起動する。
    4. ブラウザで http://localhost:5030 を開くと下のページが表示される。
      1. LED conroll セクションのTurn On, Turne Off ボタンのクリックでLEDを点消灯することができる。
      2. ブレッドボード上のタクトスイッチを押すと Button Reciver セクションのメッセージが button connected to pin 8 is pressed! と変化する。
IoT_BoiLerplate
停止
  1. CTRL+Cを2回入力してclient.jsの実行を止める。
  2. psコマンドでプロセスを表示するとnode server.js のプロセス番号 xxxxx が見える。
  3. プロセスxxxxxをkill(停止)する。
    $kill xxxxx [enter]
動作の理解
  1. ブラウザ操作→LED点消灯
    1. Webブラウザでserver.jsにアクセスするとserver.jsは ./view/controller.html をWebブラウザに向けて送り出す。
      このとき,controller.html に記述されている{{port}}の部分をioportの値 5040 に置換する。

      app.get('/', function (req, res) {
        res.render('controller', {port:ioport});
       });

      同時に,http://localhost:5040/socket.io/socket.io.js のスクリプトをブラウザで利用できるようにする。(controller.htmlの記述)

      <script src="http://localhost:{{port}}/socket.io/socket.io.js"></script>
      

      注:{{port}}は5040と置き換えられる。

    2. WebブラウザでTurnOnボタンをクリックすると,
      <button class="btn" onclick="led('on')" disabled/>Turn On</button>

      により,次のfunction led(command)が駆動される。このとき引数commandには’on’が引き渡される。

       function led(command) {
          socket.emit('led', {command:command});
      }

      function ledが実行されると,server.js に向けて ‘led’ ‘on’ のメッセージが送出される。

    3. このメッセージを受けたserver.jsは,そのままブロードキャスト(プッシュ)する。
        socket.on('led', function(data) {
          socket.broadcast.emit('led', data);
        });
    4. ブロードキャストされたメッセージをclient.jsが受信すると,’led’メッセージであれば,それに続く引数’on’,’off’により function led.on(), led.off() を実行する。
        socket.on('led', function(data){
          if(data.command === 'on'){
            led.on();
          }else if(data.command === 'off'){
            led.off();
          }
        });

      ledは次によりD13に割り振られている。on(), off() は johnny-five が持っているfunctionでon()はHIGHT,off() はLOWを出力する。

        var led = new five.Led(13);
    5. led.on() は johnny-five で Firmata プロトコルのメッセージに変換されUSB-serialポートを通してArduino UNOに送られる。
    6. Arduino UNOではStandardFirmataがメッセージを受け取ってD13にHIGHTを出力する。
    7. D13に接続されたLEDが点灯する。
  2. タクトスイッチを押す→Webブラウザで表示しているメッセージが変わる
    1. タクトスイッチを押すと,Arduino UNO StandardFirmata がUSB-Serialを通してclient.jsにメッセージ ‘press’ を送る。
    2. メッセージ ‘press’ を受信したclient.jsは,’press’, ‘pin:8’ のメッセージを server.js に送る。
      button.on('press', function() {
        socket.emit('press', {pin:8});
      });
    3. メッセージ ‘press’, ‘pin:8’ を受信した server.js は,そのままブロードキャスト(プシュ)する。
       socket.on('press', function(data) {
         socket.broadcast.emit('press', data);
       });
    4. ブロードキャストされたメッセージをWebブラウザが受信すると,socket.on(‘press’, function (data){ });のスクリプトが実行される。
      socket.on('press', function (data) {
          var message = document.getElementById("message");
          message.innerHTML = 'button connected to pin '+ data.pin +' is pressed!';
      });

      結果,<span id=’message’>〜</span> が書き換わって表示される。

       <span id='message'>Press the button on your hardware</span> が
       <span id='message'>button connected to pin 8 is pressed!</span> と書き換えられる
改編
  1. IoT-Boilderplateの localhost の部分を書き換えて,他のコンピュータのwebブラウザからアクセスしLチカできるようにしてみる。server.js, client.jsを稼働させるコンピュータのIPアドレスが192.168.10.209と仮定する。
    1. server.jsの改編
      6行目 追加,14行目 変更

      var express = require('express');
      var app = express();
      var port = 5030;
      var ioport = 5040;
      var io = require('socket.io').listen(ioport);
      var iohost = '192.168.10.209';//追加
      /*
      * express server setup
      */
      app.set('view engine', 'html');
      app.engine('html', require('hbs').__express);
      
      app.get('/', function (req, res) {
        res.render('controller', {host:iohost, port:ioport});//変更
      });
      
      //-- 以下略 --//
    2. controller.htmlの改編
      19行目と26行目を変更

      <!DOCTYPE HTML>
      <html>
        <head>
          <meta charset="UTF-8">
          <title>IoT Controller</title>
          <link rel="stylesheet" type="text/css" href="./controller.css">
        </head>
        <body>
          <h1>IoT Controller</h1>
          <h2>LED controll</h2>
            <button class="btn" onclick="led('on')" disabled/>Turn On</button>
            <button class="btn" onclick="led('off')" disabled/>Turn Off</button>
          <br>
          <br>
          <h2>Button Reciver</h2>
          <span id='message'>Press the button on your hardware</span>
      
      
          <script src="http://{{host}}:{{port}}/socket.io/socket.io.js"></script>
          <script type="text/javascript">
            /*
            * Setup
            */
      
            //1. specify domain and port of your socket.io server
            var socket = io.connect('http://{{host}}:{{port}}');
      
      //-- 以下略 --//
    3. client.jsの改編
      6行目を変更

      /*
      * Setup
      */
      
      //1.  specify domain and port of your socket.io server
      var socket = require('socket.io-client')('http://192.168.10.209:5040');
      
      //-- 以下略 --//
  2. タクトスイッチを押すとメッセージが変化するが,離してもメッセージがbutton connected to pin 8 is pressed!のままなので,離すと元のメッセージに戻るようにしてみる。
    1. client.jsの改編
      // 3. Create socket message emitter の下に次の行を追加

        button.on('up',function(){
          socket.emit('up',{pin:8});
        });
    2. server.jsの改編
      // Define socket messages used in your application の下に次の行を追加

        socket.on('up', function(data) {
          socket.broadcast.emit('up', data);
        });
    3. controller.htmlの改編
      <script type=”text/javascript”>〜 </script> の間に次の行を追加

        socket.on('up', function (data) {
          var message = document.getElementById("message");
          message.innerHTML = 'Press the button on your hardware';
        });
  3. server と client を別マシンにする。
    1. server.js を Linuxマシン(192.168.10.209)で稼働させる。
    2. client.js をArduino UNO を接続した Rasspberry Pi(192.168.10.210) で稼働させる。
    3. さらに,別マシンでWebブラウザを起動しhttp://192.168.10.209:5030(Linuxマシン)にアクセスしLEDのTurnOn/TurnOffを行う。
    4. ブレッドボードのタクトスイッチの操作を行う。

    ソースコードは1,2の改編のままで正しく動く。