さくらIoT x node-RED on Bluemix で会議室の空き状況を表示させるまでの3日間(1日目)

  • 3
    いいね
  • 0
    コメント

さくらのIoT PlatformとIBM Bluemix上のnode-REDを接続してみた記録を、半分日記形式で記載しています。
1日目 では、IBM BluemixにNode-REDを導入し、(シミュレータを作って)WebSocketでデータを受信して、Ambientというグラフ表示サービスにデータを連携するところまで進みました。
2日目では、受信したデータを No-SQL DBにとりあえず保存するのと、Webサイトを作るところまで行きました。
2.5日目で、IoT Platformが届いたので、Arduinoを実際に接続してみました。
3日目では、保存したデータを読める形にして、利用率を計算するところまで行きました。
すごく長くて恐縮ですが、適当にかいつまんで眺めていただき、何かの参考になればうれしいです。

目次

  • あらまし
  • 現状
  • 0日目
    • IoT Platform の注文
    • Arduinoの注文
  • 1日目
    • node-REDの導入
      • パスワードの設定
    • Ambientの導入
      • 登録
      • node-REDへのモジュール追加
    • WebSocketのテスト
      • 想定データ仕様
    • WebSocketで受信したデータをAmbientに送信する
      • 一旦global変数に格納
      • 定期的にAmbientに送信

あらまし

  • 会議室あるある
    • なかなか予約が取れない
    • 使わないかもしれないけど先に予約しておこう
    • 予約したけど使わなかった。でもキャンセル忘れてた
    • 使わないのに予約済みの会議室だけ増えていく
    • 以下無限ループ

とりあえず、状況の把握だけでもやってみることにしました。


現状

まだ統計情報まではできていません。それは3日目にでもやる予定。
スクリーンショット 2017-01-06 20.04.40.png


0日目


IoT Platform を買った。

会社内なのに有線無線LANを使わなかったのは、セキュリティの問題があるためです。
完全に社内ネットワークと切り離して、すべてをイントラ側ではなく、インターネット側で実現しようと考えました。


Arduinoを買った。

スクリーンショット 2016-12-31 16.37.56.png

Arduino UNO互換であれば特になんでもいいとたぶん思います。
純正のUNOを一台持っているので、今回はお試しで安いのを買ってみた。

届くまで少し時間がかかるので、その間にWebサイト側を作ってしまいましょう。


1日目


node-REDの導入

Bluemixは日進月歩で画面が新しくなるので、毎回迷います。
サービスカタログから、 Node-RED Starter を追加します。
スクリーンショット 2016-12-31 16.59.34.png


ダッシュボードを開き、管理者用のユーザ名、パスワードを環境変数に設定し、保存します。
アプリが再起動するので数分待ちます。

スクリーンショット 2016-12-31 19.07.14のコピー.png


Ambientの導入

Ambientという、データを送るだけで最大8系統のデータを自動で履歴保存し、グラフにしてくれる素晴らしい無料のサービスがあります。これを利用させてもらい、0と1を送信することで、利用時間と空き時間を可視化しようと思います。

スクリーンショット 2016-12-31 19.17.29.png


Node-REDからAmbientに送信するモジュールのインストール

Ambientにデータを送るには、APIにPOSTすればいいのですが、Node-REDで簡単にその送信ができるモジュールがあるので、それをインストールします。
Wio node + Groveセンサー + Node-RED + Ambientで超簡単IoT を参考にさせていただきました。なお、現在はBluemixのDevOpsサービスは、Continuous Delivery サービスに変更になっており、 ギブハブ GitHubとの連携も簡単にできるようになっています。


Bluemixの Continuous Deliveryサービスの利用

ダッシュボードから、「継続的デリバリー」の有効化をクリックします。

スクリーンショット 2016-12-31 20.20.13.png


「Create」をおして、GitHubとのアカウントを紐付けると、

スクリーンショット 2016-12-31 20.23.13.png


GitHubに新しいレポジトリが登録されます。

スクリーンショット 2016-12-31 20.23.56.png


package.json にAmbientを追加し、Commitすると、自動でBluemixに連携され、Node-REDが再起動します。
スクリーンショット 2016-12-31 20.27.25のコピー.png


WebSocketのテストをする。

他の例をみてみると、さくらIoTとはWebSocketでつなぐのが鉄板のようですので、今回もWebSocketで接続することにします。
しかしながら、まだIoT Platformの発送通知すら来ていないので、先にテストができるよう、テストデータを送信できるようにしてみます。

先ほど設定したユーザ名とパスワードでNode-REDにログインします。

スクリーンショット 2016-12-31 21.07.33.png


