Node-RED小ワザ集

[Node-RED](http://nodered.org/)で使える小ワザをまとめていきます。Node-REDの実行環境はIBM Bluemixを利用します。

## 前提
IBM Bluemix上でボイラープレート「Node-RED Starter」、または、「Internet of Things Foundation」がデプロイされていることとします。

## 小ワザ1. フローのインポート
フローエディターの右上の三本線のメニューバーより「Import」→「Clipboard」の順で選択します。
![nodered-import-01.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/a5e27e8c-ef67-e68c-658f-e60c54cfc352.jpeg)

JSON形式で記述されたフローを枠内にコピーし「OK」をクリックします。
![nodered-import-02.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/8de5dcd2-abbb-7fe1-ae65-0f37ae83b906.jpeg)

サンプルのフローです。コピーして利用してみてください。

```
[{"id":"bd2402cf.2fb78","type":"websocket-listener","path":"/ws/sensor","wholemsg":"false"},{"id":"184a0fa5.45eaa8","type":"ibmiot in","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"0C60110016ea","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IoT Sensor","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","x":99,"y":147,"z":"4b3f3f7f.65a9a8","wires":[["2f6b16a3.dca7e2"]]},{"id":"2f6b16a3.dca7e2","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":301,"y":147,"z":"4b3f3f7f.65a9a8","wires":[["242a56f5.2f771a","a967f901.ee1508"]]},{"id":"242a56f5.2f771a","type":"debug","name":"","active":false,"console":"false","complete":"payload","x":441,"y":63,"z":"4b3f3f7f.65a9a8","wires":[]},{"id":"a967f901.ee1508","type":"websocket out","name":"WebSocket Output","server":"bd2402cf.2fb78","client":"","x":532,"y":147,"z":"4b3f3f7f.65a9a8","wires":[]}]
```

以下のフローが表示されることを確認してください。
![nodered-import-03.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/4eb368c2-681a-9329-d0e4-4d770ffb7c8d.jpeg)

[Node-REDのサイトにサンプルフローが公開されています](http://flows.nodered.org/)ので、いろいろと試してみてください。

## 小ワザ2. センサーデータを加工してタイムスタンプを追加する
センサーデータをデータベースに保管する際に、タイムスタンプを付けて保管したいケースがあると思います。Node-REDのfunctionノード（![nodered-function01.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/07d93062-ddb2-ff49-d370-920ef0448739.jpeg)）を使ってタイムスタンプを追加する方法を紹介します。

サンプルのフローは以下のような感じです。この例では、センサーデータは、[センサーシミュレーター](https://quickstart.internetofthings.ibmcloud.com/iotsensor/)から出力されるデータを使用しています。
![nodered-timestamp01.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/92913d85-2046-b634-cc14-643c52258863.jpeg)

"Convert Payload"と書かれたfunctionノードには、以下のJavascriptのコードが埋め込まれています。センサーデータの加工部分は非常に単純で、`msg.payload`に出力したいデータをJSON形式で格納しているだけです。
大半がタイムスタンプの整形用のコードとなっています。また、Bluemix上はUTCで扱われるため、`date.setHours(date.getHours() + 9);`により、JSTに変換しています。

```
var getCurrentTime = function () {
    var date = new Date();
    date.setHours(date.getHours() + 9);
    var d = date.getFullYear() + '-';
    d += ('0' + (date.getMonth() + 1)).slice(-2) + '-';
    d += ('0' + date.getDate()).slice(-2) + 'T';
    d += ('0' + date.getHours()).slice(-2) + ':';
    d += ('0' + date.getMinutes()).slice(-2) + ':';
    d += ('0' + date.getSeconds()).slice(-2) + 'Z';
    return d;
};

msg.payload =  {
    "timestamp": getCurrentTime(),
    "temp": msg.payload.d.temp,
    "humidity": msg.payload.d.humidity,
    "objectTemp": msg.payload.d.objectTemp
};

return msg;
```

出力例です。

```
{ "timestamp": "2015-04-23T03:60:15Z", "temp": 16, "humidity": 78, "objectTemp": 23 }
```

以下のJSONを、小ワザ1. の方法を使ってインポートすることで、サンプルフローを復元できます。

```
[{"id":"a096f3c0.8b2af","type":"ibmiot in","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"a910e6c629f2","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"Sensor Simulator","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","x":125,"y":114,"z":"56be2dc6.6f2e4c","wires":[["b35ec10c.df9bc"]]},{"id":"b35ec10c.df9bc","type":"function","name":"Convert Payload","func":"var getCurrentTime = function () {\n    var date = new Date();\n    date.setHours(date.getHours() + 9);\n    var d = date.getFullYear() + '-';\n    d += ('0' + (date.getMonth() + 1)).slice(-2) + '-';\n    d += ('0' + date.getDate()).slice(-2) + 'T';\n    d += ('0' + date.getHours()).slice(-2) + ':';\n    d += ('0' + date.getMinutes()).slice(-2) + ':';\n    d += ('0' + date.getSeconds()).slice(-2) + 'Z';\n    return d;\n};\n\nmsg.payload =  {\n    \"timestamp\": getCurrentTime(),\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":326,"y":114,"z":"56be2dc6.6f2e4c","wires":[["2bd52b43.6ff1fc"]]},{"id":"2bd52b43.6ff1fc","type":"debug","name":"Check Output","active":false,"console":"false","complete":"payload","x":521,"y":114,"z":"56be2dc6.6f2e4c","wires":[]}]
```

## 小ワザ3. センサーからの出力形式を確認する
IoT Foundationに対して、使用するセンサーからどのような形式でデータが出力されているか、まず最初に確認したいことと思います。各センサーのマニュアルを確認するのが王道ですが、手っ取り早くやるために、Debugノードを使って確認してみましょう。

作成するフローは非常にシンプルで、以下のフローとなります。
![nodered-checkinput.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/1ee9b2e0-92bd-b21e-5c19-00fe26fbe567.jpeg)

Texas Instruments社の[CC2541 SensorTag](http://www.tij.co.jp/tool/jp/cc2541dk-sensor)での出力を確認してみました。

```
2015/4/23 11:43:47[Check Input]iot-2/type/"multitool-app"/id/xxxxxxxxxxxx/evt/status/fmt/json : [msg.payload] : object{ "d": { "AmbTemp": "24.875", "IRTemp": "18.99777", "humidity": "48.24201", "magX": "5.310059", "magY": "-4.760742", "magZ": "-3.326416", "gyroX": "-3.410339", "gyroY": "-4.051208", "gyroZ": "-1.64032" } }
```

`[msg.payload]`とあるように、payload要素の下にデータが入っています。出力結果を見てみると、payloadの中のd要素、つまり、`msg.payload.d`要素に各データが入っているようですね。magXは、magnetometerX、gyroXはgyroscopeXの略でしょうか。つまり、方位と回転速度をそれぞれ表していると推測できます。

## 小ワザ4. センサーの特定のデータのみ抽出する
小ワザ3でセンサーからの出力形式を確認しました。今回は、確認した形式の中から、特定のデータのみを抽出する方法です。

データの抽出にはfunctionノードを使用します。サンプルとして、以下のフローを作成します。
![nodered-extract-gyro.jpg](https://qiita-image-store.s3.amazonaws.com/0/73397/18dce084-6906-9459-a048-52d926b6c9e6.jpeg)

小ワザ3に記載したとおり、センサーデータは、`msg.payload.d`要素の中に格納されています。それを参照すればよいので、たとえば回転速度の値のみを使いたい場合は、以下のように記述できます。

```
var gyroX = msg.payload.d.gyroX;
var gyroY = msg.payload.d.gyroY;
var gyroZ = msg.payload.d.gyroZ;

msg.payload = {
    x: gyroX,
    y: gyroY,
    z: gyroZ
};

return msg;
```

次のノード（ここではDebugノード）にデータを渡さないといけないため、`msg.payload`の中に抽出したデータを保管しています。このフローをデプロイし、Debugの出力を確認した結果が以下となります。x, y, zそれぞれに抽出したデータが保管されています。

```
2015/4/23 14:02:53[Check Input]iot-2/type/"multitool-app"/id/xxxxxxxxxxxx/evt/status/fmt/json : [msg.payload] : object{ "x": "-5.271912", "y": "-173.2178", "z": "154.6631" }
```

以下のJSONを、小ワザ1. の方法を使ってインポートすることで、サンプルフローを復元できます。

```
[{"id":"138b5b7c.ea7dfd","type":"ibmiot in","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"be150f155552","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"Input from Sensor","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","x":178,"y":99,"z":"fbe3c77.a1adbb8","wires":[["11051acf.600bdd"]]},{"id":"2f3b1ac7.8cc2c6","type":"debug","name":"Check Input","active":true,"console":"false","complete":"payload","x":556,"y":99,"z":"fbe3c77.a1adbb8","wires":[]},{"id":"11051acf.600bdd","type":"function","name":"extract gyrp data","func":"var gyroX = msg.payload.d.gyroX;\nvar gyroY = msg.payload.d.gyroY;\nvar gyroZ = msg.payload.d.gyroZ;\n\nmsg.payload = {\n    x: gyroX,\n    y: gyroY,\n    z: gyroZ\n};\n\nreturn msg;","outputs":1,"valid":true,"x":374,"y":99,"z":"fbe3c77.a1adbb8","wires":[["2f3b1ac7.8cc2c6"]]}]
```


## 小ワザ5. xxx
Comming soon...