• conect+

CandyPi LiteとオムロンUSB環境センサを使ってconect+ Stduioでモニタリングをしてみよう

1.概要

2.Candy Pi Liteについて

3.オムロン環境センサについて

4.Cnady Pi Liteのセットアップ

5.Candy-Redを使ってプログラミング

6.ダッシュボードにグラフを表示して可視化

7.熱中症指数でメールアラート機能を設定

1.概要

 本記事では、セルラー通信ができるRaspberryPiのCandyPi Liteと、様々な環境情報(温度、湿度、照度、気圧、CO2…等々)を記録できるオムロンUSB型環境センサをつないで、環境モニタリングシステムを構築します。今回は各種情報はconect+Studioで可視化しつつ、熱中症指数が危険値まであがった場合にアラートが出る仕組みも合わせて構築します。


CandyPi Lite + オムロン環境センサ

温度、湿度、照度、気圧…などの情報をダッシュボードで可視化

アラートの設定とメール通知の例


2.Candy Pi Liteについて

 IoTを活用した環境モニタリングをしたい場合、Wifiが必ずある環境とは限りません。CANDY Pi Lite は Raspberry Piなどに搭載できる通信モジュールで、これによりキャリア回線を使ったインターネットへの接続が可能になります。ハードウェアだけでなく、CANDY RED という Node-RED ベースの開発環境も、OSと一緒に提供され、複雑なプログラミングすることなく簡単にIoT環境を実現できます。

NTTドコモ・au/KDDI・ソフトバンクネットワーク向け


商品の詳細は以下ページをご参照ください。

CANDY LINE https://candy-line.com/



3.オムロン環境センサについて

今回の環境センシングにはオムロン製のUSB型環境センサ(2JCIE-BU)を用います。

このセンサは指先サイズのUSBドングルの中に、温度、湿度、照度、気圧、騒音、加速度、VOCガス、CO2濃度の計測ができるセンサを搭載している複合環境センサです。

(CO2濃度はeCO2という推定濃度になるので、参考値なのをご注意ください)


BLEで通信が可能ですが、今回はRaspberryPiのUSBに直接接続するので、USB通信のシリアル通信によるデータ取得を行います。



形2JCIE-BU 環境センサ USB型 | OMRON - Japan

https://www.omron.co.jp/ecb/product-detail?partNumber=2JCIE-BU


4.CANDY Pi Liteのセットアップ

購入したCANDY Pi Liteと組み立てます。

以下公式ドキュメントページのsetupの項目から、デバイスごとに組み立てを実施してください。SIMカードもCANDY Pi Liteに取り付けます。

candy-pi-lite-info/setup at master · CANDY-LINE/candy-pi-lite-info · GitHub

https://github.com/CANDY-LINE/candy-pi-lite-info/tree/master/setup


その後、CANDY Pi Liteをセットアップします。以下のページに従って、CADNY Pi LIteの用にカスタムされた専用OSイメージをダウンロードし、SDカードに書き込みます。


Raspberry Pi Imagerを利用したCANDY Pi Lite専用OSイメージの書き込み方法 - CANDY Pi Lite/+ - CANDY LINE®

https://forums.candy-line.io/t/raspberry-pi-imager-candy-pi-lite-os/455


電源を入れてしばらくするとオレンジのLEDが点滅し始めます。

通常のRaspberryPiのOSイメージを利用するのと同じように、初期のパスワードをセキュリティ観点から必ず変更しましょう。


このイメージには開発環境のCANDY REDもプリインストールされており、OS起動時に自動的に起動します。有線LANを経由して同じネットワーク内のPCなどからCANDY REDへアクセスしてみましょう。

http://raspberrypi.local:8100

以下のようなログイン画面が出れば成功です。

ユーザ名はpi、先程変更したパスワードでログインしてください。


5.CANDY-REDを使ってプログラミング

ここからは、①環境センサ情報の取得と、②conect+Studioへのデータ送信をCANDY-REDで実装します。CANDY-REDはNODE-REDベースの専用開発環境で、CANDY Piを複雑なプログラミングをせずとも使うことが可能になります。


①まずUSB環境センサの情報を取得します。

USB環境センサとは複雑なシリアル通信が必要になりますが、ノードで扱えるようにパッケージが準備されていますので、こちらを活用します。最新のCANDY Pi用OSではデフォルトでインストールされているので、追加のインストールは不要です。


node-red-contrib-omron-2jcie-bu (node) - Node-RED https://flows.nodered.org/node/@candy-line/node-red-contrib-omron-2jcie-bu


データの取得には、RaspberryPi側でUSB通信のドライバ設定が必要です。

まず以下を忘れずに実行してください。

