4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-12-31

さくらの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 を買った。

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

会社内なのに有線無線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日目に続く

4
8
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
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?