Node-REDには入出力処理やさまざまな機能を実装した便利なノード(部品)があらかじめ用意されていますが、それ以外にもコミュニティや個人が作成したノードが多数公開されていて、用途に応じて追加で組み込んで使用ことができます。
nodered.orgのNode-RED Library を見ると、現時点(2017年8月時点)で1000個以上のノードが公開されているのですが、その中にnode-red-dashboardという、ダッシュボード(計器盤)が作れる便利な部品があります。
今回はこれを使って、センサーデータをグラフィカルに可視化するNode-REDフローを作ってみます。
手順は以下のとおりです。
- Node-REDにnode-red-dashboardを組み込む
- 温度センサーのデータを受信するフローを作成する
- 温度データをダッシュボードのtextノードに表示する
- ダッシュボードにGaugeノード、chartノードを追加する
- 湿度データ、物体温度データもダッシュボードに表示する
1. Node-REDにnode-red-dashboardを組み込む
Node-REDにはノードを追加する機能が用意されているので、これを使ってnode-red-dashboardをさっそく組込んでみましょう。画面右上の三本線をクリックして、プルダウンメニューから「パレットの管理」を選択します。
タブを「現在のノード」から「ノードを追加」に切り替えます。検索キーワードに「dashbo」くらいをタイプしたところで選択肢にnode-red-dashboardが現れるので、「ノードを追加」をクリックします。
「ノードを追加」ボタンが「追加しました」に変わったら追加完了です。
「閉じる」でパレットの管理を終了して元の画面に戻り、左側のパレットをスクロールダウンすると、追加されたdashboardの部品群が現れます。画面右側の「デバッグ」タブの隣には「dashboard」タブが追加されていました。
2. 温度センサーのデータを受信するフローを作成する
ダッシュボードに表示するデータの発生源として、IBMのIoTデモでよく使われる温度センサーシミュレータを使うことにします。シミュレータはhttps://quickstart.internetofthings.ibmcloud.com/iotsensor/ を開くと現れます。
シミュレータには温度(Temperature)、湿度(Humidity)、物体温度(Object Temperature)の3種類のセンサーがあり、画面の左右にある"<",">"で切り替えることができます。画面下にある"↓","↑"で温度等を上昇、下降することができます。センサーデータはWatson IoT Platformを経由してNode-REDのIBM IoTノードに毎秒送信されます。
センサー右肩にはセンサーID(ここでは3fbd1f674143)が表示されており、IBM IoTノードはこのIDでセンサーを識別します。
次に、このセンサーのデータを受信するフローを作成します。パレットの「入力」部品群から「ibmiot」を選択してキャンバスにドラッグ&ドロップします。
キャンバスの「IBM IoT」ノードをダブルクリックして設定画面を表示します。先程のセンサーIDを「Device Id」の欄にコピペし、他はデフォルトのまま「完了」をクリックしてキャンバスに戻ります。
ダッシュボードを作成する前に、まずはdebugノードを使ってIBM IoTノードの動作を確認します。パレットの「出力」部品群から「debug」を選択してキャンバスにドラッグ&ドロップし、「IBM IoT」と「msg.payload」の端子間をドラッグして接続します。
右側表示領域を「デバッグ」タブに切り替えておき、右上の「デプロイ」ボタンをクリックしてフローをデプロイします。
デプロイが完了すると同時に、デバッグ画面に1秒毎にメッセージが表示されるようになれば、フロー作成は成功です。
debug(msg.payload)ノードの右側のタブ(出っ張り)をクリックすると、メッセージ出力のON/OFFを切り替えることができます。クリックして薄緑色にするとメッセージ出力が止まります。
メッセージの{ d: object }は階層構造のjsonデータで、左側の三角形をクリックして展開できます。
実はIBM IoTノードの出力はmsgというjsonデータなのですが、このデータはmsgの下にpayload、payloadの下にdという階層構造になっていて、更にdの下に"name","temp","humidity","objectTemp"という4種類のデータが含まれていて、それがここに表示されています。このうち"temp","humidity","objectTemp"の値が、シミュレータの「温度(Temperature)」「湿度(Humidity)」「物体温度(Object Temperature)」のデータにそれぞれ対応しています。シミュレータの値を"↓","↑"で変化させると、これらの値も変化します。
3. 温度データをダッシュボードのtextノードに表示する
センサーのデータをNote-REDで受信できるようになったので、次にこのデータをダッシュボードに表示するフローを作成します。dashboard部品群のうち"text","gauge","chart"の3種類の部品を使います。
このうち"gauge"と"chart"は入力データがmsg.payloadに固定されているので、まずは"IBM IoT"の出力をmsg.payloadに変換するノードを作成します。
「機能」部品群から「change」を選択してキャンバスにドラッグ&ドロップします。
changeノード(「set msg.payload」と表示)をダブルクリックして設定画面を表示します。まず「対象の値」の「az」を「msg.」に切り替えます。
「対象の値」の「msg.」に続いて「payload.d.temp」と入力します。他の値はデフォルトのままでOKです。入力したら「完了」をクリックしてキャンバスに戻ります。
それではいよいよ「dashboard」部品群からノードを追加していきます。まずは「text」を選択してキャンバスにドラッグ&ドロップします。
「text」ノードをダブルクリックして設定画面を開き、まずはGroupを編集します。「新規にui_groupを追加...」の右側の鉛筆マークをクリックします。
Name(「Group」の名前)を「Default」から「温度」に変更します。更に続けてTabを編集します。「新規にui_tabを追加...」の右側の鉛筆マークをクリックします。
Tab名はDefaultのHomeのままでも動作上は問題ないのですが、ここではシミュレータの表示の「IoT Sensor」に合わせることにします。Nameの値を「Home」から「IoT Sensor」に変更し、追加をクリックして一つ前の画面(groupノード設定画面)に戻ります。
Tabの表示が「IoT Sensor」に変わったことを確認し、「追加」をクリックして一つ前の画面(textノード設定画面)に戻ります。
Groupの表示が「温度 [IoT Sensor]」に変わったことを確認します。更にLabelの値を「text」から「温度」に変更します。他の値はデフォルトのまま、「完了」をクリックしてキャンバスに戻ります。
キャンバスに戻ったら、右側の「dashboard」タブをクリックして画面を切り替えます。LayoutタブのTabs & Linksの下に先程定義した「IoT Sensor」(Tab名)、「温度」(Group名)などの名前が表示されています。Group名の「温度」をクリックして展開すると、textノード名の「温度」が現れます。
キャンバス上でIBM IoTノードとchangeノード、changeノードとtextノードの端子間をドラッグしてつなぎ、フローを作成します。フローができたら右上の「デプロイ」をクリックして、フローをデプロイします。
デプロイが成功したら、画面右端の「Site」タブの右側にある四角に矢印のアイコンをクリックして、ダッシュボードを開きます。
温度をテキストで表示するだけのシンプルなダッシュボードが現れます。Tab名「IoT Sensor」がブルーに白抜きで、その下にGroup名「温度」が水色の文字で表示され、その下に「温度 17」と表示されています。
この17はシミュレータから届いたmsg.payload.d.tempをリアルタイムに表示しています。シミュレータの値を変更して、ダッシュボードの値の変化を確認してみましょう。
4. ダッシュボードにgaugeノード、chartノードを追加する
パレットのgaugeノードを選択して、キャンバスにドラッグ&ドロップします。
Gauteノードをダブルクリックして設定画面を開きます。
Group名はすでに「温度 [IoT Sensor]」になっているので、そのまま受け入れます。
下の方にあるRangeの項目で、値をmin=0、max=40にセットしておきます。さらにその下のSectorsを、「0 ... 30 ... 35 ... 40」にします。温度が0〜30の時は緑色、30〜35の時は黄色、35〜40の時は赤色で表示することを表しています。
その他の値はデフォルトのままで「完了」をクリックし、キャンバスに戻ります。
キャンバスに戻ったら、changeノードとGaugeノードの端子間をドラッグしてつなぎ、右上の「デプロイ」をクリックしてフローをデプロイします。
デプロイしたらダッシュボードの画面に切り替え、Gaugeが追加されていることを確認します。
シミュレータで温度を上げていくと、Gaugeの針が右に傾き、表示色が緑から黄、更には赤に変化します。
chartノードをパレットからキャンバスにドラッグ&ドロップした後、ダブルクリックして設定画面を開きます。Y-axis(Y軸)の範囲をmin=0,max=40にセットし、他はデフォルトを受け入れて「完了」クリックします。
キャンバスに戻ったら、changeノードとchartノードの端子間をドラッグしてつなぎ、右上のデプロイをクリックしてフローをデプロイします。
デプロイしたらダッシュボードの画面に切り替え、chartが追加されていることを確認します。
シミュレータの温度を上下させると、chartのグラフも変化します。
この状態でNode-REDフローをエクスポートしたデータを以下に添付しておきます。
[{"id":"6a8b6204.b58e2c","type":"ibmiot in","z":"d29f2b73.bb856","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"3fbd1f674143","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IBM IoT","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","qos":0,"x":80.39999389648438,"y":79.16665649414062,"wires":[["49240739.1d131","73fb2c55.ccb794"]]},{"id":"49240739.1d131","type":"debug","z":"d29f2b73.bb856","name":"","active":false,"console":"false","complete":"false","x":347.40000915527344,"y":79.08332824707031,"wires":[]},{"id":"73fb2c55.ccb794","type":"change","z":"d29f2b73.bb856","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.d.temp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":152.40000915527344,"y":155,"wires":[["c836c360.a02448","af08c9f1.fe20a","77db9d47.f45634"]]},{"id":"c836c360.a02448","type":"ui_text","z":"d29f2b73.bb856","group":"f6e58351.6ed218","order":0,"width":0,"height":0,"name":"","label":"温度","format":"{{msg.payload}}","layout":"row-spread","x":365.40000915527344,"y":157.4499969482422,"wires":[]},{"id":"af08c9f1.fe20a","type":"ui_gauge","z":"d29f2b73.bb856","name":"","group":"f6e58351.6ed218","order":0,"width":0,"height":0,"gtype":"gage","title":"Gauge","label":"units","format":"{{value}}","min":0,"max":"40","colors":["#00b500","#e6e600","#ca3838"],"seg1":"30","seg2":"35","x":368.40000915527344,"y":213.34999084472656,"wires":[]},{"id":"77db9d47.f45634","type":"ui_chart","z":"d29f2b73.bb856","name":"","group":"f6e58351.6ed218","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"40","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":369.40000915527344,"y":284.84999084472656,"wires":[[],[]]},{"id":"f6e58351.6ed218","type":"ui_group","z":"","name":"温度","tab":"6a2033b6.8a0594","disp":true,"width":"6"},{"id":"6a2033b6.8a0594","type":"ui_tab","z":"","name":"IoT Sensor","icon":"dashboard"}]
5. 湿度データ、物体温度データもダッシュボードに表示する
まず湿度データをダッシュボードに追加します。
温度データの時と同様に、受信データを変換するchangeノード、ダッシュボード部品のtextノード、Gaugeノード、chartノードをパレットからキャンバスにドラッグ&ドロップします。
changeノードは、対象の値としてmsg.payload.d.humidityを指定します。
textノードは、Groupで「新規にui_groupを追加」を選択して鉛筆マークをクリックし、湿度グループを作成します。
グループ名が「湿度 [IoT Sensor]」に変わったことを確認し、Labelを「text」から「湿度」に変更して、「完了」をクリックしてキャンバスに戻ります。
Gaugeノードは、まずGroupを「湿度 [IoT Sensor]」に変更します。更にRangeをmin=0,max=100に、Sectorsを「0 ... 60 ... 70 ... 100」にセットし、他はデフォルトを受け入れて完了します。
chartノードも、まずGroupを「湿度 [IoT Sensor]」に変更します。更にY-axisをmin=0,max=100にセットし、他はデフォルトを受け入れて完了します。
キャンバスに戻ったら各ノードの端子間を接続してフローを作成し、デプロイします。
デプロイしたらダッシュボードの画面に切り替えます。湿度を表示するtext,Gauge,chartが追加されました。
同様に、物体温度データもダッシュボードに表示します。手順は省略しますが、以下にフローの最終型、ダッシュボードの最終型と、フローをエクスポートしたデータを添付しておきます。
[{"id":"6a8b6204.b58e2c","type":"ibmiot in","z":"d29f2b73.bb856","authentication":"quickstart","apiKey":"","inputType":"evt","deviceId":"3fbd1f674143","applicationId":"","deviceType":"+","eventType":"+","commandType":"","format":"json","name":"IBM IoT","service":"quickstart","allDevices":"","allApplications":"","allDeviceTypes":true,"allEvents":true,"allCommands":"","allFormats":"","qos":0,"x":80.39999389648438,"y":79.16665649414062,"wires":[["49240739.1d131","73fb2c55.ccb794","c156fe31.46178","6c2a1a1.f41d0e4"]]},{"id":"49240739.1d131","type":"debug","z":"d29f2b73.bb856","name":"","active":false,"console":"false","complete":"false","x":347.40000915527344,"y":79.08332824707031,"wires":[]},{"id":"73fb2c55.ccb794","type":"change","z":"d29f2b73.bb856","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.d.temp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":152.40000915527344,"y":155,"wires":[["c836c360.a02448","af08c9f1.fe20a","77db9d47.f45634"]]},{"id":"c836c360.a02448","type":"ui_text","z":"d29f2b73.bb856","group":"f6e58351.6ed218","order":0,"width":0,"height":0,"name":"","label":"温度","format":"{{msg.payload}}","layout":"row-spread","x":295.4000244140625,"y":133.4499969482422,"wires":[]},{"id":"af08c9f1.fe20a","type":"ui_gauge","z":"d29f2b73.bb856","name":"","group":"f6e58351.6ed218","order":0,"width":0,"height":0,"gtype":"gage","title":"Gauge","label":"units","format":"{{value}}","min":0,"max":"40","colors":["#00b500","#e6e600","#ca3838"],"seg1":"30","seg2":"35","x":414.4000244140625,"y":132.34999084472656,"wires":[]},{"id":"77db9d47.f45634","type":"ui_chart","z":"d29f2b73.bb856","name":"","group":"f6e58351.6ed218","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"40","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":416.4000244140625,"y":173.84996032714844,"wires":[[],[]]},{"id":"c156fe31.46178","type":"change","z":"d29f2b73.bb856","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.d.humidity","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":153.39999389648438,"y":266.5,"wires":[["a3b0a5bf.fe734","220ed27.acd08ae","e86c0636.15a898"]]},{"id":"a3b0a5bf.fe734","type":"ui_text","z":"d29f2b73.bb856","group":"57a9f7d1.3aff4","order":0,"width":0,"height":0,"name":"","label":"湿度","format":"{{msg.payload}}","layout":"row-spread","x":295.40000915527344,"y":241.24998474121094,"wires":[]},{"id":"220ed27.acd08ae","type":"ui_gauge","z":"d29f2b73.bb856","name":"","group":"57a9f7d1.3aff4","order":0,"width":0,"height":0,"gtype":"gage","title":"Gauge","label":"units","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"60","seg2":"70","x":420.40000915527344,"y":241.34999084472656,"wires":[]},{"id":"e86c0636.15a898","type":"ui_chart","z":"d29f2b73.bb856","name":"","group":"57a9f7d1.3aff4","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":423.40000915527344,"y":283.84999084472656,"wires":[[],[]]},{"id":"6c2a1a1.f41d0e4","type":"change","z":"d29f2b73.bb856","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.d.objectTemp","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":150.39999389648438,"y":367.9000244140625,"wires":[["704db5dd.4a2d0c","6034919a.ca5a08","6513ac91.98922c"]]},{"id":"704db5dd.4a2d0c","type":"ui_text","z":"d29f2b73.bb856","group":"7a8177b1.4e8528","order":0,"width":0,"height":0,"name":"","label":"物体温度","format":"{{msg.payload}}","layout":"row-spread","x":304.40000915527344,"y":339.24998474121094,"wires":[]},{"id":"6034919a.ca5a08","type":"ui_gauge","z":"d29f2b73.bb856","name":"","group":"7a8177b1.4e8528","order":0,"width":0,"height":0,"gtype":"gage","title":"Gauge","label":"units","format":"{{value}}","min":0,"max":"40","colors":["#00b500","#e6e600","#ca3838"],"seg1":"30","seg2":"35","x":434.4000244140625,"y":338.3499755859375,"wires":[]},{"id":"6513ac91.98922c","type":"ui_chart","z":"d29f2b73.bb856","name":"","group":"7a8177b1.4e8528","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"40","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":421.40000915527344,"y":381.84999084472656,"wires":[[],[]]},{"id":"f6e58351.6ed218","type":"ui_group","z":"","name":"温度","tab":"6a2033b6.8a0594","disp":true,"width":"6"},{"id":"57a9f7d1.3aff4","type":"ui_group","z":"","name":"湿度","tab":"6a2033b6.8a0594","disp":true,"width":"6"},{"id":"7a8177b1.4e8528","type":"ui_group","z":"","name":"物体温度","tab":"6a2033b6.8a0594","disp":true,"width":"6"},{"id":"6a2033b6.8a0594","type":"ui_tab","z":"","name":"IoT Sensor","icon":"dashboard"}]
以上です。
参照:https://github.com/jeancarl/node-red-labs/tree/master/lab-sense-hat/node-red-dashboard