節約プログラマー雑記

Arduino(ESP32)とMQTTで温湿度データ送信

もう大分前になるのですが、「これからはIoTだー」と一時期Arduino(ESP32)にはまり、色々なセンサーデータの取得や、身の周りHWのコントロールを行っている時期がありました。
その一環として、部屋の温湿度をArduino(ESP32)で取得し、Raspberry Piに送って可視化していたのですが、意外と普段の生活でも、温度の推移が見れて役に立っているのでその時のプログラムがご紹介します。

1. 概要

今回のアプリの概要としては、Arduino側で定期的に温湿度のセンサーデータを取得し、MQTT通信を用いて、Raspberry Pi側にデータを飛ばすという構成を取っています。
Raspberry Pi側はMQTTのブローカーを立ち上げておくことで、Arduinoから送られたデータをMySQLに蓄積して、DjangoとChart.jsを用いてグラフに表示するという形を取っています。

Raspberry Pi側でセンサーデータも取ることができるというお話はあると思いますが、センサーデバイスと管理サーバーを分離することで、複数の場所からデータを取得することができることが可能になると考え、この構成を取りました。
また、最近は、GCPやAWSでもMQTT通信をサポートしたサービスがあるので、いつか活用できるかもしれません笑。

今回は、Arduiono側の部分について、説明していきたいと思います。

2. 準備・必要モジュール

Arduino側のアプリを作るにあたって必要なものは、以下の3点になります。

一つ注意点としては、Arduinoのボードは、ESP32が載っているものであるほうが良いです。
通常のArduinoの場合、Wifi通信用のモジュールが搭載されていないため、秋月電子などで別途購入して、半田づけする必要があってかなり手間になります。そのため、ESP32など、すでに通用モジュールが搭載されているボードがお勧めです。
ジャンパーワイヤーやブレッドボードなどは、すでに購入していれば特に必要ありません。


必要なモジュールの購入できたら、Arduinoの開発環境を準備します。
下記のArduino公式サイトの赤枠部分から、Arduino IDEのインストーラをダウンロードし、インストーラに従い、インストールを行います。

・Arduino公式サイト Arduino_IDE.png

Arduino IDEの使い方については、一旦、省略をしますが、IDEのインストールが完了しましたら、ライブラリの管理から「DHT sensor library for ESPx」、「PubSubClient」をインストールすれば、準備完了になります。

3. 作成・ソースコード

部品が一式揃ったら、下記のような形で、ESP32とDHT22をブレッドボード上で、ジャンパーワイヤーを用いて、繋げます。
ESP32.jpg

正直、画像だと入り組んでいて分かりづらいと思いますが、DHT22を正面から見たときに、左側の1番ピンから順に(1)5V電源(VDD)、(2)データ入出力(DATA)、(3)繋がない、(4)GNDと繋いでいます。また、(1)、(2)の間は抵抗が必要らしく、10kΩの抵抗をつないだ状態になっています。
回路の構築が完了したら、Arduino IDEを立ち上げ、下記のソースを作成します。


今回、ESP32に書き込んだソースは下記の通り。
12分毎の定間隔でDHT22からデータを取得し、Wifiでルーターに接続を行って、MQTTでデータを飛ばすような処理を行っており、接続先のルーターのSSID、パスワードとデータの送信先のIPアドレス(Raspberry Pi)、自分のESP32のデータ出力ピン番号を変えれば、基本的には問題無く利用できるようなソースになっています。

ソースコード

#include <DHTesp.h>
#include <PubSubClient.h>
#include <WiFi.h>

// WiFi
const char* ssid   = "接続先のWifiルータのSSID";
const char* passwd = "パスワード";

//MQTT
const char* mqttHost = "接続先のIPアドレス(※Raspberry Pi)";
const int mqttPort = 1883;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

//PublishData
const char* topic = "sensor/1";

//DHT22
DHTesp dht;
TaskHandle_t tempTaskHandle = NULL;
int dhtPin=14; //(2)の接続先のピン番号を設定
String val;

//初期化処理
void setup() {
   Serial.begin(115200);
   connectWiFi();
   connectMqtt();
   dht.setup(dhtPin,DHTesp::DHT22);
}

//メイン処理
void loop() {
  int netsts = 0;
  //WiFi
  if(WiFi.status() == WL_DISCONNECTED) {
    netsts = connectWiFi();
    if(netsts != 0) return;
  }
  //MQTT
  if ( ! mqttClient.connected()){
    netsts = connectMqtt();
    if(netsts != 0) return;
  }
  //センサーデータ取得
  TempAndHumidity lastValue = dht.getTempAndHumidity();
  Serial.println("Temprature:" + String(lastValue.temperature,3));
  Serial.println("Humidity  :" + String(lastValue.humidity,3));
  // 送信処理
  val = String(String(lastValue.temperature,2)+";"+String(lastValue.humidity,2)); 
  mqttClient.publish(topic, val.c_str());
  delay(1000);
  esp_sleep_enable_timer_wakeup(12*60 *1000000); //スリープ時間を12分に設定
  esp_deep_sleep_start();

  mqttClient.loop();
}

 /**
   * Connect WiFi
   */
int connectWiFi()
{
   short cnt = 0;
   delay(10);
   WiFi.begin(ssid, passwd);
   Serial.print("WiFi connecting...");
   while(WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
        cnt++;
        if (cnt > 101) return 1;
   }
   Serial.print(" connected. ");
   Serial.println(WiFi.localIP());
   return 0;
}
/**
  * Connect MQTT
  */
 int connectMqtt()
 {
    short cnt=0;
    mqttClient.setServer(mqttHost, mqttPort);
    while( ! mqttClient.connected() ) {
        Serial.println("Connecting to MQTT...");
        String clientId = "ESP32-" + String(random(0xffff), HEX);
        if ( mqttClient.connect(clientId.c_str()) ) {
            Serial.println("connected"); 
        }
        else if(cnt > 100){
          return 1;
        }
        cnt++;
        delay(1000);
        randomSeed(micros());
    }
    return 0;
 }

ソースの作成が完了したら、ESP32のマイコンボードに書き込みを行い、以下のような出力がされれば、問題無くESP32からデータが送信されていることが確認できます。

Arduino_debug.png

4. 結果

上記のような形で、Arduino側からセンサーデータを取得し、データを送信できることが確認できました。
今回は、センサー側の処理のみを書いたのですが、データを集約するセンター側の処理も記載できれば、温度と湿度をグラフ化することができるようになります。
私の場合は、家計簿の時でも紹介したDjangoとChart.jsを使って、下記のような形でグラフを作って遊んでいます。

Sensor_data.png

冒頭でも少し触れましたが、今はGCPやAWSでも、MQTT通信をサポートしたサービスがあるので、何かデータ収集アプリに役に立たせていければと勝手に思っています。

(2021/5/13追記)
Arduino(ESP32)をずっと連続稼働させていると、3,4か月過ぎたあたりで、データが正しく飛ばなくなり、電源を再起動してもなってしまいました。正直、原因は良く理解できていませんが、その際、再度パソコンからスケッチをコンパイルして書き込むと治りましたのでご参考までに。