Node-REDで使える小ワザをまとめていきます。Node-REDの実行環境はIBM Bluemixを利用します。
前提
IBM Bluemix上でボイラープレート「Node-RED Starter」、または、「Internet of Things Foundation」がデプロイされていることとします。
小ワザ1. フローのインポート
フローエディターの右上の三本線のメニューバーより「Import」→「Clipboard」の順で選択します。
JSON形式で記述されたフローを枠内にコピーし「OK」をクリックします。
サンプルのフローです。コピーして利用してみてください。
[{"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":[]}]
Node-REDのサイトにサンプルフローが公開されていますので、いろいろと試してみてください。
小ワザ2. センサーデータを加工してタイムスタンプを追加する
センサーデータをデータベースに保管する際に、タイムスタンプを付けて保管したいケースがあると思います。Node-REDのfunctionノード()を使ってタイムスタンプを追加する方法を紹介します。
サンプルのフローは以下のような感じです。この例では、センサーデータは、センサーシミュレーターから出力されるデータを使用しています。
"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ノードを使って確認してみましょう。
Texas Instruments社のCC2541 SensorTagでの出力を確認してみました。
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ノードを使用します。サンプルとして、以下のフローを作成します。
小ワザ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...