目的
最近データの見える化、働き方改革、IoTというバズワードが広がっている。IoTと相性が良さそうな職種に農業があると言われている。農業における現場のニーズは温度が下がったとき、温度が下がったときにalertをを飛ばすくらいで良いという。しかし少々考えてみると農業では、温度、湿度、照度、地中温度、土壌成分等が必要だと考えられる。
今回は取得したデータを通信することが可能かどうか、可能であればどのような難易度かを探るために下記実験を行った。今回は接続実験なのでデータの正確性、信憑性は問わないものとする。
今回の実験は、センサーで取得したデータをESP32で処理してWi-Fiを使ってMQTTプロトコルで通信する。AWS EC2で作成した仮想サーバーで処理をすることにした。サーバーの中にMQTT受信用のmosquittoブローカーを作成して、Node-Redで処理してinfluxDBに入れる。そこからgrafanaを使って可視化、alertを発信する設定もgrafana上で行った。

仮想サーバーのOSはUbuntuにしたのでここからはUbuntuで説明する。
使用機器
ESP WROOM32 Geekcreit®ESP32開発ボード WiFi + Bluetooth 超低消費電力 デュアル コア ESP-32 ESP-32S ボード
SHT31(温湿度センサー) SHT31使用 高精度温湿度センサモジュールキット
TSL2561(照度センサー) TSL2561使用 照度センサーモジュール
EPC-1204−1B(ブレッドボード) ブレッドボード EIC1202B 0165-40-4-1202B
MacBookPro
HiGrow(Wemos®Higrow ESP32 WiFi + Bluetoothバッテリー+ DHT11土壌温度および湿度センサーモジュール )
Higrow ESP32 WiFi + Bluetooth Battery + DHT11 Soil Temperature And Humidity Sensor Module


実験方法
1 センサーとESP32を接続する
2 センサの可動テストをする
3 awsにMosquittoBroker,node-red,influxDB,grafanaをインストールする
4 接続テストをする
5 Alertを発信してみる
MosquittoBrokerのインストール
sudo apt install mosquitto
受信するためにmosquittoclientもインストールしておく
sudo apt install mosquitto-clients
接続テストをしてみる
mosquitto_sub -h localhost -t test
新しくコンソールを開いて
mosquitto_pub -h localhost -t test -m "test"
を入力してみて、testが表示されたら接続テスト成功である。
Node-Redのインストール

![]()
Node-Redのインストールはnodejsのインストールから始めた。Node-Redの公式サイトではNode-REDは、Node.js LTS 8.xを使用することをお勧めします。Node.js 6.xおよび4.xのユーザーは、最新の更新があることを確認する必要があります。Node-REDはNode.js 0.12.xまたは0.10.xをサポートしなくなりました。とあるので、nodejsをインストールする際にはnode -vでバージョンを確認しておいたほうが良い。
基本的には下記のコマンドでインストールできる。(2018年10月現在)
sudo apt update sudo apt install nodejs sudo apt install npm sudo npm install -g --unsafe-perm node-red
influxDBのインストール
公式サイトを参考にしてインストールした。
https://www.influxdata.com/time-series-platform/influxdb/
Ubuntuなので下記のコマンドでインストールした。
wget https://dl.influxdata.com/influxdb/releases/influxdb_1.6.4_amd64.deb sudo dpkg -i influxdb_1.6.4_amd64.deb
influxDBを起動させる。
sudo systemctl start influxdb.service
起動させた後にinfluxと入力することで対話モードに入っていける。
対話モードで
create database hogehogedb
でデータベースを作成した。
今回はここから後はGUIで作業することにしたので、influxDBのGUIツールchronografをインストールした。
これも公式サイトを参考に
wget https://dl.influxdata.com/chronograf/releases/chronograf_1.6.2_amd64.deb sudo dpkg -i chronograf_1.6.2_amd64.deb
のコマンドでインストールした。インストールできたかどうかはブラウザでサーバーのipアドレスの8888ポートを開くとGUIが立ち上がってることで確認できた。

chronografの中でのクエリはGUIで操作できるのでここでは言及しない。
Grafanのインストール
こちらも公式サイトを参考にインストールした。
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.3.2_amd64.deb sudo dpkg -i grafana_5.3.2_amd64.deb
このコマンドではうまくいかないことがあるので、次の方法の方が無難です。
/etc/apt/sources.listに下記のコマンドを追加します。
deb https://packagecloud.io/grafana/testing/debian/ stretch main
そのあとにキーを取得してインストールした。下記のコマンドを順番に実行していく。
curl https://packagecloud.io/gpg.key | sudo apt-key add - sudo apt-get update sudo apt-get install grafana
これでインストールできたので、下記のコマンドで起動した。
sudo service grafana-server start
3000番のポートにアクセスすることで無事にインストールできていることを確認した。

