LoginSignup
6
7

More than 5 years have passed since last update.

Watson IoT Platform - サンプルフロー - リアルタイムでIoTセンサーからの値を表示

Last updated at Posted at 2016-08-12

実際のIoTシステムでは、下記のフローの先頭にMQTTなどで接続されたIoTデバイス・センサーからの入力を接続します。
このサンプルのフローでは、IoTセンサーからの値をシミュレートし、websocketで出力した値をリアルタイムで可視化します。ccchartを使用しています。

サンプル1 センサーからのIoTデータをリアルタイムで表示する

IoTデータをリアルタイムで表示
[{"id":"48e2ea18.2d831c","type":"websocket-listener","z":"a9346054.4ad1b","path":"/ws/flow20","wholemsg":"false"},{"id":"db1d6d53.85c758","type":"function","z":"a9346054.4ad1b","name":"センサー値を出力","func":"if (msg.payload === 0 ) {\n    context.set(\"i\", 0);\n}\n\nvar i = context.get('i')||0;\ni += 1;\nvar time =[\"10:00\",\"10:01\",\"10:02\",\"10:03\",\"10:04\",\"10:05\",\"10:06\",\"10:07\",\"10:08\",\"10:09\",\"10:10\",\"10:11\",\"10:12\",\"10:13\",\"10:14\",\"10:15\",\"10:16\",\"10:17\",\"10:18\",\"10:19\",\"10:20\",\"10:21\",\"10:22\",\"10:23\",\"10:24\",\"10:25\",\"10:26\",\"10:27\",\"10:28\",\"10:29\",\"10:30\",\"10:31\",\"10:32\",\"10:33\",\"10:34\",\"10:35\",\"10:36\",\"10:37\",\"10:38\",\"10:39\",\"10:40\",\"10:41\",\"10:42\",\"10:43\",\"10:44\",\"10:45\",\"10:46\",\"10:47\",\"10:48\",\"10:49\",\"10:50\",\"10:51\",\"10:52\",\"10:53\",\"10:54\",\"10:55\",\"10:56\",\"10:57\",\"10:58\",\"10:59\"];\nvar sen1 = [2,8,4,6,0,10,8,4,2,6,10,6,4,8,0,2,10,8,2,8,4,6,10,2,0,8,4,6,10,8,4,0,6,2,8,10,6,4,2,0,6,8,2,0,6,10,6,4,8,10,4,2,6,8,4,0,2,8,10,8];\nvar sen2 = [12,10,4,6,14,8,20,12,8,4,0,12,18,6,4,10,6,2,18,14,12,4,0,8,14,16,20,12,8,4,0,12,14,10,8,4,18,12,14,10,4,2,6,12,18,14,10,2,8,4,12,18,10,4,2,0,6,18,20,12];\nvar sen3 = [1,5,3,7,9,7,5,3,7,9,3,1,5,7,3,7,9,1,7,5,3,9,3,1,7,5,9,3,1,7,3,5,9,3,1,7,5,3,1,7,9,3,7,1,5,7,3,7,9,5,3,1,7,9,5,3,3,1,7,9];\nvar sen4 = [7,11,17,3,7,11,1,9,17,13,17,11,3,9,11,3,7,15,13,19,11,7,5,1,13,17,15,5,7,3,11,7,19,13,15,11,9,3,5,9,17,13,11,9,13,15,7,3,5,1,13,17,7,19,3,5,9,1,7,3];\nvar sen5 = [8,2,10,14,8,16,8,12,4,0,12,12,18,14,6,10,4,8,12,14,20,4,14,16,10,12,8,6,2,8,0,10,12,8,4,16,18,12,8,4,2,8,0,12,20,16,12,18,20,8,12,14,8,4,8,16,2,8,14,8];\n\nif (i > time.length-1) return;\ncontext.set('i', i);\nvar data = [[time[i]],[sen1[i]],[sen2[i]],[sen3[i]],[sen4[i]],[sen5[i]]];\nmsg.payload=data;\nreturn msg;\n","outputs":1,"noerr":0,"x":310,"y":120,"wires":[["420ffd32.8c879c","2fdd8414.5770e4"]]},{"id":"9ac1d27b.b5dd7","type":"inject","z":"a9346054.4ad1b","name":"1秒毎","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":110,"y":100,"wires":[["db1d6d53.85c758"]]},{"id":"d9ec4e9.7c3203","type":"inject","z":"a9346054.4ad1b","name":"restart","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":110,"y":140,"wires":[["db1d6d53.85c758"]]},{"id":"2fdd8414.5770e4","type":"debug","z":"a9346054.4ad1b","name":"出力","active":true,"console":"false","complete":"payload","x":490,"y":100,"wires":[]},{"id":"8fb4da72.9d3278","type":"comment","z":"a9346054.4ad1b","name":"IoTセンサーからの値をシミュレート","info":"","x":200,"y":60,"wires":[]},{"id":"5afa1350.35c85c","type":"http in","z":"a9346054.4ad1b","name":"","url":"/test20","method":"get","swaggerDoc":"","x":130,"y":260,"wires":[["229a6875.3761c"]]},{"id":"229a6875.3761c","type":"template","z":"a9346054.4ad1b","name":"ws用htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n\t<head>\n\t\t<title>リアルタイムIoTデータ表示</title>\n\t\t<meta charset=\"utf-8\" />\n\t\t<script src=\"http://ccchart.com/js/ccchart.js\" charset=\"utf-8\"></script>\n<script>\n\nwindow.onload=function(){\n\tcc();\n}\n\nfunction cc() {\n\nvar chartdata87 = {\n\n  \"config\": {\n    \"title\": \"リアルタイムIoTデータ表示\",\n    \"subTitle\": \"IoTデータをリアルタイムで可視化します\",\n    \"type\": \"stackedarea\",\n    \"maxWsColLen\": 12,\n    \"colorSet\": \n          [\"#ffbf7f\",\"#7fff7f\",\"#ff7fff\",\"#7fbfff\",\"#ff7f7f\"],\n    \"useMarker\": \"arc\",\n    \"useVal\": \"yes\",\n    \"roundedUpMaxY\": 100\n  },\n\n  \"data\": [\n    [\"時刻\"],\n    [\"センサー1値\"],\n    [\"センサー2値\"],\n    [\"センサー3値\"],\n    [\"センサー4値\"],\n    [\"センサー5値\"]\n  ]\n};\n\n  ccchart.wsCloseAll();//一旦クリア\n  ccchart\n    .init('id123', chartdata87)\n\t.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow20')\n\t.on('message', myOneColAtATime)\n\t.on('message', ccchart.wscase.oneColAtATime);\n}\n\nfunction myOneColAtATime (msg) {\n\tconsole.log(\"myOneColAtATime entered\");\n\t// 一度に1列ずつ [[\"2013\"],[435],[600]] といった配列で届く場合\n    // e.g. ws.on('message', ccchart.wscase.oneColAtAtime)\n    var msgs = JSON.parse(msg.data);\n\t// 各センサー要素を取り出して、画面へ表示\n\tfor (var i = 0; i < msgs.length; i++) { console.log( i + \" = \" + msgs[i]); }\n\ttarget = document.getElementById(\"output1\");\n\ttarget.innerHTML = msgs[0];\n\ttarget = document.getElementById(\"output2\");\n\ttarget.innerHTML = msgs[1];\n\ttarget = document.getElementById(\"output3\");\n\ttarget.innerHTML = msgs[2];\n\ttarget = document.getElementById(\"output4\");\n\ttarget.innerHTML = msgs[3];\n\ttarget = document.getElementById(\"output5\");\n\ttarget.innerHTML = msgs[4];\n\ttarget = document.getElementById(\"output6\");\n\ttarget.innerHTML = msgs[5];\n\n}\n\n</script>\n\t</head>\n\t<body>\n\n<div id=\"a-box\" style=\"background-color: #87cefa; padding: 20px;\">\n\t<h1>リアルタイムIoTデータ表示</h1>\n\t<br />\n\t<p>\n\t\tIoTセンサーからデータをリアルタイムで可視化します<br />\n\t</p>\n</div>\n\n<div id=\"b-box\" style=\"background-color: #ecf2fe; padding: 20px; \">\n\t<canvas id=\"id123\"></canvas>\n\t\t<h2>時刻</h2>\n\t\t\t<div style=\"text-align:left\" id=\"output0\"></div>\n\t\t\t<div style=\"text-align:left;font-size: 18pt\" id=\"output1\"></div>\n\t\t<h2>センサー1 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output2\"></span>\n\t\t<h2>センサー2 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output3\"></span>\n\t\t<h2>センサー3\t</h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output4\"></span>\n\t\t<h2>センサー4\t</h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output6\"></span>\n\t\t<h2>センサー5\t</h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output5\"></span>\n\t\t<h2>積算\t</h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output8\"></span>\n\n\n</div>\n\n<div id=\"c-box\" style=\"background-color: #f0e8fa; padding: 20px; \">\n\t\t<ul>\n\t\t\t<li><a href=\"http://qiita.com/egplnt/items/af867711a7191923b2ff\">Watson IoT Platformを使ってみる</a></li>\n\t\t\t<li><a href=\"https://internetofthings.ibmcloud.com/#/\">Watson IoT Platform</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/tutorials/use-the-simulated-device-to-experience-the-iot-foundation/\">Recipe - Simulator</a></li>\n\t\t</ul>\n\t\t<div class=\"category\">資料ページ</div>\n\t\t<ul>\n\t\t\t<li><a href=\"http://ibm.com/iot\">IBM IoT</a></li>\n\t\t\t<li><a href=\"https://docs.internetofthings.ibmcloud.com/ja/\">Watson IoT Platform資料ページ</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/\">Recipe</a></li>\n\t\t</ul>\n\n\n\t\t\t\n<!---\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n--->\n\n</div>\n<div id=\"d-box\" style=\"clear: both; background-color: #e0ce96; font-size: 18px; padding: 10px; text-align: center;  padding: 20px;\">\n\tcopyright (c) abc.com All right reserved. \n</div>\n\n\t</body>\n</html>\n","x":320,"y":260,"wires":[["63381646.36ce4"]]},{"id":"63381646.36ce4","type":"http response","z":"a9346054.4ad1b","name":"","x":510,"y":260,"wires":[]},{"id":"420ffd32.8c879c","type":"websocket out","z":"a9346054.4ad1b","name":"websocket output","server":"48e2ea18.2d831c","client":"","x":530,"y":140,"wires":[]},{"id":"d7d552a3.6ba1e8","type":"comment","z":"a9346054.4ad1b","name":"リアルタイムIoTセンサー値表示","info":"","x":190,"y":220,"wires":[]}]

  1. Node-REDのフローをコピーする方法を参照して、上記のフローをコピペします。
  2. 上段のシミュレーターのフローを確認し、左上の「1秒毎」と表記されたInjectノードをダブルクリックで開いて適当なインターバルに設定し、ノード右側から線を引き出して後続のオレンジ色の「センサー値を出力」ノードに接続します。(この線は常時リクエストを送付してしまうので、テスト時以外は切断しておくことをお薦めします。)
  3. 下段の「リアルタイムIoTセンサー値表示」フローを確認し、オレンジ色の「ws用htmlを返す」のノードを開き、42行目の.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow20')のアプリ名部分を更新します。
  4. Node-RED画面右上の赤い「Deploy」ボタンを押してクラウド側へ反映します。
  5. ブラウザの新しいタブを開き、IoTアプリ名.bluemix.net/test20へアクセスすると下記のような画面が表示されます。
  6. 上段のシミュレーターのフローの「再起動」を押し、シミュレートされたセンサーデータがHTML画面に表示されるのを確認します。
  7. うまく表示されない場合、上段のIoTセンサー値を出力するフローのwebsocket出力ノードを一旦削除して、画面左側のパレットのoutputセクションからwebsocketノードをドラッグ&ドロップして作り直してみます。出力Pathは/we/flow20としてあります(html内の指定と整合すれば何でも構いません)。

