BluemixでIoT　温湿度、気圧を収集・蓄積・可視化＋LED制御 その８

##０．はじめに
[前回](http://qiita.com/hino9966/items/2ff8b224c64a2570d68e)の続きです。今回はGoogle GaugeとWebSocketを使用し、センサデータの可視化を行います。

##１．必要なもの（今回準備したもの）
|項目|数量|メモ|
|---|:---:|---|

##２．参考にさせていただいたところ
[Node-REDを使ってセンサーデータをWebSocketで出力する](http://qiita.com/asmanabu/items/03fcced66fd850a10061)
[Github (karuru6225/bme280i2c)](https://github.com/karuru6225/bme280i2c)
##３．JSONデータにデバイスIDを追加
受信したJSONデータには、デバイスIDが入っていません。将来複数のデバイスが増えた場合を考慮して、デバイスIDを付加するようにします。
**①デバイスIDを追加用のfunctionノードを追加する。**
Node-REDの左側にあるfunctionからfunctionノードを選択する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/98681aea-70a2-de16-1854-5bc7302a909e.png)

**②functionノードを編集する。**
　Name項目に、「devid追加」を入力する。
　Functionに、以下の内容を入力する。

```js:Function
devID = msg.deviceId;

msg.payload = {
    "deviceid" : devID,
    "timestamp": msg.payload.d.timestamp,
    "temp"     : msg.payload.d.temp,
    "humid"    : msg.payload.d.humid,
    "press"    : msg.payload.d.press
};

return msg;
```

![image](https://qiita-image-store.s3.amazonaws.com/0/113879/54e6b711-9a39-a334-ee5f-5144103a68f8.png)



##４．Websocket出力を追加
**①websocket出力用のノードを追加する。**
　Node-REDの左側にあるoutputからwebsocketノードを選択する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/1eeba01a-d702-0f8a-2274-4e409834fc9c.png)

**②websocket出力用ノードを編集する。**
　Type項目に、「Listen on」を選択する。
　Path項目に、「/ws/sensor」を入力する。
　Name項目に、「/ws/sensor」を入力する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/1593cadb-7ba0-260e-e12f-304af1d38db1.png)

**③センサ情報取得ノードとdevid追加ノードおよびwebsocket出力用ノードを接続する。また、DB蓄積前にdevidを追加するように変更する**
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/b9738ab7-368d-d76f-cfec-7920b5c3d926.png)

##５．Google Gaugeテンプレートの作成
ここでは、HTMLで表示するGoogle GaugeのHTMLテンプレートを作成する。
**①templateノードを追加する。**
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/0626c0d6-66ab-6768-ad96-b74c68c97701.png)

**②templateノードを編集する。**
　Name項目に、「Google Gauge」を入力する。
　Syntax Highlight項目に、「HTML」を選択する。
　Fomart項目に、「Plain text」を選択する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/1f2bbe24-d05f-a197-d69f-d7fe48f3c16b.png)
 
 Template内には、下記を入力してください。
*※var wsUrl = 'ws://XXXXXX.mybluemix.net/ws/sensor';*
*XXXXXXの部分は、自分の環境に合わせて変更してください。*