IDとパスワードを聞かれるが、デフォルトではどちらもadminであるので、入ってみるとこのようなUIが出る、使い方については後述する。準備が終わったのでいよいよ実装していく。
まずはセンサーとマイコンを接続した。温度センサーと照度センサーのアドレスが違うことを前提にI2Cで接続した。


電源 3V
SDA GPIO21
SCL GPIO22
に接続し、サンプルを参考に動かしてみた。
//STH31_TSL2561/ESP32 動作テスト
#include <WiFiClientSecure.h>
#include <Arduino.h>
#include <Wire.h>
#include "AE_SHT31.h"
#include <Wire.h>
#include "TSL2561.h"
//---------------------------------------------------//
// AE-SHT31 ------ //
// //
// V+ ------ 5.0V //
// SDA ------ 21 //
// SCL ------ 22 //
// ADR ------ (Open= 0x45 Close= 0x44) //
// GND ------ GND //
//---------------------------------------------------//
// SHT31のアドレスを設定
AE_SHT31 SHT31 = AE_SHT31(0x45);
void setup() {
// シリアル通信を9600bpsに設定
Serial.begin(9600);
// シリアルに文字を出力
Serial.println("SHT31 Test!!");
// SHT31をソフトリセット
SHT31.SoftReset();
// 内蔵ヒーター 0:OFF 1:ON
SHT31.Heater(0);
}
void shtloop()
{
// SHT31から温湿度データを取得
SHT31.GetTempHum();
Serial.println("--------------------------");
// SHT31.Temperature() より温度データ取得
Serial.println("Temperature ('C)");
Serial.println(SHT31.Temperature());
// SHT31.Humidity() より相対湿度データ取得
Serial.println("Humidity (%)");
Serial.println(SHT31.Humidity());
// 待ち時間
//delay(800);
}
// Example for demonstrating the TSL2561 library - public domain!
// connect SCL to analog 5
// connect SDA to analog 4
// connect VDD to 3.3V DC
// connect GROUND to common ground
// ADDR can be connected to ground, or vdd or left floating to change the i2c address
// The address will be different depending on whether you let
// the ADDR pin float (addr 0x39), or tie it to ground or vcc. In those cases
// use TSL2561_ADDR_LOW (0x29) or TSL2561_ADDR_HIGH (0x49) respectively
TSL2561 tsl(TSL2561_ADDR_FLOAT);
void tslsetup() {
if (tsl.begin()) {
Serial.println("Found sensor");
} else {
Serial.println("No sensor?");
while (1);
}
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
//tsl.setGain(TSL2561_GAIN_0X); // set no gain (for bright situtations)
tsl.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations)
// Changing the integration time gives you a longer time over which to sense light
// longer timelines are slower, but are good in very low light situtations!
tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright light)
//tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium light)
//tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim light)
// Now we're ready to get readings!
}
void tslloop() {
// Simple data read example. Just read the infrared, fullspecrtrum diode
// or 'visible' (difference between the two) channels.
// This can take 13-402 milliseconds! Uncomment whichever of the following you want to read
uint16_t x = tsl.getLuminosity(TSL2561_VISIBLE);
//uint16_t x = tsl.getLuminosity(TSL2561_FULLSPECTRUM);
//uint16_t x = tsl.getLuminosity(TSL2561_INFRARED);
Serial.println(x, DEC);
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
// That way you can do whatever math and comparisons you want!
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir, full;
ir = lum >> 16;
full = lum & 0xFFFF;
Serial.print("IR: "); Serial.print(ir); Serial.print("\t\t");
Serial.print("Full: "); Serial.print(full); Serial.print("\t");
Serial.print("Visible: "); Serial.print(full - ir); Serial.print("\t");
Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir));
//delay(1000);
}
void loop(){
shtloop();
tslloop();
delay(1000);
}
値が取得できた(今回は値の信頼性は問わないものとする)。
値が取得できたので通信してみる。
今回はWi-Fiで接続して通信プロトコルはMQTTとする。
#include <WiFiClientSecure.h>
#include <PubSubClient.h> //mqtt用のライブラリ
#include <Wire.h>
#include "AE_SHT31.h"
#include <ArduinoJson.h>
#include <TSL2561.h>
//ピン設定
//---------------------------------------------------//
// AE-SHT31 ------ Arduino UNO //
// //
// V+ ------ 5.0V //
// SDA ------ A4 //
// SCL ------ A5 //
// ADR ------ (Open = 0x45) //
// GND ------ GND //
//---------------------------------------------------//
// SHT31のアドレスを設定
AE_SHT31 SHT31 = AE_SHT31(0x44);
TSL2561 tsl(TSL2561_ADDR_FLOAT);
// SHT31をソフトリセット
//SHT31.SoftReset();
// 内蔵ヒーター 0:OFF 1:ON
//SSIDとパスワードの設定
char *ssid = "your SSID";
char *password = "your password";
//MQTTサーバーの指定
const char* mqtt_server = "your server public DNS";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("msg/comment", "Coming Packets");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
// pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
SHT31.GetTempHum(); //SHTから温湿度データを取得
tsl.begin(); //tslからデータの取得
tsl.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations)
tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium light)
uint16_t x = tsl.getLuminosity(TSL2561_VISIBLE);
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir, full;
ir = lum >> 16;
full = lum & 0xFFFF;
float temp = SHT31.Temperature();
float humi = SHT31.Humidity();
float ilum =tsl.getLuminosity(TSL2561_VISIBLE);
long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
snprintf (msg, 75, "{\"temp\":\%f\,\"humi\":\%f\,\"ilum\":\%f\}",temp,humi,ilum);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("msg/comment", msg);
}
}
少し不安定ですが、接続テストはできました。そのまま使う際はどこかのタイミングでディレイを入れたほうがいいです。

