はじめに
今年の夏は連日37℃とか38℃とかの酷暑だったので、こりゃ我が家の温度を測ってみなくてはと思って、8月にESP32-DevKitC-32E で温湿度ログを作ってみました。
使ったもの
- ESP32-DevKitC-32E
- DHT22 温湿度センサー
配線図
いたってシンプル。これ以上ないくらいシンプル。
ちなみに、DHT22の極性を間違えると一発で死にます(当たり前)。それ以前に使っていたDHT11のセンサーモジュールと逆になっていたのに気が付かずに、以前ひとつ犠牲にしました。気を付けましょう。
プログラム(ESP32側)
ライブラリは DHT22 ライブラリを使用。Arduino IDE のライブラリマネージャーからも「DHT22」で検索できます。
github.com
Wi-Fi部分は、こちらを参考にさせていただきました。
garretlab.web.fc2.com
ただし今回は、測定後に10分間のディープスリープに入るようにしたので、すべてsetup関数内で完結しています。
#include <Arduino.h> #include <DHT22.h> #include <WiFi.h> // 温湿度センサーのピン設定 #define DHT_PIN 13 // WiFi接続情報 const char* ssid = "*****"; const char* password = "*****"; // Webサーバ const char* host = "*****"; // 温湿度センサ DHT22 dht(DHT_PIN); void setup() { // 変数宣言 float temperature; // 温度測定値 float humidity; // 湿度測定値 char stemp[10],shumi[10]; // 温湿度格納文字列 char path[255]; // URLのパス部分(引数付)格納文字列 char strRequest[1024]; // リクエスト文字列 // 初期設定 Serial.begin(115200); pinMode(32, OUTPUT); delay(10); // WiFiに接続 Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); // 温湿度取得 humidity = dht.getHumidity(); temperature = dht.getTemperature(); // 文字列に変換 dtostrf(humidity,1,2,shumi); dtostrf(temperature,1,2,stemp); // URLパスを作成 sprintf(path,"/iot/logTempHumi.cgi?date=0&temp=%s&humi=%s", stemp, shumi); // デバッグ用 Serial.print(path); // サーバに接続 Serial.print("connecting to "); Serial.println(host); WiFiClient client; if (!client.connect(host, 80)) { Serial.println("connection failed"); return; } // リクエスト送信 sprintf (strRequest, "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, host); client.print(strRequest); // 一定時間レスポンスがなければタイムアウト. unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { Serial.println(">>> Client Timeout !"); client.stop(); return; } } // レスポンスを表示. Serial.println("Response Begin"); while(client.available()) { String line = client.readStringUntil('\r'); Serial.print(line); } Serial.println("Response End"); // 切断 Serial.println(); Serial.println("close connection"); client.stop(); // ディープスリープ esp_sleep_enable_timer_wakeup(1000000 * 60 * 10 - millis() * 1000 + 3049000); esp_deep_sleep_start(); } void loop() { }
最後の部分でディープスリープに入りますが、10分の間隔といっても、10分のインターバルではこのプログラムの実行時間分オーバーして、累積でどんどんずれてしまうので、その分をインターバルから引いています。millies()関数で調整している部分ですね。更にそれでも実際に動かしてみると3秒ほど早く再起動されるので、12時間=72回分測定して10分との誤差の平均を算出した補正値 3049ms(=3049000μs)を足しています。なぜずれるんだろう。内蔵時計の精度、そんなに悪いの?
プログラム(Webサーバ側)
Webサーバ側は、ちょっと都合あって Perlで記述。GETの引数でdate、temp、humiで、それぞれ日時、温度、湿度を取得してファイルに追記します。
dateが0の時にはWebサーバ側の現在日時を使用。最初はリアルタイムクロックモジュールで割り込みかけて、ESP32側から日時も送ろうかと思って、このようにしたのですが、そこまでの精度はいらないやと方針変更したため、サーバ側の時刻でも動くようにしました。
#!/usr/bin/perl use CGI; # GET パラメータを取得 my $q = new CGI; # 各値を取得 my $p_date = $q->param('date'); my $p_temp = $q->param('temp'); my $p_humi = $q->param('humi'); # 日時が0の時には、サーバ側の現在時刻を使用 if (p_date == 0) { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime; $year += 1900; $mon++; $p_date = sprintf "%04d/%02d/%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec; } #ファイルを開く open(LOG, ">>log.txt"); #データ書き出し my $outStr = sprintf "%s,%s,%s\n", $p_date, $p_temp, $p_humi; print LOG $outStr; #ファイルを閉じる close (LOG); print "Content-type: text/html\n\n"; print "<html>"; print "<head>"; print "</head>"; print "<body>"; print "OK"; print "</body>"; print "</html>";
これを logTempHumi.cgi とかの名前にしてWebサーバ上に置けばOK。log.txt にどんどん追記されます。最後はとってつけたようにOKだけ返しています。
これでUSB電源に繋いで動作を確認しました。