スクリーンショット 2016-08-12 14.16.07.png

スクリーンショット 2016-08-12 13.32.26.png


サンプル2 積算値を表示するサンプル

IoTセンサーからの値を積算して表示
[{"id":"3df0391e.e83cb6","type":"websocket-listener","z":"1413dbbf.96edd4","path":"/ws/flow22","wholemsg":"false"},{"id":"b03e4b77.5aba6","type":"template","z":"1413dbbf.96edd4","name":"ws用htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n\t<head>\n\t\t<title>積算値IoTデータ表示</title>\n\t\t<meta charset=\"utf-8\" />\n\t\t<script src=\"http://ccchart.com/js/ccchart.js\" charset=\"utf-8\"></script>\n<script>\n\nwindow.onload=function(){\n\tcc();\n}\n\nfunction cc() {\n\nvar chartdata87 = {\n\n  \"config\": {\n    \"title\": \"積算値IoTデータ表示\",\n    \"subTitle\": \"IoTデータを積算して可視化します\",\n    \"type\": \"stackedarea\",\n    \"maxWsColLen\": 12,\n    \"colorSet\": \n          [\"#ffbf7f\",\"#7fff7f\",\"#ff7fff\",\"#7fbfff\",\"#ff7f7f\"],\n    \"useMarker\": \"arc\",\n    \"useVal\": \"yes\",\n    \"roundedUpMaxY\": 100\n  },\n\n  \"data\": [\n    [\"時刻\"],\n    [\"センサー1値\"],\n    [\"積算値\"]\n  ]\n};\n\n  ccchart.wsCloseAll();//一旦クリア\n  ccchart\n    .init('id123', chartdata87)\n\t.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow22')\n\t.on('message', myOneColAtATime)\n\t.on('message', ccchart.wscase.oneColAtATime);\n}\n\nfunction myOneColAtATime (msg) {\n\tconsole.log(\"myOneColAtATime entered\");\n\t// 一度に1列ずつ [[\"2013\"],[435],[600]] といった配列で届く場合\n    // e.g. ws.on('message', ccchart.wscase.oneColAtAtime)\n    var msgs = JSON.parse(msg.data);\n\t// 各センサー要素を取り出して、画面へ表示\n\tfor (var i = 0; i < msgs.length; i++) { console.log( i + \" = \" + msgs[i]); }\n\ttarget = document.getElementById(\"output1\");\n\ttarget.innerHTML = msgs[0];\n\ttarget = document.getElementById(\"output2\");\n\ttarget.innerHTML = msgs[1];\n\ttarget = document.getElementById(\"output3\");\n\ttarget.innerHTML = msgs[2];\n}\n\n</script>\n\t</head>\n\t<body>\n\n<div id=\"a-box\" style=\"background-color: #87cefa; padding: 20px;\">\n\t<h1>積算値IoTデータ表示</h1>\n\t<br />\n\t<p>\n\t\tIoTセンサーからデータを積算して可視化します<br />\n\t</p>\n</div>\n\n<div id=\"b-box\" style=\"background-color: #ecf2fe; padding: 20px; \">\n\t<canvas id=\"id123\"></canvas>\n\t\t<h2>時刻</h2>\n\t\t\t<div style=\"text-align:left\" id=\"output0\"></div>\n\t\t\t<div style=\"text-align:left;font-size: 18pt\" id=\"output1\"></div>\n\t\t<h2>センサー1 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output2\"></span>\n\t\t<h2>積算値 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output3\"></span>\n</div>\n\n<div id=\"c-box\" style=\"background-color: #f0e8fa; padding: 20px; \">\n\t\t<ul>\n\t\t\t<li><a href=\"http://qiita.com/egplnt/items/af867711a7191923b2ff\">Watson IoT Platformを使ってみる</a></li>\n\t\t\t<li><a href=\"https://internetofthings.ibmcloud.com/#/\">Watson IoT Platform</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/tutorials/use-the-simulated-device-to-experience-the-iot-foundation/\">Recipe - Simulator</a></li>\n\t\t</ul>\n\t\t<div class=\"category\">資料ページ</div>\n\t\t<ul>\n\t\t\t<li><a href=\"http://ibm.com/iot\">IBM IoT</a></li>\n\t\t\t<li><a href=\"https://docs.internetofthings.ibmcloud.com/ja/\">Watson IoT Platform資料ページ</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/\">Recipe</a></li>\n\t\t</ul>\n\n\n\t\t\t\n<!---\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n--->\n\n</div>\n<div id=\"d-box\" style=\"clear: both; background-color: #e0ce96; font-size: 18px; padding: 10px; text-align: center;  padding: 20px;\">\n\tcopyright (c) abc.com All right reserved. \n</div>\n\n\t</body>\n</html>\n","x":360,"y":280,"wires":[["bcf664db.750b"]]},{"id":"56042020.2b7b2","type":"function","z":"1413dbbf.96edd4","name":"センサー値を出力","func":"if (msg.payload === 0 ) {\n    context.set('total',0);\n    context.set(\"i\", 0);\n}\n\nvar i = context.get('i')||0;\ni += 1;\nvar time =[\"10:00\",\"10:01\",\"10:02\",\"10:03\",\"10:04\",\"10:05\",\"10:06\",\"10:07\",\"10:08\",\"10:09\",\"10:10\",\"10:11\",\"10:12\",\"10:13\",\"10:14\",\"10:15\",\"10:16\",\"10:17\",\"10:18\",\"10:19\",\"10:20\",\"10:21\",\"10:22\",\"10:23\",\"10:24\",\"10:25\",\"10:26\",\"10:27\",\"10:28\",\"10:29\",\"10:30\",\"10:31\",\"10:32\",\"10:33\",\"10:34\",\"10:35\",\"10:36\",\"10:37\",\"10:38\",\"10:39\",\"10:40\",\"10:41\",\"10:42\",\"10:43\",\"10:44\",\"10:45\",\"10:46\",\"10:47\",\"10:48\",\"10:49\",\"10:50\",\"10:51\",\"10:52\",\"10:53\",\"10:54\",\"10:55\",\"10:56\",\"10:57\",\"10:58\",\"10:59\"];\nvar sen1 = [2,8,4,6,0,10,8,4,2,6,10,6,4,8,0,2,10,8,2,8,4,6,10,2,0,8,4,6,10,8,4,0,6,2,8,10,6,4,2,0,6,8,2,0,6,10,6,4,8,10,4,2,6,8,4,0,2,8,10,8];\n\nif (i > time.length-1) return;\ncontext.set('i', i);\nvar total = context.get('total')||0;\ntotal += sen1[i];\ncontext.set('total', total);\nvar data = [[time[i]],[sen1[i]],[total]];\nmsg.payload=data;\nreturn msg;\n","outputs":1,"noerr":0,"x":350,"y":140,"wires":[["1fe22eb.a3ff551","63658ed5.e6482"]]},{"id":"db370290.0c588","type":"inject","z":"1413dbbf.96edd4","name":"1秒毎","topic":"","payload":"","payloadType":"date","repeat":"2","crontab":"","once":false,"x":150,"y":120,"wires":[[]]},{"id":"75be76f7.2d5158","type":"inject","z":"1413dbbf.96edd4","name":"restart","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":150,"y":160,"wires":[["56042020.2b7b2"]]},{"id":"63658ed5.e6482","type":"debug","z":"1413dbbf.96edd4","name":"出力","active":true,"console":"false","complete":"payload","x":530,"y":120,"wires":[]},{"id":"723e138a.c57bb4","type":"comment","z":"1413dbbf.96edd4","name":"IoTセンサーからの値をシミュレート","info":"","x":240,"y":80,"wires":[]},{"id":"653274ab.54234c","type":"http in","z":"1413dbbf.96edd4","name":"","url":"/test22","method":"get","swaggerDoc":"","x":170,"y":280,"wires":[["b03e4b77.5aba6"]]},{"id":"bcf664db.750b","type":"http response","z":"1413dbbf.96edd4","name":"","x":550,"y":280,"wires":[]},{"id":"1fe22eb.a3ff551","type":"websocket out","z":"1413dbbf.96edd4","name":"websocket output","server":"3df0391e.e83cb6","client":"","x":570,"y":160,"wires":[]},{"id":"d772f570.d1207","type":"comment","z":"1413dbbf.96edd4","name":"IoTセンサーからの値を積算して表示","info":"","x":240,"y":240,"wires":[]}]

  1. Node-REDのフローをコピーする方法を参照して、上記のフローをコピペします。
  2. 上段のシミュレーターのフローを確認し、左上の「1秒毎」と表記されたInjectノードをダブルクリックで開いて適当なインターバルに設定し、ノード右側から線を引き出して後続のオレンジ色の「センサー値を出力」ノードに接続します。(この線は常時リクエストを送付してしまうので、テスト時以外は切断しておくことをお薦めします。)
  3. 下段の「リアルタイムIoTセンサー値表示」フローを確認し、オレンジ色の「ws用htmlを返す」のノードを開き、39行目の.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow22')のアプリ名部分を更新します。
  4. Node-RED画面右上の赤い「Deploy」ボタンを押してクラウド側へ反映します。
  5. ブラウザの新しいタブを開き、IoTアプリ名.bluemix.net/test22へアクセスすると下記のような画面が表示されます。
  6. 上段のシミュレーターのフローの「再起動」を押し、シミュレートされたセンサーデータがHTML画面に表示されるのを確認します。
  7. うまく表示されない場合、上段のIoTセンサー値を出力するフローのwebsocket出力ノードを一旦削除して、画面左側のパレットのoutputセクションからwebsocketノードをドラッグ&ドロップして作り直してみます。出力Pathは/we/flow22としてあります(html内の指定と整合すれば何でも構いません)。