```js:Template
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>センサデータ　リアルタイム表示</title>
    <script type="text/javascript" src="//www.google.com/jsapi"></script>
    <script type="text/javascript">
      var wsUrl = 'ws://XXXXXX.mybluemix.net/ws/sensor';//XXXXXXのところは、自分の環境に合わせて変更してください。
      var socket;
      var temperatureData, humidityData, pressureData;
      var temperatureOptions, humidityOptions, pressureOptions;
      var temperatureChart, humidityChart, pressureChart;

      // Google Gauge
      google.load("visualization", "1", {packages:["gauge"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        // Data for temperature chart
        temperatureData = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ['温度', 0]
        ]);

        // Data for humidity chart
        humidityData = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ['湿度', 0]
        ]);

        // Data for Pressure chart
        pressureData = google.visualization.arrayToDataTable([
          ['Label', 'Value'],
          ['気圧', 0]
        ]);

        temperatureOptions = {
          width: 800, height: 240,
          min: 0, max: 60,
          redFrom: 50, redTo: 60,
          yellowFrom:40, yellowTo: 50,
          minorTicks: 5,
          majorTicks: ["0", "10","20", "30", "40", "50", "60"]
        };

        // Option for humidity chart
        humidityOptions = {
          width: 800, height: 240,
          min: 0, max: 100,
          redFrom: 90, redTo: 100,
          yellowFrom:75, yellowTo: 90,
          minorTicks: 5,
          majorTicks: ["0", "10","20", "30", "40", "50", "60", "70", "80", "90", "100"]
        };

        // Option for pressure chart
        pressureOptions = {
          width: 800, height: 240,
          min: 0, max: 1100,
          redFrom: 1050, redTo: 1100,
          yellowFrom:1010, yellowTo: 1050,
          minorTicks: 5,
          majorTicks: ["0", "","", "", "", "", "", "700", "800", "900", "1000", "1100"]
        };

        temperatureChart = new google.visualization.Gauge(document.getElementById('temperatureChart'));
        humidityChart = new google.visualization.Gauge(document.getElementById('humidityChart'));
        pressureChart = new google.visualization.Gauge(document.getElementById('pressureChart'));

        temperatureChart.draw(temperatureData, temperatureOptions);
        humidityChart.draw(humidityData, humidityOptions);
        pressureChart.draw(pressureData, pressureOptions);
        connect();
      };

      function connect() {
        socket = new WebSocket(wsUrl);
        socket.onmessage = function(e) {
          var sensorData = JSON.parse(e.data);

          // Update temperature data
          temperatureData.setValue(0, 1, sensorData.temp);

          // Update humidity data
          humidityData.setValue(0, 1, sensorData.humid);

          // Update pressure data
          pressureData.setValue(0, 1, sensorData.press);

          temperatureChart.draw(temperatureData, temperatureOptions);
          humidityChart.draw(humidityData, humidityOptions);
          pressureChart.draw(pressureData, pressureOptions);
        };
      };

      function disconnect() {
          socket.close();
      };


function clock() {
   var nowTime = new Date();
   var nowHour = ("0"+ nowTime.getHours()).substr(-2);
   var nowMin = ("0"+ nowTime.getMinutes()).substr(-2);
   var nowSec = ("0"+ nowTime.getSeconds()).substr(-2);
   var msg = "現在時刻：" + nowHour + ":" + nowMin + ":" + nowSec;
   document.getElementById("Clock").innerHTML = msg;
}
setInterval('clock()',1000);

    </script>
  </head>
  <body>
    <h2>温湿度・気圧　リアルタイム表示(Google Gauge)</h2>
    <p id="Clock"></p>
    <div>
      <button onclick="connect()">Connect</button>
      <button onclick="disconnect()">Disconnect</button>
    </div>

    <div>
      <div id="temperatureChart" style="width: 800px; height: 0px;"></div>
      <div id="humidityChart" style="width: 800px; height: 0px; position: relative; left: 230px;"></div>
      <div id="pressureChart" style="width: 800px; height: 220px; position: relative; left: 460px;"></div>
    </div>
  </body>
</html>
```

**③入力用HTTPノードを追加する。**
Node-REDの左側にあるinputからhttpノードを選択する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/ae008525-afac-8506-1f8a-3c33a06b2ea9.png)

**④入力用HTTPノードを編集する。**
　Method項目に、「GET」を選択する。
　URL項目に、「/sensor」を入力する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/230e4940-b990-efd7-d239-5d94f143750e.png)

**⑤出力用HTTPノードを追加する。**
Node-REDの左側にあるoutputからhttp responseノードを選択する。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/ffcdd94c-b99c-a254-8e43-a3b24bea4bfe.png)


**⑥入力用HTTPノードとGoogle Gaugeノードおよび出力用HTTPノードを接続する。**
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/29012b7b-54f3-a8bd-0a8b-cf8646d19d6a.png)

**⑦右上のDeployをクリックし、変更を反映する。**


##６．ブラウザで表示を確認
**①任意のブラウザで下記URLに接続する。**
http://XXXXXX.mybluemix.net/sensor  　※XXXXXXは、自分の環境にあわせて変更してください。

![image](https://qiita-image-store.s3.amazonaws.com/0/113879/e4fdafa9-bee9-33fc-8c01-5f158932c199.png)

**②Websocketの接続状況を確認する。**
 下図の赤枠「connected 1」になっていれば接続されています。
　※disconnectedになっている場合は、①の添付図にあるConnectボタンを再度クリックしてください。
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/9b8fc92d-c259-081a-0ba6-579315546c19.png)

**③以前作成した、mqtt.jsを使用してデータを投入する。**

```text:コマンド
pi@raspberrypi ~ $ node mqtt.js
```