$ sudo modprobe ftdi_sio
$ sudo chmod 777 /sys/bus/usb-serial/drivers/ftdi_sio/new_id
$ sudo echo 0590 00d4 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id

② conect+Studioへのデータ送信も専用のノードが準備されています。

conect+Studioの各種ワークスペースID、WebAPIキー、デバイスID、センサーIDを指定し、JSONで指定したフォーマットデータをつなぐだけで簡単にデータを送信することができます。


node-red-contrib-conect-plus (node) - Node-RED https://flows.nodered.org/node/node-red-contrib-conect-plus


上記を組み合わせて、以下のようなCANDY-REDのプログラムを作成しました。

20秒ごとにデータを取得のコマンドを環境センサに送信し、シリアルで受信したデータを変換、functionノードで時間やバリュー情報を付加して、conect+に送信しています。


以下コードをコピーし、「読み込み」から貼り付けると上記図のフローをそのまま再現できます。

[
    {
        "id": "e7a96cbb.cc45d",
        "type": "tab",
        "label": "2JCIE-BU01",
        "disabled": false,
        "info": ""
    },
    {
        "id": "4349e36f.d916ec",
        "type": "debug",
        "z": "e7a96cbb.cc45d",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1370,
        "y": 280,
        "wires": []
    },
    {
        "id": "1d2eff66.0de7d1",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "temp",
        "x": 1090,
        "y": 280,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "5e368ca.51ee774",
        "type": "comment",
        "z": "e7a96cbb.cc45d",
        "name": "Get last senosr data every 10 sec",
        "info": "",
        "x": 250,
        "y": 100,
        "wires": []
    },
    {
        "id": "f2bf9890.208c18",
        "type": "2JCIE-BU out",
        "z": "e7a96cbb.cc45d",
        "name": "",
        "x": 480,
        "y": 160,
        "wires": [
            [
                "748bd1fb.87095"
            ]
        ]
    },
    {
        "id": "7b49c718.af4fd8",
        "type": "inject",
        "z": "e7a96cbb.cc45d",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "20",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "getLatestSensorData",
        "payload": "",
        "payloadType": "str",
        "x": 250,
        "y": 160,
        "wires": [
            [
                "f2bf9890.208c18"
            ]
        ]
    },
    {
        "id": "748bd1fb.87095",
        "type": "serial out",
        "z": "e7a96cbb.cc45d",
        "name": "",
        "serial": "6e3108f2.8e92d8",
        "x": 670,
        "y": 160,
        "wires": []
    },
    {
        "id": "bb320af4.4cdcf8",
        "type": "serial in",
        "z": "e7a96cbb.cc45d",
        "name": "",
        "serial": "6e3108f2.8e92d8",
        "x": 210,
        "y": 280,
        "wires": [
            [
                "21ca9e25.aefef2"
            ]
        ]
    },
    {
        "id": "21ca9e25.aefef2",
        "type": "2JCIE-BU in",
        "z": "e7a96cbb.cc45d",
        "name": "",
        "messageFormat": "standard",
        "ttl": "10000",
        "x": 470,
        "y": 280,
        "wires": [
            [
                "77cdfb80.d22ed4",
                "eb5e693b.8fc5a8",
                "4a3d42ce.e6b62c",
                "307b2d23.0031b2",
                "d9010ec.69c33f",
                "75e0d060.cab34",
                "c742850d.a69878",
                "31055d17.5b58d2"
            ]
        ]
    },
    {
        "id": "77cdfb80.d22ed4",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [temp]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet temp = msg.payload.data.temperature;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": temp\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 770,
        "y": 280,
        "wires": [
            [
                "1d2eff66.0de7d1"
            ]
        ]
    },
    {
        "id": "ceeee3aa.44089",
        "type": "comment",
        "z": "e7a96cbb.cc45d",
        "name": "Send data to conect+",
        "info": "",
        "x": 740,
        "y": 240,
        "wires": []
    },
    {
        "id": "eb5e693b.8fc5a8",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [humid]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet humid = msg.payload.data.humidity;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": humid\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 770,
        "y": 340,
        "wires": [
            [
                "27527c25.e62c34"
            ]
        ]
    },
    {
        "id": "4a3d42ce.e6b62c",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [illuminance]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet illuminance = msg.payload.data.illuminance;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": illuminance\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 790,
        "y": 400,
        "wires": [
            [
                "9a427865.65db18"
            ]
        ]
    },
    {
        "id": "307b2d23.0031b2",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [pressure]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet barometricPressure = msg.payload.data.barometricPressure;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": barometricPressure\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 780,
        "y": 460,
        "wires": [
            [
                "687f5f23.06f4a"
            ]
        ]
    },
    {
        "id": "d9010ec.69c33f",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [noise]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet soundNoise = msg.payload.data.soundNoise;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": soundNoise\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 770,
        "y": 520,
        "wires": [
            [
                "5c0794af.88580c"
            ]
        ]
    },
    {
        "id": "75e0d060.cab34",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [eco2]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet eco2 = msg.payload.data.eco2;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": eco2\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 770,
        "y": 580,
        "wires": [
            [
                "baef1f1d.74ae5"
            ]
        ]
    },
    {
        "id": "c742850d.a69878",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [discomfortIndex]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet discomfortIndex = msg.payload.data.discomfortIndex;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": discomfortIndex\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 800,
        "y": 640,
        "wires": [
            [
                "f662c021.1e0ed"
            ]
        ]
    },
    {
        "id": "31055d17.5b58d2",
        "type": "function",
        "z": "e7a96cbb.cc45d",
        "name": "Convert c+ data format [heatStroke]",
        "func": "const dt = new Date;\ndt.setHours(dt.getHours()+9);\nlet time = dt.toISOString().split('Z')[0] + '+09:00';\n\nlet heatStroke = msg.payload.data.heatStroke;\n\nmsg.payload = {\n    \"sensingAt\": time,\n    \"value01\": heatStroke\n};\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 780,
        "y": 700,
        "wires": [
            [
                "3fa646e7.17d8fa"
            ]
        ]
    },
    {
        "id": "27527c25.e62c34",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "humid",
        "x": 1090,
        "y": 340,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "9a427865.65db18",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "illuminance",
        "x": 1090,
        "y": 400,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "687f5f23.06f4a",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "pressure",
        "x": 1090,
        "y": 460,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "5c0794af.88580c",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "noise",
        "x": 1090,
        "y": 520,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "baef1f1d.74ae5",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "eco2",
        "x": 1090,
        "y": 580,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "f662c021.1e0ed",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "discomfort",
        "x": 1090,
        "y": 640,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "3fa646e7.17d8fa",
        "type": "studio-send",
        "z": "e7a96cbb.cc45d",
        "workspaceId": "XXXXXXXXX",
        "webAPIKey": "XXXXXXXXX",
        "deviceId": "CandyPi01",
        "sensorId": "heatStroke",
        "x": 1090,
        "y": 700,
        "wires": [
            [
                "4349e36f.d916ec"
            ]
        ]
    },
    {
        "id": "6e3108f2.8e92d8",
        "type": "serial-port",
        "serialport": "/dev/ttyUSB0",
        "serialbaud": "115200",
        "databits": "8",
        "parity": "none",
        "stopbits": "1",
        "waitfor": "",
        "dtr": "none",
        "rts": "none",
        "cts": "none",
        "dsr": "none",
        "newline": "0",
        "bin": "bin",
        "out": "time",
        "addchar": "",
        "responsetimeout": "10000"
    }
]