スクリーンショット 2016-08-12 14.37.43.png

スクリーンショット 2016-08-12 14.38.44.png


サンプル3 センサー値と直近10件の平均値を表示するサンプル

センサー値と直近10件の平均値を表示
[{"id":"68c5eaa7.793bec","type":"websocket-listener","z":"985cc25a.9014","path":"/ws/flow24","wholemsg":"false"},{"id":"eb8f68e9.a6598","type":"template","z":"985cc25a.9014","name":"ws用htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n\t<head>\n\t\t<title>センサー値と直近10件の平均値を表示</title>\n\t\t<meta charset=\"utf-8\" />\n\t\t<script src=\"http://ccchart.com/js/ccchart.js\" charset=\"utf-8\"></script>\n<script>\n\nwindow.onload=function(){\n\tcc();\n}\n\nfunction cc() {\n\nvar chartdata87 = {\n\n  \"config\": {\n    \"title\": \"センサー値と直近10件の平均値を表示\",\n    \"subTitle\": \"IoTセンサーからの値と直近10件の平均値を表示します\",\n    \"type\": \"stackedarea\",\n    \"maxWsColLen\": 12,\n    \"colorSet\": \n          [\"#ff7fff\",\"#7fffbf\",\"#ff7fff\",\"#7fbfff\",\"#ff7f7f\"],\n    \"useMarker\": \"arc\",\n    \"useVal\": \"yes\",\n    \"roundedUpMaxY\": 100\n  },\n\n  \"data\": [\n    [\"時刻\"],\n    [\"センサー1値\"],\n    [\"平均値\"]\n  ]\n};\n\n  ccchart.wsCloseAll();//一旦クリア\n  ccchart\n    .init('id123', chartdata87)\n\t.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow24')\n\t.on('message', myOneColAtATime)\n\t.on('message', ccchart.wscase.oneColAtATime);\n}\n\nfunction myOneColAtATime (msg) {\n\tconsole.log(\"myOneColAtATime entered\");\n\t// 一度に1列ずつ [[\"2013\"],[435],[600]] といった配列で届く場合\n    // e.g. ws.on('message', ccchart.wscase.oneColAtAtime)\n    var msgs = JSON.parse(msg.data);\n\t// 各センサー要素を取り出して、画面へ表示\n\tfor (var i = 0; i < msgs.length; i++) { console.log( i + \" = \" + msgs[i]); }\n\ttarget = document.getElementById(\"output1\");\n\ttarget.innerHTML = msgs[0];\n\ttarget = document.getElementById(\"output2\");\n\ttarget.innerHTML = msgs[1];\n\ttarget = document.getElementById(\"output3\");\n\ttarget.innerHTML = msgs[2];\n}\n\n</script>\n\t</head>\n\t<body>\n\n<div id=\"a-box\" style=\"background-color: #87cefa; padding: 20px;\">\n\t<h1>センサー値と直近10件の平均値を表示</h1>\n\t<br />\n\t<p>\n\t\tIoTセンサーからの値と直近10件の平均値を表示します<br />\n\t</p>\n</div>\n\n<div id=\"b-box\" style=\"background-color: #ecf2fe; padding: 20px; \">\n\t<canvas id=\"id123\"></canvas>\n\t\t<h2>時刻</h2>\n\t\t\t<div style=\"text-align:left\" id=\"output0\"></div>\n\t\t\t<div style=\"text-align:left;font-size: 18pt\" id=\"output1\"></div>\n\t\t<h2>センサー1 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output2\"></span>\n\t\t<h2>平均値 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output3\"></span>\n</div>\n\n<div id=\"c-box\" style=\"background-color: #f0e8fa; padding: 20px; \">\n\t\t<ul>\n\t\t\t<li><a href=\"http://qiita.com/egplnt/items/af867711a7191923b2ff\">Watson IoT Platformを使ってみる</a></li>\n\t\t\t<li><a href=\"https://internetofthings.ibmcloud.com/#/\">Watson IoT Platform</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/tutorials/use-the-simulated-device-to-experience-the-iot-foundation/\">Recipe - Simulator</a></li>\n\t\t</ul>\n\t\t<div class=\"category\">資料ページ</div>\n\t\t<ul>\n\t\t\t<li><a href=\"http://ibm.com/iot\">IBM IoT</a></li>\n\t\t\t<li><a href=\"https://docs.internetofthings.ibmcloud.com/ja/\">Watson IoT Platform資料ページ</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/\">Recipe</a></li>\n\t\t</ul>\n\n\n\t\t\t\n<!---\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n--->\n\n</div>\n<div id=\"d-box\" style=\"clear: both; background-color: #e0ce96; font-size: 18px; padding: 10px; text-align: center;  padding: 20px;\">\n\tcopyright (c) abc.com All right reserved. \n</div>\n\n\t</body>\n</html>\n","x":320,"y":280,"wires":[["7d36338b.49d68c"]]},{"id":"fee016c.b7d29e8","type":"function","z":"985cc25a.9014","name":"センサー値を出力","func":"if (msg.payload === 0 ) {\n    context.set(\"i\", 0);\n}\nif ( !context.array ) {\n    context.array = new Array (10);\n}\nvar sum = 0, average = 0;\n\nvar time =[\"10:00\",\"10:01\",\"10:02\",\"10:03\",\"10:04\",\"10:05\",\"10:06\",\"10:07\",\"10:08\",\"10:09\",\"10:10\",\"10:11\",\"10:12\",\"10:13\",\"10:14\",\"10:15\",\"10:16\",\"10:17\",\"10:18\",\"10:19\",\"10:20\",\"10:21\",\"10:22\",\"10:23\",\"10:24\",\"10:25\",\"10:26\",\"10:27\",\"10:28\",\"10:29\",\"10:30\",\"10:31\",\"10:32\",\"10:33\",\"10:34\",\"10:35\",\"10:36\",\"10:37\",\"10:38\",\"10:39\",\"10:40\",\"10:41\",\"10:42\",\"10:43\",\"10:44\",\"10:45\",\"10:46\",\"10:47\",\"10:48\",\"10:49\",\"10:50\",\"10:51\",\"10:52\",\"10:53\",\"10:54\",\"10:55\",\"10:56\",\"10:57\",\"10:58\",\"10:59\"];\nvar sen1 = [2,8,4,6,0,10,8,4,2,6,10,6,4,8,0,2,10,8,2,8,4,6,10,2,0,8,4,6,10,8,4,0,6,2,8,10,6,4,2,0,6,8,2,0,6,10,6,4,8,10,4,2,6,8,4,0,2,8,10,8];\n\nvar i = context.get('i')||0;\ni += 1;\nif (i > time.length-1) return;\ncontext.set('i', i);\n\nvar shifted = context.array.shift();\ncontext.array.push(sen1[i]);\n\nvar length = context.array.length;\n\nfor (k=0; k<length; k++) {\n        sum = sum + context.array[k];\n}\n\naverage = sum / length;\nvar data = [[time[i]],[sen1[i]],[average]];\nmsg.payload=data;\nreturn msg;\n","outputs":1,"noerr":0,"x":310,"y":140,"wires":[["e4f47cb2.6de238","fe4e3fb1.158d78"]]},{"id":"adb5d728.25e47","type":"inject","z":"985cc25a.9014","name":"1秒毎","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":110,"y":120,"wires":[[]]},{"id":"d6cf08c7.c7249","type":"inject","z":"985cc25a.9014","name":"restart","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":110,"y":160,"wires":[["fee016c.b7d29e8"]]},{"id":"fe4e3fb1.158d78","type":"debug","z":"985cc25a.9014","name":"出力","active":true,"console":"false","complete":"payload","x":490,"y":120,"wires":[]},{"id":"cd5d6cc2.d31e7","type":"comment","z":"985cc25a.9014","name":"IoTセンサーからの値をシミュレート","info":"","x":200,"y":80,"wires":[]},{"id":"a8c5dde3.129678","type":"http in","z":"985cc25a.9014","name":"","url":"/test24","method":"get","swaggerDoc":"","x":130,"y":280,"wires":[["eb8f68e9.a6598"]]},{"id":"7d36338b.49d68c","type":"http response","z":"985cc25a.9014","name":"","x":510,"y":280,"wires":[]},{"id":"e4f47cb2.6de238","type":"websocket out","z":"985cc25a.9014","name":"websocket output","server":"68c5eaa7.793bec","client":"","x":530,"y":160,"wires":[]},{"id":"e2ee57c.4c2db28","type":"comment","z":"985cc25a.9014","name":"IoTセンサーからの値と直近10件の平均値を表示","info":"","x":250,"y":240,"wires":[]}]

  1. Node-REDのフローをコピーする方法を参照して、上記のフローをコピペします。
  2. 上段のシミュレーターのフローを確認し、左上の「1秒毎」と表記されたInjectノードをダブルクリックで開いて適当なインターバルに設定し、ノード右側から線を引き出して後続のオレンジ色の「センサー値を出力」ノードに接続します。(この線は常時リクエストを送付してしまうので、テスト時以外は切断しておくことをお薦めします。)
  3. 下段の「リアルタイムIoTセンサー値表示」フローを確認し、オレンジ色の「ws用htmlを返す」のノードを開き、39行目の.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow24')のアプリ名部分を更新します。
  4. Node-RED画面右上の赤い「Deploy」ボタンを押してクラウド側へ反映します。
  5. ブラウザの新しいタブを開き、IoTアプリ名.bluemix.net/test24へアクセスすると下記のような画面が表示されます。
  6. 上段のシミュレーターのフローの「再起動」を押し、シミュレートされたセンサーデータがHTML画面に表示されるのを確認します。
  7. うまく表示されない場合、上段のIoTセンサー値を出力するフローのwebsocket出力ノードを一旦削除して、画面左側のパレットのoutputセクションからwebsocketノードをドラッグ&ドロップして作り直してみます。出力Pathは/we/flow24としてあります(html内の指定と整合すれば何でも構いません)。
  8. 必要に応じ、 「センサー値を出力」ノード内の5行目のcontext.array = new Array (10);の配列(Array)の要素数を増減して直近の平均値を算出する対象のエントリー数を調整します。
  9. 参考:Watson IoT Platform - Node-RED - 直近10件の平均や標準偏差を求める

