Arduino ESP32で温湿度データを収集する

힘센캥거루
2025년 7월 7일(수정됨)
1
85
arduino

今日はArduino ESP32で温湿度を測定し、データを送信するWiFi百葉箱を作ってみる。

この内容は学校で行われる16+1授業の原稿を基にして書いた文章である。

1. 準備物

準備物は簡単だ。

ESP32, DHT-22, 電線3本
Arduino ESP32で温湿度データを収集する-1

まずESP32を簡単に説明すると、WiFiモジュールが内蔵されたArduinoである。

しかし、サイズは一般的なArduinoよりもはるかに小さい。

2. ESP32ピンマップ

Arduino ESP32で温湿度データを収集する-2

おや?ピン番号が少しおかしいかな?

これは以前の記事でも説明したが、WiFiモジュールが入ることでピンマッピングが変更されたためだ。

以下にESP32 Arduinoのピンマッピングを示す。

それでも、この子はGPIOピン番号とピン名がほぼ一致しているようだ。

以下のピンのうち安全なD4ピンを利用してDHT-22を動かしてみる予定だ。

Arduino ESP32で温湿度データを収集する-4

Arduino Dピン

GPIO番号

注意事項

機能および説明

D0

GPIO0

ストラッピング: ブート時にLOWまたはフローティングが必要

フラッシュモード突入に影響 ([randomnerdtutorials.com][1])

D1

GPIO1 (TX0)

USBシリアル競合に注意

アップロード・デバッグ用UART0 TX

D2

GPIO2

ストラッピング: ブート時にLOW/フローティングが必要

オンボードLED → ブートに影響あり

D3

GPIO3 (RX0)

USBシリアル競合に注意

UART0 RX、ブート時にHIGH

D4

GPIO4

★ 安全

デジタルI/O、ADC2_CH0、タッチ可能

D5

GPIO5

ストラッピング: ブート時にHIGHが必要

ブート中PWM出力可能

D6D11

GPIO6–11

絶対使用禁止

内部SPIフラッシュピン

D12

GPIO12

ストラッピング: ブート時にLOWが必要

ADC2_CH5、タッチ、ブートに影響あり

D13

GPIO13

安全

ADC2_CH4、タッチ可能

D14

GPIO14

ブート時PWM出力、ブートストラッピング可能

ADC2_CH6、タッチ可能

D15

GPIO15

ストラッピング: ブート時HIGHが必要、PWM出力

ADC2_CH3、タッチ可能

D16

GPIO16

Wroverモジュール使用時はPSRAMに注意

UART2デフォルトTX/RX (17/16)

D17

GPIO17

Wroverモジュールに注意

UART2デフォルトTX/RX (17/16)

D18, D19, D21–D23, D25–D27, D32–D33

省略

安全

デジタル、PWM、I2C、SPI、ADC/DAC使用可能

D34, D35, D36(VP), D39(VN)

34,35,36,39

入力専用、プルアップ/プルダウンなし

ADC1チャンネル(追加機能なし)

3. DHT-11 vs DHT-22

通常、Arduinoを購入すると基本的に入っている温湿度計はDHT-11である。

青い色のものだが、これを使うと誤差範囲が約2度と非常に大きい。

以下にDHTとDHT-22の性能を表でまとめた。

項目

DHT-11

DHT-22 (AM2302)

外観

Arduino ESP32で温湿度データを収集する-5Arduino ESP32で温湿度データを収集する-6

温度測定範囲

0 ~ 50°C

-40 ~ +80°C

温度精度

±2°C

±0.5°C

湿度測定範囲

20 ~ 80% RH

0 ~ 100% RH

湿度精度

±5% RH

±2~3% RH

測定解像度

温度: 1°C, 湿度: 1% RH

温度: 0.1°C, 湿度: 0.1% RH

測定周期(サンプリング間隔)

1秒以上

2秒以上

データ転送速度

低速

低速

サイズ

小型

やや大きい

価格