Node-REDの便利な機能の一つに、部品をjson形式で書き出す機能があります。
私が作った稚拙な部品をここに置いておきますので、よろしかったらご利用ください。


[{"id":"9f1852ae.9260a8","type":"websocket out","z":"396465eb.1d8e22","name":"test websocket (/ws/test)","server":"75254220.fd7a5c","client":"","x":700.0000343322754,"y":190.9999828338623,"wires":[]},{"id":"a00899b6.1c5b48","type":"template","z":"396465eb.1d8e22","name":"sakura-iot","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"module\":\"1234567890ab\",\"type\":\"channels\",\"datetime\":\"{{payload.datetime}}\",\"payload\":{\"channels\":[{\"channel\":{{payload.channel}},\"type\":\"I\",\"value\":{{payload.value}}}]}}","x":478.5714797973633,"y":188.14291858673096,"wires":[["9f1852ae.9260a8","88ccffee.743da8"]]},{"id":"99d5057c.56db98","type":"inject","z":"396465eb.1d8e22","name":"15秒おき","topic":"","payload":"true","payloadType":"bool","repeat":"15","crontab":"","once":true,"x":105,"y":102.4285888671875,"wires":[["1566d30d.eb7c95"]]},{"id":"1566d30d.eb7c95","type":"function","z":"396465eb.1d8e22","name":"ランダムなチャンネルにランダムな値を生成","func":"var pdata = {}\n\n    \n// 15秒 * 1/4 = 1分に一度の割合で値を更新\nif(Math.random() < 1/4){\n    \n    // 0 - 5のいずれか\n    pdata.channel =  Math.floor( Math.random() *6 ) ;\n    \n    // 0 , 1のいずれか\n    pdata.value =  Math.round( Math.random()) ;\n    \n    pdata.datetime = new Date().toJSON();\n    msg.payload = pdata;\n\n    return msg;\n\n} else {\n    return null;\n}\n\n\n","outputs":1,"noerr":0,"x":403.57142639160156,"y":102.42860794067383,"wires":[["a00899b6.1c5b48"]]},{"id":"88ccffee.743da8","type":"debug","z":"396465eb.1d8e22","name":"WebSocket送信データ","active":true,"console":"false","complete":"payload","x":680.714282989502,"y":263.8572196960449,"wires":[]},{"id":"50fc2bf8.59c0b4","type":"comment","z":"396465eb.1d8e22","name":"さくらiotのWebSocketのモック","info":"","x":135,"y":51,"wires":[]},{"id":"6ac7390e.c86848","type":"comment","z":"396465eb.1d8e22","name":"モックのWebSocket から受信","info":"","x":137.8571548461914,"y":355.28572368621826,"wires":[]},{"id":"3b4df7a2.862328","type":"websocket in","z":"396465eb.1d8e22","name":"WebSocket (/ws/test)","server":"","client":"df973c4.18d10c","x":114.28571755545477,"y":405.28572368621826,"wires":[["38a72b0c.319a0c"]]},{"id":"38a72b0c.319a0c","type":"debug","z":"396465eb.1d8e22","name":"WebSocket受信データ","active":true,"console":"false","complete":"payload","x":362.32144927978516,"y":404.5715093612671,"wires":[]},{"id":"75254220.fd7a5c","type":"websocket-listener","z":"","path":"/ws/test","wholemsg":"false"},{"id":"df973c4.18d10c","type":"websocket-client","z":"","path":"ws://your-app-name.mybliemix.net/ws/test","wholemsg":"false"}]

こちらをコピーして右上のメニュー(横線3本のアイコン)からImportできます。
スクリーンショット 2016-12-31 21.08.47.png


なお、まだ見ぬAPIから送られてくるデータ仕様は、 さくらのIoT Platformを試してみたを参考にさせていただきました。

右上の「Deploy」をおすと、debugタブにデータがどんどん貯まっていくのが分かります。
スクリーンショット 2016-12-31 21.12.38.png


想定データ仕様

IoT Platformには、128のチャンネルがあり、そのチャンネルそれぞれに、8バイト(オクテット)のデータを送ることができます。

当社の会議室は、利用中以外はドアを開けておくルールになっています。
なので、Arduinoにドアセンサ(こんなの)を接続して、一つの部屋にひとつのチャンネルを割り当て、ドアが開いていればゼロ、ドアが閉まっていればイチを送るようにしました。

また、なるべくリアルタイムにデータを取得できるよう、5秒おきにループを回すことにしたのですが、毎回通信していたらそれなりに通信量がかさんでしまうので、状態が変わったときにだけデータを送ることにします。

実際のArduinoのコードは、0日目に注文したものが届いて、動くことを確認した後にアップします。