スクリーンショット 2016-08-12 15.24.42.png

スクリーンショット 2016-08-12 15.24.59.png


サンプル4 指定した間隔でセンサー値と直近10件の平均値を表示するサンプル

センサー値と直近10件の平均値を表示
[{"id":"70e4d0da.5629b","type":"websocket-listener","z":"9caf5f2d.ee644","path":"/ws/flow26","wholemsg":"false"},{"id":"7b5b76f2.ebdbd8","type":"function","z":"9caf5f2d.ee644","name":"センサー値を出力","func":"//var sampling_min_interval = 1;\nvar sampling_sec_interval = 60;     // データを出力する間隔\n\nvar sum = 0, average = 0;\nvar sen1 = Math.floor(Math.random () * 10) + 1; // センサー値を生成(シミュレート)\n\nif ( !context.array ) {\n    context.array = new Array (10); //直近10件分を保持\n}\nvar shifted = context.array.shift();\ncontext.array.push(sen1);           // 最新の値を保存\nvar length = context.array.length;\n\nfor (k=0; k<length; k++) {\n        sum = sum + context.array[k];   // 合計を算出\n}\n\nvar hour = JSON.stringify(msg.date.hour);\nvar min_org  = JSON.stringify(msg.date.minute);\nvar min = ( \"0\" + min_org ).substr( -2 );       // 一桁分の場合、二桁に\nvar sec_org  = JSON.stringify(msg.date.second);\nvar sec = ( \"0\" + sec_org ).substr( -2 );       // 一桁秒の場合、二桁に\nvar time = hour + \":\" + min + \":\" + sec;\n\naverage = sum / length;\nvar data = [[time],[sen1],[average]];\nmsg.payload = data;\nif ( ( msg.date.second % sampling_sec_interval ) !== 0 ) return;\n//if ( ( msg.date.minute % sampling_min_interval ) !== 0 ) return;\nreturn msg;\n","outputs":1,"noerr":0,"x":470,"y":160,"wires":[["88545406.3f6818","2c25b12a.092b4e","35aab970.8f3be6"]]},{"id":"a7ab6090.c965a","type":"template","z":"9caf5f2d.ee644","name":"ws用htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n\t<head>\n\t\t<title>指定した間隔でセンサー値と直近10件の平均値を表示</title>\n\t\t<meta charset=\"utf-8\" />\n\t\t<script src=\"http://ccchart.com/js/ccchart.js\" charset=\"utf-8\"></script>\n<script>\n\nwindow.onload=function(){\n\tcc();\n}\n\nfunction cc() {\n\nvar chartdata87 = {\n\n  \"config\": {\n    \"title\": \"センサー値と直近平均値をインターバル表示\",\n    \"subTitle\": \"指定した間隔でIoTセンサーからの値と直近10件の平均値を表示します\",\n    \"type\": \"stackedarea\",\n    \"maxWsColLen\": 12,\n    \"colorSet\": \n          [\"#bf7fff\",\"#ffbf7f\",\"#ff7fff\",\"#7fbfff\",\"#ff7f7f\"],\n    \"useMarker\": \"arc\",\n    \"useVal\": \"yes\",\n\t\"autoReConnect\": \"yes\",\n\t\"autoReConnectInterval\": 500,\n\t\"wsReCnt\": 5000,\n    \"roundedUpMaxY\": 100\n  },\n\n  \"data\": [\n    [\"時刻\"],\n    [\"センサー1値\"],\n    [\"平均値\"]\n  ]\n};\n\n  ccchart.wsCloseAll();//一旦クリア\n  ccchart\n    .init('id123', chartdata87)\n\t.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow26', autoReConnectInterval = 5000)\n\t.on('message', myOneColAtATime)\n\t.on('message', ccchart.wscase.oneColAtATime);\n}\n\nfunction myOneColAtATime (msg) {\n\tconsole.log(\"myOneColAtATime entered\");\n\t// 一度に1列ずつ [[\"2013\"],[435],[600]] といった配列で届く場合\n    // e.g. ws.on('message', ccchart.wscase.oneColAtAtime)\n    var msgs = JSON.parse(msg.data);\n\t// 各センサー要素を取り出して、画面へ表示\n\tfor (var i = 0; i < msgs.length; i++) { console.log( i + \" = \" + msgs[i]); }\n\ttarget = document.getElementById(\"output1\");\n\ttarget.innerHTML = msgs[0];\n\ttarget = document.getElementById(\"output2\");\n\ttarget.innerHTML = msgs[1];\n\ttarget = document.getElementById(\"output3\");\n\ttarget.innerHTML = msgs[2];\n}\n\n</script>\n\t</head>\n\t<body>\n\n<div id=\"a-box\" style=\"background-color: #87cefa; padding: 20px;\">\n\t<h1>指定した間隔でセンサー値と直近10件の平均値を表示</h1>\n\t<br />\n\t<p>\n\t\t指定した間隔でIoTセンサーからの値と直近10件の平均値を表示します<br />\n\t</p>\n</div>\n\n<div id=\"b-box\" style=\"background-color: #ecf2fe; padding: 20px; \">\n\t<canvas id=\"id123\"></canvas>\n\t\t<h2>時刻</h2>\n\t\t\t<div style=\"text-align:left\" id=\"output0\"></div>\n\t\t\t<div style=\"text-align:left;font-size: 18pt\" id=\"output1\"></div>\n\t\t<h2>センサー1 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output2\"></span>\n\t\t<h2>直近10件の平均値 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output3\"></span>\n</div>\n\n<div id=\"c-box\" style=\"background-color: #f0e8fa; padding: 20px; \">\n\t\t<ul>\n\t\t\t<li><a href=\"http://qiita.com/egplnt/items/af867711a7191923b2ff\">Watson IoT Platformを使ってみる</a></li>\n\t\t\t<li><a href=\"https://internetofthings.ibmcloud.com/#/\">Watson IoT Platform</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/tutorials/use-the-simulated-device-to-experience-the-iot-foundation/\">Recipe - Simulator</a></li>\n\t\t</ul>\n\t\t<div class=\"category\">資料ページ</div>\n\t\t<ul>\n\t\t\t<li><a href=\"http://ibm.com/iot\">IBM IoT</a></li>\n\t\t\t<li><a href=\"https://docs.internetofthings.ibmcloud.com/ja/\">Watson IoT Platform資料ページ</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/\">Recipe</a></li>\n\t\t</ul>\n\n\n\t\t\t\n<!---\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n--->\n\n</div>\n<div id=\"d-box\" style=\"clear: both; background-color: #e0ce96; font-size: 18px; padding: 10px; text-align: center;  padding: 20px;\">\n\tcopyright (c) abc.com All right reserved. \n</div>\n\n\t</body>\n</html>\n","x":320,"y":300,"wires":[["30f8039c.a85bd4"]]},{"id":"a34bbc54.711aa8","type":"inject","z":"9caf5f2d.ee644","name":"1秒毎","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":110,"y":140,"wires":[["cef961b7.c12238"]]},{"id":"35276ce4.1d332c","type":"inject","z":"9caf5f2d.ee644","name":"restart","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":110,"y":180,"wires":[["cef961b7.c12238"]]},{"id":"88545406.3f6818","type":"debug","z":"9caf5f2d.ee644","name":"出力","active":true,"console":"false","complete":"payload","x":650,"y":140,"wires":[]},{"id":"e4b92c19.4c359","type":"comment","z":"9caf5f2d.ee644","name":"IoTセンサーからの値をシミュレート","info":"","x":200,"y":100,"wires":[]},{"id":"62aeaebe.acc14","type":"http in","z":"9caf5f2d.ee644","name":"","url":"/test26","method":"get","swaggerDoc":"","x":130,"y":300,"wires":[["a7ab6090.c965a"]]},{"id":"30f8039c.a85bd4","type":"http response","z":"9caf5f2d.ee644","name":"","x":510,"y":300,"wires":[]},{"id":"3265f51e.f1e4e2","type":"comment","z":"9caf5f2d.ee644","name":"指定されたインターバルでIoTセンサーからの値と直近10件の平均値を表示","info":"","x":330,"y":260,"wires":[]},{"id":"cef961b7.c12238","type":"function","z":"9caf5f2d.ee644","name":"日付時刻の追加","func":"var d = new Date();\nvar localTime = d.getTime();\nvar localOffset = d.getTimezoneOffset() * 60000;\nvar utc = localTime + localOffset;\nvar offset = -9.0;\nvar result = utc - (3600000 * offset);\nvar date = parseInt(new Date(result) / 1000);\nvar dt = new Date(result);\n\nvar year = dt.getFullYear();\nvar month = dt.getMonth()+1;\nvar day = dt.getDate();\nvar hour = dt.getHours();\nvar minute = dt.getMinutes();\nvar second = dt.getSeconds();\n//if (!msg.payload) {\n//    msg.payload = { \"initial\": \"value\" };\n//}\nif (!msg.date) {\n    msg.date = { \"initial\": \"value\" };\n}\nmsg.date = {\n        \"date\": date,\n        \"year\": year,\n        \"month\": month,\n        \"day\": day,\n        \"hour\": hour,\n        \"minute\": minute,\n        \"second\": second\n};\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":160,"wires":[["7b5b76f2.ebdbd8","2c25b12a.092b4e"]]},{"id":"2c25b12a.092b4e","type":"debug","z":"9caf5f2d.ee644","name":"時刻の表示","active":false,"console":"false","complete":"date","x":670,"y":100,"wires":[]},{"id":"35aab970.8f3be6","type":"websocket out","z":"9caf5f2d.ee644","name":"","server":"70e4d0da.5629b","client":"","x":670,"y":200,"wires":[]}]

  1. センサーから1秒毎など頻繁に送付されてくるデータを全部画面に表示すると画面が見にくくなって大変なので、飛来したデータを内部で配列に保持して直近の平均値などの算出は続けておいて、指定した時間インターバルが経過したらその時飛来したセンサー値とその直前までの平均値を表示する、というサンプルです。
  2. Node-REDのフローをコピーする方法を参照して、上記のフローをコピペします。
  3. 上段のシミュレーターのフローを確認し、左上の「1秒毎」と表記されたInjectノードをダブルクリックで開いて適当なインターバルに設定し、ノード右側から線を引き出して後続のオレンジ色の「センサー値を出力」ノードに接続します。(この線は常時リクエストを送付してしまうので、テスト時以外は切断しておくことをお薦めします。)
  4. 下段の「リアルタイムIoTセンサー値表示」フローを確認し、オレンジ色の「ws用htmlを返す」のノードを開き、39行目の.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow26')のアプリ名部分を更新します。
  5. Node-RED画面右上の赤い「Deploy」ボタンを押してクラウド側へ反映します。
  6. ブラウザの新しいタブを開き、IoTアプリ名.bluemix.net/test26へアクセスすると下記のような画面が表示されます。
  7. 上段のシミュレーターのフローの「再起動」を押し、シミュレートされたセンサーデータがHTML画面に表示されるのを確認します。
  8. うまく表示されない場合、上段のIoTセンサー値を出力するフローのwebsocket出力ノードを一旦削除して、画面左側のパレットのoutputセクションからwebsocketノードをドラッグ&ドロップして作り直してみます。出力Pathは/we/flow26としてあります(html内の指定と整合すれば何でも構いません)。
  9. 必要に応じ、 「センサー値を出力」ノード内の1行目のvar sampling_interval = 60;のサンプリング間隔秒数を変更します。また5行目のcontext.array = new Array (10);の配列(Array)の要素数を増減して直近の平均値を算出する対象のエントリー数を調整します。
  10. 参考:Watson IoT Platform - Node-RED - 直近10件の平均や標準偏差を求めるWatson IoT Platform - Node-RED - 日付・時刻の追加

