今日はArduino ESP32で温湿度を測定し、データを送信するWiFi百葉箱を作ってみる。
この内容は学校で行われる16+1授業の原稿を基にして書いた文章である。
1. 準備物
準備物は簡単だ。
ESP32, DHT-22, 電線3本
まずESP32を簡単に説明すると、WiFiモジュールが内蔵されたArduinoである。
しかし、サイズは一般的なArduinoよりもはるかに小さい。
2. ESP32ピンマップ

おや?ピン番号が少しおかしいかな?
これは以前の記事でも説明したが、WiFiモジュールが入ることでピンマッピングが変更されたためだ。
以下にESP32 Arduinoのピンマッピングを示す。
それでも、この子はGPIOピン番号とピン名がほぼ一致しているようだ。
以下のピンのうち安全なD4ピンを利用してDHT-22を動かしてみる予定だ。

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出力可能 |
D6–D11 | 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) |
|---|---|---|
外観 | ![]() | ![]() |
温度測定範囲 | 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ドライバのインストール

上の写真で赤い丸の中にチップが一つ挿さっているのが見える。
これは中国で製造されているCH340というチップセットで、コンピュータでいうとCPUに相当すると考えればよい。
CH340チップのドライバを提供している公式サイトのリンクを載せる。
ダウンロードして何も考えずに次に進んでインストールしよう。
このファイルには以下のすべてのチップを含むドライバが入っている。
ちなみにMacBookではこのチップセットのドライバをデフォルトで提供しているのでインストールする必要はない。
CH340G,CH340T,CH340C,CH340N, CH340K, CH340E,CH340B,CH341A,CH341F, CH341T,CH341B,CH341C,CH341U5. Arduino IDEボードマネージャー設定
次にArduino IDEにボードマネージャーをセットアップしよう。
Arduino IDEでFile > Preferences(基本設定)に入る。

そして追加ボードマネージャーURLに下記のアドレスをコピーして入力する。
https://espressif.github.io/arduino-esp32/package_esp32_index.json

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

それからUSBポートにArduinoを接続するとポートが自動的に認識される。
このポートに対応するArduinoボードを選んで選択すればよい。

6. WiFi接続
そして簡単な例を一つアップロードしてみよう。
ファイル -> 例 -> HttpClient -> BasicHttpsClientをクリックするとHttpリクエストの例が出てくる。

この例の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を少し低い値に変更すると安定する。

そしてそのまま例のサイトにアクセスするとシリアルモニターでhtmlを表示する。
これだけで1/3くらいは完成したことになる。

7. DHT-22センサー接続
次にArduinoにDHT-22センサーを接続し、温湿度値を取得してみよう。
まずライブラリを探してインストールする。
dht センサー ライブラリを検索し、adafruit製のライブラリを取得しよう。

次にファイル->例に入り、温湿度計の例がある。
この例の中からセンサーテストを一度やってみよう。
コメントを除くと核心は以下の通り。

#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 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のデータを受け取って送信することである。

10. コードを合体

これらのコードを統合しよう。
統合が難しい場合は、無作為に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と表示されたら成功だ。
スプレッドシートに入り、確認すればよい。

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. 感想
過去に学生たちと実験をしたときは以下のようなデータが出てきた。
途中のデータ欠損は夜に電源が遮断されたことで発生したもの...
しかし、簡単な装置を作っておけばこのように自動でデータを収集してくれるので、これを私たちは分析するだけで済むという点では非常に良い。

出来上がった結果物だけ見ると内容がないように見えるが、解説し始めると文章がとても長くなった。
16+1授業で前の3時間はC言語を、後ろの2時間はArduino温湿度計を、残りの時間は個人プロジェクトを進める予定だが時間が足りないのではないかと心配している。
何とかして一生懸命準備した授業が無事終了し、夏休みを迎えたいです。




댓글을 불러오는 중...