**④Google Gaugeに結果がリアルタイムに反映することを確認する。**
![image](https://qiita-image-store.s3.amazonaws.com/0/113879/99c621a3-cb76-e7ad-3b36-88c37970d627.png)


**⑤mqtt.jsをカスタマイズする。**
　このままですと、固定の温度・湿度・気圧のため、変化がないので、ランダムに値が変化するように
　カスタマイズする。また、５秒置きにデータを発生させるように変更する。

```js:mqtt.js
var moment = require('moment');
var Client = require("ibmiotf").IotfDevice;

var config = {
省略
};

//ランダムデータを発生させる
var getRandomData = function(value){
   return Math.floor(Math.random()*8 + (value-3));
}
var client = new Client (config);

client.connect();

client.on("connect", function () {
   setInterval(function(){
      var nowtime = moment().format("YYYY-MM-DD HH:mm:ss.SSS");
      var temp_v = getRandomData(25);
      var humid_v = getRandomData(40);
      var press_v = getRandomData(1000);
      payload = JSON.stringify({d : { timestamp : nowtime, temp : temp_v, humid : humid_v, press : press_v }});
      console.log(payload);
      client.publish ("eid", "json", payload);
   }, 5000); //5000ms置き(5秒置きにデータを発生させる)
});
```

**⑥再度mqtt.jsを実行して、Google Gaugeがリアルタイムに変化することを確認する。**

##７．BME280センサデータの連携
**①githubで公開されているソースファイルを入手する。**
　自力で作成する力が足りなかったため、ここ[Github (karuru6225/bme280i2c)](https://github.com/karuru6225/bme280i2c)を利用させていただきました。

```text:コマンド
pi@raspberrypi ~ $ git clone https://github.com/karuru6225/bme280i2c.git
```
**②index.jsを参考にbme280.jsを作成する。**
　index.jsをbme280.jsとしてコピーする。

```text:コマンド
pi@raspberrypi ~ $ cp bme280i2c/index.js bme280.js
```

次の部分を編集する。編集個所は、ファイルの後ろにあるsetIntaval部分の３か所を編集する。

```js:bme280.js
（省略）
//setInterval(function(){　　　　　　　　//この行をコメントとし、
exports.bme = function(p_callback) {    //この行を追加する。
  async.waterfall([
      function(cb){
        readRawData(function(raws){
          cb(null, raws);
        });
      },
      function(raws, cb){
        var tbase = getTBase(raws.t, calib);
        var temp = calibrateT(tbase, calib);
        var pres = calibrateP(raws.p, tbase, calib);
        var humi = calibrateH(raws.h, tbase, calib);
        console.log('temp:' + (temp/100.0));
        console.log('pres:' + (pres/100.0));
        console.log('humi:' + (humi));
        console.log('');
        p_callback(temp/100.0, humi, pres/100.0); //この行を追加
        cb();
      }
  ]);
//},1000);　　//この行をコメントとし、
};            //この行を追加する。
```

**③bme280.jsを呼び出し、温度・湿度・気圧データを取得するように、mqtt.jsをカスタマイズする。**
カスタマイズ後のmqtt.jsは、下記の通り。

```js:mqtt.js
var f = require('./bme280.js');
var moment = require('moment');
var Client = require("ibmiotf").IotfDevice;

var config = {
 (省略)
};

function mkJson(callback) {
   f.bme(function(temp, humid, press){
      var nowtime = moment().format("YYYY-MM-DD HH:mm:ss.SSS");
      var temp_v =  temp.toFixed(1);
      var humid_v = humid.toFixed(1);
      var press_v = press.toFixed(1);
      payload = JSON.stringify({d : { timestamp : nowtime, temp : temp_v, humid : humid_v, press : press_v }});
      //console.log(payload);
      callback(payload);
   });
}

var client = new Client (config);

client.connect();

client.on("connect", function () {
   mkJson(function(payload) {
      console.log(payload);
      client.publish ("eid", "json", payload);
   });
   setInterval(function(){
        mkJson(function(payload) {
           console.log(payload);
        });
        client.publish ("eid", "json", payload);
   }, 60000);
});
```
**④mqtt.jsを実行する。**
　今回は、１分周期にしたため、適宜時間を変更して試してください。

以上で、Google GaugeとWebsocketを用いた可視化手順は終了です。

次([その９](http://qiita.com/hino9966/items/be8ecca36bd90aa8419a))は、chart.jsを利用しmongodbから取得した過去データを折れ線グラフで表示することを行います。