WebSocketで受信したデータをAmbientに送信する

前述の通り、IoT Platformからは、ドアの状態に変化が起こったときだけデータを受信することにしました。受け取ったデータを、そのままAmbientに転送し、棒グラフを描画させると、こんな風に、いつ使われているのか全く分からないデータになります。
スクリーンショット-2016-12-31-22.28.49.png
(画像はイメージです)

そのため、Node-REDの中で、IoT Platformから受信したデータを現在の状態として一時的に貯めておき、Ambientには定期的(1分おきとか)に現在の状態を送信することにしました。


まず、状態を蓄積するために、グローバル変数を定義し、初期化します。
左のNode(それぞれの部品をNodeと呼ぶんですね)の一覧から、「Inject」と「Function」を取り出し、2つを線でつないでください。
それぞれのNodeをダブルクリックすると、設定が出てきます。
スクリーンショット 2016-12-31 22.45.59.png


Injectの設定では、PayloadでBooleanのtrueを送るようにし、「Inject once at start?」にチェックを入れてください。これで、再起動時(左上のデプロイを押したとき)に必ず実行されます。
スクリーンショット 2016-12-31 22.44.51.png
Functionの設定では、下記のように、global変数にArrayを追加して、ゼロで初期化しておきます。
スクリーンショット 2016-12-31 22.45.20.png

設定を変更したら、反映するために「Deploy」を忘れず押しましょう。


つぎに、WebSocketから受信したデータでglobal変数を更新する部分を作ります。
せっかちな方は下記をコピーしてImportしてください。

[{"id":"1603f091.8c119f","type":"debug","z":"396465eb.1d8e22","name":"Global変数に保存された値","active":true,"console":"false","complete":"payload","x":602.7500076293945,"y":473.0000066757202,"wires":[]},{"id":"c6245639.e87ce8","type":"function","z":"396465eb.1d8e22","name":"Global変数の更新","func":" msg.payload.payload.channels.forEach(function(v) {\n     context.global.data[v.channel] = v.value;\n\n});\n\nmsg.payload = JSON.stringify(context.global.data);\n\nreturn msg;","outputs":1,"noerr":0,"x":343.75000762939453,"y":472.5000066757202,"wires":[["1603f091.8c119f"]]},{"id":"3e6f4d17.8847f2","type":"json","z":"396465eb.1d8e22","name":"","x":136.875,"y":472.5,"wires":[["c6245639.e87ce8"]]}]

Nodeのリストの上に、検索ボックスがあります。必要なNodeが見つからない場合はここから検索してください。
jsonというNodeは、文字列からjson オブジェクトに変換してくれます。WebSocketから受信した状態だと文字列なので変換が必要です。
スクリーンショット 2016-12-31 23.31.26.png


これで、global変数に各会議室の利用状態が保存されたので、情報を定期的にAmbientに送信します。

スクリーンショット 2017-01-01 0.17.28.png


[{"id":"3f480fb6.370088","type":"Ambient","z":"396465eb.1d8e22","name":"Ambient:会議室状況","channelId":"123","writeKey":"0123456789abcdef","x":521.5000019073486,"y":731,"wires":[]},{"id":"30e286bf.69737a","type":"function","z":"396465eb.1d8e22","name":"Arrayから値を取得","func":"\n\nvar data = {\n    // 0 or 1 \n    \"d1\" : context.global.data[0] ,\n    \"d2\" : context.global.data[1] ,\n    \"d3\" : context.global.data[2] ,\n    \"d4\" : context.global.data[3] ,\n    \"d5\" : context.global.data[4] ,\n    \"d6\" : context.global.data[5]  \n};\nmsg.payload = data;\nreturn msg;","outputs":1,"noerr":0,"x":276,"y":785.0000123977661,"wires":[["3f480fb6.370088","2b6720b9.34f1f8"]]},{"id":"cb556381.39e78","type":"inject","z":"396465eb.1d8e22","name":"1分おきに実行","topic":"","payload":"true","payloadType":"bool","repeat":"60","crontab":"","once":true,"x":109,"y":727,"wires":[["30e286bf.69737a"]]},{"id":"2b6720b9.34f1f8","type":"debug","z":"396465eb.1d8e22","name":"Ambient送信データ","active":false,"console":"false","complete":"payload","x":504,"y":785.0000123977661,"wires":[]}]

これをコピペして、ChannelIDとWriteKeyを適宜書き換えてください。
AmbientのチャネルIDとライトキーはログインすると出てきます。
スクリーンショット 2017-01-01 0.32.32.png

そうこうやっている間に年が明けてしまったので、2日目に続きます。


2日目に続く