スクリーンショット 2016-08-12 16.05.55.png

スクリーンショット 2016-08-12 16.06.10.png

  • クライアントのサンプルです。Injectノードの代わりにIBM IoTインプットノードを使用し、Device ID欄に0123456789abを指定して接続します。
pubTemp.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

import logging
import os
import os.path
import sys
import codecs
import time
import paho.mqtt.client as mqtt
import json
import threading
import random

MQTT_BROKER="quickstart.messaging.internetofthings.ibmcloud.com"

MQTT_PORT=1883
MQTT_TIMEOUT=60

MQTT_PUB_TOPIC="iot-2/evt/status/fmt/json"

def on_connect(client, userdata, flags, rc):
    print("on connect")
    #client.subscribe(MQTT_SUB_TOPIC)
    #client.subscribe(MQTT_SUB_TOPIC + "#") 

def on_disconnect(client, userdata, rc):
    print("on disconnect")
    client.unsubscribe(MQTT_SUB_TOPIC)

def on_message(client, userdata, msg):
    print("on message: " + msg.topic + " " + str(msg.payload))

def mqttConnect():
    print("mqttConnect")
    try:
        global client
        client = mqtt.Client("d:quickstart:myThing:0123456789ab")
        client.on_connect = on_connect
        client.on_message = on_message
        client.on_disconnect = on_disconnect
        client.connect(MQTT_BROKER,MQTT_PORT,MQTT_TIMEOUT)
        print("connected")
    except KeyboardInterrupt, kex:
        sys.exit()
    except Exception, ex:
        print("mqttConnect error")