安価

DHT-11より高価

使用電圧

3 ~ 5V

3 ~ 5V

誤差範囲が大きすぎるとデータを信頼できないため、誤差がやや少ないDHT-22を使用することにした。

これよりも正確な温度を得たい場合はPT-100温度計を使えばよいが、そこまでの必要ないようだ。

4. CH340ドライバのインストール

Arduino ESP32で温湿度データを収集する-7

上の写真で赤い丸の中にチップが一つ挿さっているのが見える。

これは中国で製造されているCH340というチップセットで、コンピュータでいうとCPUに相当すると考えればよい。

CH340チップのドライバを提供している公式サイトのリンクを載せる。

ダウンロードして何も考えずに次に進んでインストールしよう。

このファイルには以下のすべてのチップを含むドライバが入っている。

ちなみにMacBookではこのチップセットのドライバをデフォルトで提供しているのでインストールする必要はない。

CH340G,CH340T,CH340C,CH340N, CH340K, CH340E,CH340B,CH341A,CH341F, CH341T,CH341B,CH341C,CH341U

5. Arduino IDEボードマネージャー設定

次にArduino IDEにボードマネージャーをセットアップしよう。

Arduino IDEでFile > Preferences(基本設定)に入る。

Arduino ESP32で温湿度データを収集する-8

そして追加ボードマネージャーURLに下記のアドレスをコピーして入力する。

https://espressif.github.io/arduino-esp32/package_esp32_index.json
Arduino ESP32で温湿度データを収集する-9Arduino ESP32で温湿度データを収集する-10

そしてボードマネージャーでESP32を検索し、提供者がEspressif Systemsであることを確認してインストールする。

Arduino ESP32で温湿度データを収集する-11

それからUSBポートにArduinoを接続するとポートが自動的に認識される。

このポートに対応するArduinoボードを選んで選択すればよい。

Arduino ESP32で温湿度データを収集する-12

6. WiFi接続

そして簡単な例を一つアップロードしてみよう。

ファイル -> 例 -> HttpClient -> BasicHttpsClientをクリックするとHttpリクエストの例が出てくる。

Arduino ESP32で温湿度データを収集する-13

この例のSSID、PASSWORD部分だけ変更する。

void setup() {

 USE_SERIAL.begin(115200);

 USE_SERIAL.println();
 USE_SERIAL.println();
 USE_SERIAL.println();

 for (uint8_t t = 4; t > 0; t--) {
 USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
 USE_SERIAL.flush();
 delay(1000);
 }
// 下のSSIDにWiFi名、PASSWORDにパスワードを入力
 wifiMulti.addAP("SSID", "PASSWORD");
}

もしアップロードに失敗した場合はアップロード速度を調整しよう。

ツール -> Upload Speedを少し低い値に変更すると安定する。

Arduino ESP32で温湿度データを収集する-14

そしてそのまま例のサイトにアクセスするとシリアルモニターでhtmlを表示する。

これだけで1/3くらいは完成したことになる。

Arduino ESP32で温湿度データを収集する-15

7. DHT-22センサー接続

次にArduinoにDHT-22センサーを接続し、温湿度値を取得してみよう。

まずライブラリを探してインストールする。

dht センサー ライブラリを検索し、adafruit製のライブラリを取得しよう。

Arduino ESP32で温湿度データを収集する-16

次にファイル->例に入り、温湿度計の例がある。

この例の中からセンサーテストを一度やってみよう。

コメントを除くと核心は以下の通り。

Arduino ESP32で温湿度データを収集する-17
#include "DHT.h"

#define DHTPIN 4 // ピン番号指定
#define DHTTYPE DHT22 // DHT 22 
DHT dht(DHTPIN, DHTTYPE);

void setup() {
 Serial.begin(115200); // シリアル通信速度。115200に変更
 Serial.println(F("DHTxx test!"));
 dht.begin();
}

