背景
うちはメゾネットタイプの家なんですが、夏は異常に暑い。
いまあるものを使って、IoTっぽい何かを作ってみよう。
家にあったもの:
・マイコン:ESP32
・温湿度計:DHT11
・OLCD:SSD1306
・赤外線LED
概要
・温湿度センサ(DHT11)で、部屋の温度/湿度を読み取り、暑すぎる場合は自動で部屋を快適温度に設定してくれる。(せっかくなら自分好みにカスタマイズできること)
・エアコンへの指示内容は、スマホに通知する(Wifi、LINEなど)
・現在の温度、湿度、指示状況はLCDに表示する。
・温湿度の推移はスマホでグラフになって確認できる。
設計
Mainが全体を制御するメイン部で、
緑色の枠が直接マイコンの機能や、センサにアクセスするような末端の部品というイメージ。
黄色枠は判断ができる高級な部品群イメージ。
本記事ではWifiとOLED、DHT11の部品だけ作ってみた。
作るといっても、いい感じのライブラリが用意されていて、Arduino IDEのツールでライブラリをインストールしておけば簡単に使うことができる。
・スケッチ→ライブラリをインクルード→ライブラリマネージャ
ここで使いたいライブラリを検索してインストールボタンを押すだけで、あとはインクルード文を記載すれば使うことができる。
まだ判断部が全然できてないので、もう少し変えるかも。
Wifi
時間を正確に計測するにはWifi経由でとってくるのが楽なので、Wifiクラスに時間系も入れた。
初期化と、Wifi経由の時間取得、1h間隔を知るためのメソッドを用意した。
Wifi接続はなぜか全然つながらなくて、色々調べるとリトライ処理を入れないとなかなかつながらないことがわかった。
#include <WiFi.h>
#include <time.h>
#define JST 3600* 9
const char* ssid = "xxx";
const char* password = "yyy";
void wifi_Init()
{
//Wifi
bool done = true;
WiFi.begin(ssid, password);
while (done) {
Serial.print("WiFi connecting");
auto last = millis();
while (WiFi.status() != WL_CONNECTED && last + 1000 > millis()) {
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
done = false;
} else {
Serial.println("retry");
WiFi.disconnect();
WiFi.reconnect();
}
}
Serial.println();
Serial.printf("Connected, IP address: ");
Serial.println(WiFi.localIP());
configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
}
void wifi_time(char* t_time) {
time_t t;
struct tm *tm;
static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
t = time(NULL);
tm = localtime(&t);
sprintf(t_time , " %04d/%02d/%02d(%s) %02d:%02d:%02d\n",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
wd[tm->tm_wday],
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
//return1なら1hのタイミング
int time_judge(int* hour){
int ret=0;
time_t t;
struct tm *tm;
t = time(NULL);
tm = localtime(&t);
if (tm->tm_min == 0x0){
ret == 1;
}else{
ret == 0;
}
if (ret == 1){
*hour = tm->tm_hour;
}
return ret;
}
OLED
ディスプレイ表示用の部品。
初期化と、フォントサイズ毎の表示用メソッドを用意。
#include <Wire.h>
#include "SSD1306Wire.h"
void OLED_Display_Init()
{
//初期化する
display.init();
//バッファをクリア
display.clear();
}
void OLED_Display_10(int x, int y, char* c) {
display.setFont(ArialMT_Plain_10);
display.drawString(x,y,c);
display.display();
}
void OLED_Display_16(int x, int y, char* c) {
display.setFont(ArialMT_Plain_16);
display.drawString(x,y,c);
display.display();
}
void OLED_Display_clear(){
display.clear();
}
DHT11
DHT11は温湿度センサだが、結構誤差があるらしい。。
ここが信じられないとシステムが信用できなくなるが、まあ細かいことは良しとする。
heatIndexという体感温度も取得できるらしいが、使い方がよくわからないので使わない。
初期化と温湿度を取得する関数のみ用意した。
PINはどこでも良いが26を使った。たまたまGPIO12を使うと起動しなくなるという問題があって少し困ったが、すぐ解決した。
いったんデバッグ用にシリアル通信させている。
#include <DHT.h> // DHT ライブラリのインクルード
#define DHT_MODEL DHT11 // 接続するセンサの型番を定義する(DHT11やDHT22など)
#define DHT_PIN 26
DHT dht(DHT_PIN, DHT_MODEL); // センサーの初期化
// セットアップ
void DHT11_Init() {
dht.begin(); // センサーの動作開始
}
// ループ
void DHT11_GetInfo(float* Humidity, float* Temperature){
float Hum = dht.readHumidity(); // 湿度の読み取り
float Temp = dht.readTemperature(); // 温度の読み取り(摂氏)
// float heatIndex = dht.computeHeatIndex(Temperature, Humidity, false);
// 温度を出力
Serial.print("温度: ");
Serial.print(Temp, 1); // 小数点1桁まで
Serial.print("[℃]");
// 湿度を出力
Serial.print(" 湿度: ");
Serial.print(Hum, 1); // 小数点1桁まで
Serial.println("[%]");
*(Humidity) = Hum;
*(Temperature) = Temp;
}
メイン(途中、デバッグ版)
とりあえず10sに一回温度と湿度を計測して表示するだけにしてみた。
#include "SSD1306Wire.h"
void setup() {
Serial.begin(115200); // シリアル通信の開始
OLED_Display_Init();
wifi_Init();
DHT11_Init();
}
void loop() {
static int pre_hour;
int hour;
int judge_res;
char time[30];
float Humidity;
float Temperature;
char hum_buf[10]={0};
char temp_buf[10]={0};
delay(10000);
OLED_Display_clear();
//時間取得
wifi_time(time);
//時間表示
OLED_Display_10(10, 10, time);
//温度と湿度を取得
DHT11_GetInfo(&Humidity, &Temperature);
//温度と湿度を表示
sprintf(hum_buf, "hum:%4.1f", Humidity);
sprintf(temp_buf, "temp:%4.1f[C]", Temperature);
OLED_Display_16(10, 30, hum_buf);
OLED_Display_16(10, 45, temp_buf);
}
ここまでの動作結果
PCで確認したシリアル通信結果
初期化でWifi接続が成功してIPアドレスが表示できています。
温度と湿度が通信できています。
19:51:46.587 ->
19:51:46.587 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
19:51:46.587 -> configsip: 0, SPIWP:0xee
19:51:46.587 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
19:51:46.587 -> mode:DIO, clock div:1
19:51:46.587 -> load:0x3fff0018,len:4
19:51:46.587 -> load:0x3fff001c,len:1216
19:51:46.587 -> ho 0 tail 12 room 4
19:51:46.587 -> load:0x40078000,len:10944
19:51:46.587 -> load:0x40080400,len:6388
19:51:46.587 -> entry 0x400806b4
19:51:46.962 -> WiFi connecting.....
19:51:49.475 -> Connected, IP address: 100.64.1.38
19:51:59.499 -> 温度: 32.6[℃] 湿度: 47.0[%]
右上の青いのがDHT11です。
Wifi経由で取得した時間と、
温度、湿度がLCDに表示できてます。
暑いけど、さすがに32度はないと思います。
DHT11の誤差を調べると5度くらいは誤差ありそうです。
一応クーラー入れてるので、体感は26度くらいです。
トラブル
今回起きたトラブルはどれも過去に先人が解決したことのあるトラブルだったので、同様に対応すれば解決できた。なんでも誰かが先にやってるもんですね。
- GPIO12を使うと正常にBOOTが動作しないときがある
- Wifiがなかなか接続されない