def mqttPublishCycle():
    while client.loop() == 0:
        try:
            temp = 10 + random.randrange(250,450)/100.0
            humid = 40 + random.randrange(500,1000)/100.0
            print "temp = " + str(temp) + ", humid = " + str(humid) 
            msg = " {\"d\": {\"Temperature\": " + str(temp) +",\"Humidity\": " + str(humid) + "} }";
            client.publish(MQTT_PUB_TOPIC, msg, 0, True)
            time.sleep(2)
        except Exception, ex:
            print("mqttPublish error")


def testHello():
    print "hello"

if __name__ == "__main__":
    print("--- started ---")
    mqttConnect()
    mqttPublishCycle()
    testHello()

    print("--- program ended ---")



サンプル5 指定した間隔でセンサー値と直近10件の平均値と標準偏差を表示するサンプル

センサー値と直近10件の平均値と標準偏差を表示
[{"id":"a7d8276f.0b198","type":"template","z":"b82d7fcb.a73958","name":"ws用htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n\t<head>\n\t\t<title>センサー値と直近10件の平均値、標準偏差を表示</title>\n\t\t<meta charset=\"utf-8\" />\n\t\t<script src=\"http://ccchart.com/js/ccchart.js\" charset=\"utf-8\"></script>\n<script>\n\nwindow.onload=function(){\n\tcc();\n}\n\nfunction cc() {\n\nvar chartdata87 = {\n\n  \"config\": {\n    \"title\": \"センサー値と直近平均値、標準偏差を表示\",\n    \"subTitle\": \"IoTセンサーからの値と直近10件の平均値、標準偏差を表示します\",\n    \"type\": \"stackedarea\",\n    \"maxWsColLen\": 8,\n    \"colorSet\": \n          [\"#bf7fff\",\"#ffbf7f\",\"#ff7fff\",\"#7fbfff\",\"#ff7f7f\"],\n    \"useMarker\": \"arc\",\n    \"useVal\": \"yes\",\n\t\"autoReConnect\": \"yes\",\n\t\"autoReConnectInterval\": 500,\n\t\"wsReCnt\": 5000,\n    \"roundedUpMaxY\": 100\n  },\n\n  \"data\": [\n    [\"時刻\"],\n    [\"センサー1値\"],\n    [\"直近10件の平均値\"],\n    [\"標準偏差\"],\n  ]\n};\n\n  ccchart.wsCloseAll();//一旦クリア\n  ccchart\n    .init('id123', chartdata87)\n\t.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow40', autoReConnectInterval = 5000)\n\t.on('message', myOneColAtATime)\n\t.on('message', ccchart.wscase.oneColAtATime);\n}\n\nfunction myOneColAtATime (msg) {\n\tconsole.log(\"myOneColAtATime entered\");\n\t// 一度に1列ずつ [[\"2013\"],[435],[600]] といった配列で届く場合\n    // e.g. ws.on('message', ccchart.wscase.oneColAtAtime)\n    var msgs = JSON.parse(msg.data);\n\t// 各センサー要素を取り出して、画面へ表示\n\tfor (var i = 0; i < msgs.length; i++) { console.log( i + \" = \" + msgs[i]); }\n\ttarget = document.getElementById(\"output1\");\n\ttarget.innerHTML = msgs[0];\n\ttarget = document.getElementById(\"output2\");\n\ttarget.innerHTML = msgs[1];\n\ttarget = document.getElementById(\"output3\");\n\ttarget.innerHTML = msgs[2];\n\ttarget = document.getElementById(\"output4\");\n\ttarget.innerHTML = msgs[3];\n}\n\n</script>\n\t</head>\n\t<body>\n\n<div id=\"a-box\" style=\"background-color: #87cefa; padding: 20px;\">\n\t<h1>センサー値と直近10件の平均値、標準偏差を表示</h1>\n\t<br />\n\t<p>\n\t\tIoTセンサーからの値と直近10件の平均値、標準偏差を表示します<br />\n\t</p>\n</div>\n\n<div id=\"b-box\" style=\"background-color: #ecf2fe; padding: 20px; \">\n\t<canvas id=\"id123\"></canvas>\n\t\t<h2>時刻</h2>\n\t\t\t<div style=\"text-align:left\" id=\"output0\"></div>\n\t\t\t<div style=\"text-align:left;font-size: 18pt\" id=\"output1\"></div>\n\t\t<h2>センサー1 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output2\"></span>\n\t\t<h2>直近10件の平均値 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output3\"></span>\n\t\t<h2>直近10件の標準偏差 </h2>\n\t\t\t<span style=\"text-align:left;font-size: 18pt\" id=\"output4\"></span>\n</div>\n\n<div id=\"c-box\" style=\"background-color: #f0e8fa; padding: 20px; \">\n\t\t<ul>\n\t\t\t<li><a href=\"http://qiita.com/egplnt/items/af867711a7191923b2ff\">Watson IoT Platformを使ってみる</a></li>\n\t\t\t<li><a href=\"https://internetofthings.ibmcloud.com/#/\">Watson IoT Platform</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/tutorials/use-the-simulated-device-to-experience-the-iot-foundation/\">Recipe - Simulator</a></li>\n\t\t</ul>\n\t\t<div class=\"category\">資料ページ</div>\n\t\t<ul>\n\t\t\t<li><a href=\"http://ibm.com/iot\">IBM IoT</a></li>\n\t\t\t<li><a href=\"https://docs.internetofthings.ibmcloud.com/ja/\">Watson IoT Platform資料ページ</a></li>\n\t\t\t<li><a href=\"https://developer.ibm.com/recipes/\">Recipe</a></li>\n\t\t</ul>\n\n\n\t\t\t\n<!---\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n\t\t<h3>h3 見出し</h3>\n\t\t<p>テキスト (省略)</p>\n--->\n\n</div>\n<div id=\"d-box\" style=\"clear: both; background-color: #e0ce96; font-size: 18px; padding: 10px; text-align: center;  padding: 20px;\">\n\tcopyright (c) abc.com All right reserved. \n</div>\n\n\t</body>\n</html>\n","x":300,"y":480,"wires":[["1e84eada.9e7035"]]},{"id":"46e3c36c.9fbc64","type":"inject","z":"b82d7fcb.a73958","name":"1秒毎","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":110,"y":260,"wires":[[]]},{"id":"56226a7b.5927bc","type":"inject","z":"b82d7fcb.a73958","name":"restart","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"x":110,"y":300,"wires":[["be56004d.1f1c78"]]},{"id":"696338dd.cff878","type":"http in","z":"b82d7fcb.a73958","name":"","url":"/test40","method":"get","swaggerDoc":"","x":110,"y":480,"wires":[["a7d8276f.0b198"]]},{"id":"1e84eada.9e7035","type":"http response","z":"b82d7fcb.a73958","name":"","x":490,"y":480,"wires":[]},{"id":"26a0b136.cc6476","type":"comment","z":"b82d7fcb.a73958","name":"可視化","info":"","x":90,"y":440,"wires":[]},{"id":"be56004d.1f1c78","type":"function","z":"b82d7fcb.a73958","name":"配列に格納","func":"/*if (msg.payload.d.ambientLight ) {\n    msg.sen1 = Math.round(msg.payload.d.ambientLight*100)/100; // Alpsセンサーから温度を取得\n} else {\n    return 0;\n}\n*/\nmsg.sen1 = Math.floor(Math.random () * 10) + 1; // センサー値を生成(シミュレート)\n\nif ( !context.global.array ) {\n    context.global.array = new Array (10);\n}\nvar shifted = context.global.array.shift();\n\ncontext.global.array.push(msg.sen1);\n\nmsg.array = context.global.array;\nmsg.length = context.global.array.length;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":280,"wires":[["cc3d1348.dc0758"]]},{"id":"cc3d1348.dc0758","type":"function","z":"b82d7fcb.a73958","name":"平均","func":"var sum = 0, average = 0;\n    for (i=0; i<msg.length; i++) {\n        sum = sum + msg.array[i];\n}\nmsg.sum = sum;\naverage = sum / msg.length;\nmsg.average = Math.round(average*100)/100;\nreturn msg;\n","outputs":1,"noerr":0,"x":430,"y":280,"wires":[["a6b18687.ca6d5","5563095.e6dc878"]]},{"id":"a6b18687.ca6d5","type":"debug","z":"b82d7fcb.a73958","name":"","active":false,"console":"false","complete":"average","x":550,"y":240,"wires":[]},{"id":"5563095.e6dc878","type":"function","z":"b82d7fcb.a73958","name":"分散","func":"var variance = 0;\nfor (i=0; i<msg.length; i++) {\n    variance = variance + Math.pow(msg.array[i] - msg.average, 2);\n}\nvariance = variance / msg.length;\nmsg.variance = Math.round(variance*100)/100;\nreturn msg;\n","outputs":1,"noerr":0,"x":570,"y":280,"wires":[["2a869a6a.73e3a6"]]},{"id":"2a869a6a.73e3a6","type":"function","z":"b82d7fcb.a73958","name":"標準偏差","func":"var standard_deviation = 0;\nstandard_deviation = Math.sqrt(msg.variance);\nmsg.std = Math.round(standard_deviation*100)/100;\nreturn msg;","outputs":1,"noerr":0,"x":260,"y":340,"wires":[["5043c9ff.86b608","ef01efdc.e4535"]]},{"id":"5043c9ff.86b608","type":"debug","z":"b82d7fcb.a73958","name":"","active":false,"console":"false","complete":"std","x":440,"y":380,"wires":[]},{"id":"ef01efdc.e4535","type":"function","z":"b82d7fcb.a73958","name":"時刻を設定","func":"var d = new Date();\nvar localTime = d.getTime();\nvar localOffset = d.getTimezoneOffset() * 60000;\nvar utc = localTime + localOffset;\nvar offset = -9.0;\nvar result = utc - (3600000 * offset);\nvar date = parseInt(new Date(result) / 1000);\nvar dt = new Date(result);\n\nvar year = dt.getFullYear();\nvar month = dt.getMonth()+1;\nvar day = dt.getDate();\nvar hour = dt.getHours();\nvar minute = dt.getMinutes();\nvar second = dt.getSeconds();\n//if (!msg.payload) {\n//    msg.payload = { \"initial\": \"value\" };\n//}\nif (!msg.date) {\n    msg.date = { \"initial\": \"value\" };\n}\nmsg.date = {\n        \"date\": date,\n        \"year\": year,\n        \"month\": month,\n        \"day\": day,\n        \"hour\": hour,\n        \"minute\": minute,\n        \"second\": second\n};\n\nvar hour = JSON.stringify(msg.date.hour);\nvar min_org  = JSON.stringify(msg.date.minute);\nvar min = ( \"0\" + min_org ).substr( -2 );       // 一桁分の場合、二桁に\nvar sec_org  = JSON.stringify(msg.date.second);\nvar sec = ( \"0\" + sec_org ).substr( -2 );       // 一桁秒の場合、二桁に\nvar time = hour + \":\" + min + \":\" + sec;\n\n//average = sum / length;\nvar data = [[time],[msg.sen1],[msg.average],[msg.std]];\nmsg.payload = data;\nreturn msg;\n","outputs":1,"noerr":0,"x":450,"y":340,"wires":[["9f156ff1.f937b","c63f01cc.a45b4"]]},{"id":"9f156ff1.f937b","type":"debug","z":"b82d7fcb.a73958","name":"","active":true,"console":"false","complete":"false","x":630,"y":320,"wires":[]},{"id":"c63f01cc.a45b4","type":"websocket out","z":"b82d7fcb.a73958","name":"","server":"aad83d48.43cde8","client":"","x":670,"y":380,"wires":[]},{"id":"cb8e5723.18e778","type":"comment","z":"b82d7fcb.a73958","name":"IoTセンサーからの値と直近10件の平均値、標準偏差を出力","info":"","x":260,"y":200,"wires":[]},{"id":"aad83d48.43cde8","type":"websocket-listener","z":"b82d7fcb.a73958","path":"/ws/flow40","wholemsg":"false"}]

  1. 前項のサンプル4に加えて標準偏差も出力するサンプルです。
  2. Node-REDのフローをコピーする方法を参照して、上記のフローをコピペします。
  3. 上段のシミュレーターのフローを確認し、左上の「1秒毎」と表記されたInjectノードをダブルクリックで開いて適当なインターバルに設定し、ノード右側から線を引き出して後続のオレンジ色の「センサー値を出力」ノードに接続します。(この線は常時リクエストを送付してしまうので、テスト時以外は切断しておくことをお薦めします。)
  4. 下段の「リアルタイムIoTセンサー値表示」フローを確認し、オレンジ色の「ws用htmlを返す」のノードを開き、43行目の.ws('ws://このIoTアプリの名前.mybluemix.net/ws/flow40')のアプリ名部分を更新します。
  5. Node-RED画面右上の赤い「Deploy」ボタンを押してクラウド側へ反映します。
  6. ブラウザの新しいタブを開き、IoTアプリ名.bluemix.net/test40へアクセスすると下記のような画面が表示されます。
  7. 上段のシミュレーターのフローの「再起動」を押し、シミュレートされたセンサーデータがHTML画面に表示されるのを確認します。
  8. うまく表示されない場合、上段のIoTセンサー値を出力するフローのwebsocket出力ノードを一旦削除して、画面左側のパレットのoutputセクションからwebsocketノードをドラッグ&ドロップして作り直してみます。出力Pathは/we/flow40としてあります(html内の指定と整合すれば何でも構いません)。
  9. 必要に応じ、 「センサー値を出力」ノード内の1行目のvar sampling_interval = 60;のサンプリング間隔秒数を変更します。また5行目のcontext.array = new Array (10);の配列(Array)の要素数を増減して直近の平均値を算出する対象のエントリー数を調整します。

スクリーンショット 2016-10-16 16.18.51.png

スクリーンショット 2016-10-16 16.25.06.png

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7