void loop() {
 delay(2000);
 float h = dht.readHumidity();
 float t = dht.readTemperature();
 float f = dht.readTemperature(true); // trueを入れると華氏になる

 if (isnan(h) || isnan(t) || isnan(f)) {
 Serial.println(F("Failed to read from DHT sensor!"));
 return;
 }

 float hif = dht.computeHeatIndex(f, h); // これは体感温度
 float hic = dht.computeHeatIndex(t, h, false);

 Serial.print(F("Humidity: "));
 Serial.print(h);
 Serial.print(F("% Temperature: "));
 Serial.print(t);
 Serial.print(F("°C "));
 Serial.print(f);
 Serial.print(F("°F Heat index: "));
 Serial.print(hic);
 Serial.print(F("°C "));
 Serial.print(hif);
 Serial.println(F("°F"));
}

このようにArduinoに送信した後、温度が出力されるのをシリアルモニターで確認する。

一度口で吹いたら湿度が100%まで上昇した。

Arduino ESP32で温湿度データを収集する-18

これでArduino WiFi接続とセンサー接続が解決したので、Googleスプレッドシートの設定に進もう。

8. Googleスプレッドシートの設定

できれば私が書くところだが、Googleスプレッドシートの設定だけで長くなるので、以前書いた記事を添付する。

以下のリンクから一度確認してほしい。

9. ArduinoからGetリクエストを送る

これでGoogleスプレッドシートの設定が終わったら、ArduinoからGETリクエストを送る番だ。

上記のWiFi接続で使用した例を持ってくる。

ここでリクエストアドレスをGoogleスクリプトに変更すればよい。

中間部分は省略して掲載する。

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <NetworkClientSecure.h>

...

String host = "https://script.google.com/";
String googleScriptID = "私のGoogleスクリプトID";
String scriptUrl = "macros/s/"+googleScriptID+"/exec";
String queryString = "?value1='こんにちは'&value2='テスト中!'";
String getReqUrl = host + scriptUrl + queryString;

void setup() {
 
 ...

 WiFiMulti.addAP("WiFi名", "WiFiパスワード");

 ...
}

void loop() {
 NetworkClientSecure *client = new NetworkClientSecure;
 if (client) {
 client->setCACert(rootCACertificate);
 {
 HTTPClient https;
 Serial.print("[HTTPS] begin...\n");
 if (https.begin(*client, getReqUrl)) { // <--- この部分だけ修正すれば良い
 
 ...

 }
 }}
}

こうするとスプレッドシートに値が入るのがわかる。

最後のステップはDHT-22のデータを受け取って送信することである。

Arduino ESP32で温湿度データを収集する-20

10. コードを合体

Arduino ESP32で温湿度データを収集する-21

これらのコードを統合しよう。

統合が難しい場合は、無作為にAIに任せる方法もおすすめだ。

まず私はDHT-22のループコードを変更してWeatherという構造体を返す関数を作った。

#include "DHT.h"

#define DHTPIN 4   
#define DHTTYPE DHT22   

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
}

struct WeatherData {
  float humi;
  float temp;
  float heat;
  bool valid;
};

WeatherData getWeather() {
  WeatherData data;
  data.humi = dht.readHumidity();
  data.temp = dht.readTemperature();

  if (isnan(data.humi) || isnan(data.temp)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    data.valid = false;
    return data;
  }
  data.valid = true;
  data.heat = dht.computeHeatIndex(data.temp, data.humi, false);

  Serial.print(F("Humidity: "));
  Serial.print(data.humi);
  Serial.print(F("%  Temperature: "));
  Serial.print(data.temp);
  Serial.print(F("°C "));
  Serial.print(F("°Heat index: "));
  Serial.print(data.heat);
  Serial.print(F("°C "));
  return data;
}

ここで必要なものを適切に配分してhttpsClientコードに統合する。

さあ、統合してみよう。

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <NetworkClientSecure.h>
#include "DHT.h"

...
認証情報は省略
...

void setClock() {
  ...
}