接続は確認できたので、Node-Redで処理を行った。

mqttというnodeがあるので、それをそのまま利用した。


サーバーのipアドレスと、トピックを入力するだけで受信できた。
パレットの管理からinfluxDBのノードを追加した。


このときパレットの管理ができないときには、
sudo apt install npm
でnpmをインストールし直す。
influxDBのノードの設定は同じサーバーに入れているので、先程influxDBの対話モードで作成したデータベースを使用した。
プロパティを入力すると簡単に連携でき、measurementもここで指定できるので適当な名前をつけた。
chronografでデータがインポートされていることを確認。

データがきていることが確認できたので、grafanaと連携させた。
gurafanaも同じサーバーに入れているので簡単に連携できる。
実際にどのような操作をしたかは動画にて保存した。
次にalertの発信を作成した。
LINEnotify機能がGrafanaにデフォルトで入っていたので使用することにする。

notification channelを追加してLINEを選択してTOKENを入力すると接続できた。

alertのルールを決めてテストをしてみた。
ちなみにLINEのalert機能はNode-Redでも実装できるが、https通信をする必要があり、かつ自己証明やlet’sencryptの証明書ではできないので今回はGrafanaのalert機能を利用した。
結果
オープンソースなどを利用してIoTが実装できた。
常時可動させていると、環境の可視化(見える化)ができた。
必要なときにalertを飛ばすことができた。
スマートホンやタブレットでも使用可能です。

考察
オープンソースを利用することで細かいことを気にすることなく接続することができるが、そのデータの信頼性を担保することが重要になると考えられる。
一口にIoTと言っても様々な技術の組み合わせであり比較的容易に動かすことができるが、その技術を理解し、起こるであろうトラブル等を回避したり、構造的に起こる誤差を排除したりして実装するためには幅広い知識が必要になる。
参考文献等
AWSドキュメント
https://docs.aws.amazon.com/index.html#lang/ja_jp
ubuntuでMQTTブローカー「mosquitto」のインストール方法
https://qiita.com/rui0930/items/40bd5a1cfd3422206ad3
influxdata公式サイト
https://www.influxdata.com/
Node-RED User Group Japan
https://nodered.jp/docs/getting-started/installation
コーヒーサーバは香炉である
https://blog.maripo.org/2017/07/esp32-aws-iot
Grafana公式サイト
https://grafana.com
とりあえず Ubuntu で新しい Node.js, npm をインストール
https://qiita.com/kerupani129/items/60ee8c8becc2fe9f0d28

Pingback: 環境計測実験2〜セキュリティの強化〜 – シンナカムラの駆け出しエンジニア日記
Pingback: 工場向けワイヤレスIOT講習会参加レポート – シンナカムラの駆け出しエンジニア日記
Pingback: ノンコーディング防犯(Raspberrypiとenebularを利用して) – シンナカムラの駆け出しエンジニア日記