Node-REDを使ってセンサーデータをWebSocketで出力する

# はじめに
Node-REDのサンプルを見ると、「Debugノードへ出力して終わり」というものが少なくありません。実際にセンサーデータを活用する場合は、データを可視化したり、データストアに保管したり、分析したりと様々なケースがあるかと思います。

今回は、センサーデータをWebSocketで出力し、ブラウザ側で可視化することに取り組んでみます。可視化には、[Google Gauge](https://developers.google.com/chart/interactive/docs/gallery/gauge)を利用します。

# 前提
1. IBM Bluemix上でボイラープレート「Node-RED Starter」、または、「Internet of Things Foundation」がデプロイされていることとします
2. Cloud Foundryのコマンド・ライン・インターフェース（cfツール）が導入されていることとします
 * cfツールのインストールは、「Bluemixマニュアル」の["Cloud Foundry コマンド・ライン・インターフェースを使用したコーディングの開始"](https://www.ng.bluemix.net/docs/#starters/install_cli.html)を参照してください。

# 作業の流れ

1. Node-REDのフローを作成
2. Githubからサンプルプログラムを取得
3. サンプルプログラムのindex.htmlを編集
4. IBM Bluemixにサンプルプログラムをpush
5. 動作確認

# Node-REDのフローを作成
以下のフローを作成します。このフローは、IoT Foundationからセンサーデータを受け取り、必要なデータのみを抽出し、そのデータをWebSocketで出力するフローです。
![nodered-import-03.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/4eb368c2-681a-9329-d0e4-4d770ffb7c8d.jpeg)

以下の4つのノードを利用しています。

| ノード |  | 用途 |
|:--|:-:|:--|
|ibmiot（入力）ノード | ![nodered-ibmiot-input.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/cead87a6-4133-235c-8937-45e0f2dbe469.jpeg) | センサーデータの入力受付 |
| functionノード | ![nodered-function.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/b1d5e723-95bc-af84-b0de-e18ed6f2c25b.jpeg) | センサーデータの加工 |
| WebSocket（出力）ノード | ![Nodered-WebSocket-output.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/22722863-9d51-c342-143d-14d70a361e1f.jpeg) | 加工したセンサーデータをWebSocketで出力 |
| Debugノード | ![nodered-debug.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/449ea1c7-f145-1318-2901-afb4a7afc6d1.jpeg) | センサーデータの加工結果確認 |

## ibmiotノードの構成
ibmiotは、[センサー・シミュレーター](https://quickstart.internetofthings.ibmcloud.com/iotsensor/)を使用するように構成しています。TI社のセンサータグやRaspberry Piなどを使用される場合は、適宜修正ください。

| 設定項目 | 内容 |
| :-- | :-- |
| Authentication | 今回は認証を使用しないため、Quickstartを選択します |
| Input Type | Device Eventを選択します |
| Device Id | センサー・シミュレーターのMACアドレスのコロン（:）を除き、アルファベットは小文字に変換した値を入力します。 |
| Name | ノードに付ける名前です。任意の値で問題ありません。 |

入力例は以下のとおりです。
![Nodered-ibmiot.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/e582ef34-ea63-e9e7-3d29-5e1dff4945b0.jpeg)

## functionノードの構成
以下の例のように、センサーデータのみをJSONで出力するように変換します。

```json

{ "temp": 16, "humidity": 78, "objectTemp": 23 }
```

以下のJavaScriotをfunctionノードに埋め込みます。

```js
msg.payload =  {
    "temp": msg.payload.d.temp,
    "humidity": msg.payload.d.humidity,
    "objectTemp": msg.payload.d.objectTemp
};

return msg;
```

## WebSocket（出力）ノードの構成
加工したセンサーデータをWebSocketで出力できるように構成します。

| 設定項目 | 内容 |
| :-- | :-- |
| Type | Listen onを選択します |
| Path | /ws/sensorとします。設定方法は後述します。 |
| Name | ノードに付ける名前です。任意の値で問題ありません。 |

Pathの設定は、別途作成が必要です。Pathの右側にある![Nodered-edit.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/1731939d-4585-49eb-ff4f-db432a6ae60d.jpeg)をクリックすると、Pathを設定できます。今回は、以下の図のように設定します。

![Nodered-websocket-listner.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/811f5747-a224-e77e-a94e-faa9ccdf7504.jpeg)

上記設定で、WebSocket出力が完成です。WebSocketのURLは、以下となります。

```
ws://(Node-REDをデプロイしたランタイムのURL)/ws/sensor
```

たとえば、Node-REDのフローエディターのURLが以下の場合、

```
http://iotfvisualizationsample.mybluemix.net/red/#
```

WebSocketのURLは、以下となります。

```
ws://iotfvisualizationsample.mybluemix.net/ws/sensor
```

## （参考）サンプルフローのインポート

以下のJSONを、[Node-RED小ワザ集](http://qiita.com/asmanabu/items/d9ba9ff0fca745c8c216)の[小ワザ1. フローのインポート](http://qiita.com/asmanabu/items/d9ba9ff0fca745c8c216#%E5%B0%8F%E3%83%AF%E3%82%B61-%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88)の方法を使ってインポートすることで、サンプルフローを復元できます。

```json
[{"id":"bd2402cf.2fb78","type":"websocket-listener","path":"/ws/sensor","wholemsg":"false"},{"id":"ffc1357f.03c8e8","type":"ibmiot in","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"88b29a5f62eb","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IoT Sensor","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","x":230,"y":196,"z":"aaf8734f.9d6bc","wires":[["529ac4cf.69d984"]]},{"id":"529ac4cf.69d984","type":"function","name":"CreateMessage","func":"msg.payload =  {\n    \"temp\": msg.payload.d.temp,\n    \"humidity\": msg.payload.d.humidity,\n    \"objectTemp\": msg.payload.d.objectTemp\n};\n\nreturn msg;","outputs":1,"valid":true,"x":432,"y":196,"z":"aaf8734f.9d6bc","wires":[["dd32a123.2d572","6f5fdabc.f40f5c"]]},{"id":"dd32a123.2d572","type":"debug","name":"","active":true,"console":"false","complete":"payload","x":572,"y":112,"z":"aaf8734f.9d6bc","wires":[]},{"id":"6f5fdabc.f40f5c","type":"websocket out","name":"WebSocket Output","server":"bd2402cf.2fb78","client":"","x":663,"y":196,"z":"aaf8734f.9d6bc","wires":[]}]
```

## 2. Githubからサンプルプログラムを取得

Githubに[Google Gaugeを利用するサンプルプログラム](https://github.com/asmanabu/SensorVisualizationSample)を用意しました。こちらを利用します。

```
git clone https://github.com/asmanabu/SensorVisualizationSample
```

ここでは、C:\work\SensorVisualizationSample にcloneしたこととします。

## 3. サンプルプログラムのindex.htmlを編集

index.htmlにGoogle Gaugeを利用するJavaScriptを記述しています。この中で、WebSocketのURLを指定する箇所がありますので、その部分を修正します。具体的には、10行目の以下の部分です。

```
var wsUrl = '<Your WebSocket URL>';
```

`<Your WebSocket URL>`の部分を、先ほどNode-REDのWebSocketノードを追加した際のURLに置き換えます。

index.html内のJavaSciptについて、簡単に細くします。18行目から58行目までは、Google Gaugeの初期設定です。温度（TemperatureとObject Temperature）用のGaugeと、湿度（Humidity）用のGaugeの2種類を用意しています。

60行目から75行目までの以下の部分が、WebSocketでデータを受信し、Gaugeの値を変更する箇所とります。

```js
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);
    temperatureData.setValue(1, 1, sensorData.objectTemp);
    
    // Update humidity data
    humidityData.setValue(0, 1, sensorData.humidity);
    
    temperatureChart.draw(temperatureData, temperatureOptions);
    humidityChart.draw(humidityData, humidityOptions);
  };
};
```

## 4. IBM Bluemixにサンプルプログラムをpush
修正したサンプルプログラムをIBM Bluemixにデプロイします。

デプロイの際に設定する情報は、*manifest.yml*に記述できます。アプリケーションが使用するホスト名が、他のユーザーと重複しないように修正します。

エディターで C:\work\SensorVisualizationSample\manifest.yml を開きます。
*\<change to your hostname\>* の部分を修正してください。

manifest.ymlの修正例です。この例の場合ですと、`vissample20150508.mybluemix.net`がサンプルアプリケーションのURLとなります。

```yaml

applications:
- disk_quota: 1024M
  name: Sensor Data Visualization Sample
  host: vissample20150508
  domain: mybluemix.net
  path: ./public
  instances: 1
  memory: 64M
  buildpack: https://github.com/cloudfoundry-incubator/staticfile-buildpack
```

manifest.ymlの修正が終わったら、cfツールを利用してBluemixにアプリケーションをデプロイします。
C:\work\SensorVisualizationSampleに移動し、`cf push`を実行します。
現在のディレクトリ以下にあるすべてのファイルをBluemixに転送します。**不要なファイルを転送しないように、必ずディレクトリを移動してください。**

## 5. 動作確認
manifest.ymlに記載したURLにブラウザでアクセスします。「Connect」を記載されたボタンをクリックすると、WebSocketの接続が開始され、センサーデータの受信が始まります。センサー・シミュレーターの値を変更し、Gaugeの針が動くことを確認してみてください。

![VisSample.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/f8cd5fb7-8f46-6f32-973e-d7dcf0378337.jpeg)