#define DHTPIN 4   
#define DHTTYPE DHT22   

WiFiMulti WiFiMulti;
DHT dht(DHTPIN, DHTTYPE);
char* SSID = "WiFi名";
char* PASSWORD = "WiFiパスワード";
String host = "https://script.google.com/";
String googleScriptID = "私のGoogleスクリプトID";
String scriptUrl = "macros/s/"+googleScriptID+"/exec";

struct WeatherData {
  ...
};

WeatherData getWeather(); //エラー発生で事前に宣言


void setup() {
  dht.begin();
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP(SSID, PASSWORD);
  Serial.print(F("Waiting for WiFi to connect..."));
  while ((WiFiMulti.run() != WL_CONNECTED)) {
    Serial.print(F("."));
  }
  Serial.println(F(" connected"));
  setClock();
}

WeatherData getWeather() {
    ...
}


void loop() {
  NetworkClientSecure *client = new NetworkClientSecure;
  if (client) {
    client->setCACert(rootCACertificate);
    {
      HTTPClient https;
      WeatherData data = getWeather();
      if (!data.valid){
        Serial.println(F("天気情報を取得できませんでした。"));
        Serial.println("次ラウンド前に10秒待機...");
        delay(10000);
        return;
      };
      Serial.print("[HTTPS] begin...\n");
      String queryString = "?value1=" + String(data.humi) + "&value2=" + String(data.temp) ;
      String getReqUrl = host + scriptUrl + queryString;
      if (https.begin(*client, getReqUrl)) {  // HTTPS
        Serial.print("[HTTPS] GET...\n");

        int httpCode = https.GET();

        if (httpCode > 0) {
          Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
        } else {
          Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
        }
        https.end();
      } else {
        Serial.printf("[HTTPS] Unable to connect\n");
      }
    }
    delete client;
  } else {
    Serial.println("Unable to create client");
  }
  Serial.println();
  Serial.println("次ラウンド前に10秒待機...");
  delay(10000);
}

このようにした後、シリアルモニターで湿度、温度が表示されてGETリクエストコードが200と表示されたら成功だ。

スプレッドシートに入り、確認すればよい。

Arduino ESP32で温湿度データを収集する-22

11. 追加作業

さらに体感温度も記録したい場合は、Googleスクリプトを修正すればよい。

パラメータを解析する部分で変数を追加したり、変数名を変更したりできる。

...
for (var param in e.parameter) {
  Logger.log('In for loop, param=' + param);
  var value = stripQuotes(e.parameter[param]);
  Logger.log(param + ':' + e.parameter[param]);
  switch (param) {
    case 'humi':
    rowData[2] = value; // value1 in column C
    result = '湿度が記録されました'; 
    break;
    case 'temp':
    rowData[3] = value; // Humidity in column D
    result += ', 温度が記録されました'; 
    break;
    case 'heat':
    rowData[4] = value;
    result += ", 体感温度が記録されました";
    break

    default:
    result = "サポートされていないパラメータです。";
  }
...

もちろん、こうしておくとArduinoコードでもクエリ文字列を変更する必要がある。

結局、個人プロジェクトなのでこうするのは今後の保守のためか、個人の趣味のようだ。

12. 感想

過去に学生たちと実験をしたときは以下のようなデータが出てきた。

途中のデータ欠損は夜に電源が遮断されたことで発生したもの...

しかし、簡単な装置を作っておけばこのように自動でデータを収集してくれるので、これを私たちは分析するだけで済むという点では非常に良い。

Arduino ESP32で温湿度データを収集する-23

出来上がった結果物だけ見ると内容がないように見えるが、解説し始めると文章がとても長くなった。

16+1授業で前の3時間はC言語を、後ろの2時間はArduino温湿度計を、残りの時間は個人プロジェクトを進める予定だが時間が足りないのではないかと心配している。

何とかして一生懸命準備した授業が無事終了し、夏休みを迎えたいです。

댓글을 불러오는 중...