conect+のstudio-sendノードにはそれぞれ皆さまのワークスペースID、WebAPIキーを指定してください。(仮でXXXXXXと指定してあります)また、こちらのプログラムのデプロイ前にはconect+Studio側で受信するためのデータアダプターの作成を事前に済ませておいてください。


データアダプターの作成方法



本プログラムをデプロイし、conect+Studio側のデータで正しくデータが受け取れていれば完了です。


6.ダッシュボードにグラフを表示して可視化

ダッシュボードの作成、編集、ウィジェットの追加の方法は、以下のリファレンスやドキュメントを参照ください。


ウィジェットアイテムの追加 – conect+ Support


M5Stackからconect+ Studioに温度・湿度・気圧センサー情報を送信しよう


今回の例では温度、湿度、照度、気圧、不快指数、eCO2を取得して各ウィジェットに表示させています。


7.熱中症指数でアラートを設定しよう

 conect+Studioのルール機能を用いることで、データをトリガーにアクションを設定します。こちらを使うとメール、Slackへの通知、IFTTTを経由してさまざまサービスと連携可能です。今回は熱中症指数の値が31を超えたらアラートメールを送る仕組みをつくってみます。


①ルール画面からルールを追加を選択します。基本設定ではルールの名前を決めてください。次の条件参照するデータ、判定条件、条件値を以下のように設定します。

③アクション設定で、具体的に実施する内容を設定します。

 今回はメールで通知とするので、メールアドレスとその文章を指定します。


「保存する」するとルールがアクティブな状態になります。

手で温めたり、息を吹きかけたりすると温湿度が上昇しますので、正しく通知メールが届けば成功です。このようにconect+ではセンサ情報を可視化するだけでなく、ルールを使った通知等も簡単につくれますので、様々な用途での活用をご検討ください。




246回の閲覧0件のコメント