環境計測実験1

目的

最近データの見える化、働き方改革、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

3 Comments

  1. Pingback: 環境計測実験2〜セキュリティの強化〜 – シンナカムラの駆け出しエンジニア日記

  2. Pingback: 工場向けワイヤレスIOT講習会参加レポート – シンナカムラの駆け出しエンジニア日記

  3. Pingback: ノンコーディング防犯(Raspberrypiとenebularを利用して) – シンナカムラの駆け出しエンジニア日記

Leave Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です