← До всіх проєктів
Сенсори Початковий

Міні-метеостанція: температура й вологість DHT22 у браузері

Датчик DHT22 + ESP32 = жива сторінка з показами, яка оновлюється кожні 5 секунд без перезавантаження. Плюс JSON-API для інших пристроїв.

Складність
Початковий
Час
1–2 h
Категорія
Сенсори

Ідея

ESP32 кожні кілька секунд опитує датчик DHT22 і віддає дві адреси:

  • / — гарна сторінка-дашборд з великими цифрами;
  • /data — JSON на кшталт {"t":22.4,"h":48.0}, який можна забирати з Home Assistant, Node-RED чи скрипта.

Сторінка сама підтягує нові дані через fetch(), тому перезавантажувати її не треба.

Компоненти

  • ESP32 DevKit
  • Датчик DHT22 (AM2302) — точніший за DHT11 (±0.5 °C, 0–100 % RH)
  • Резистор 10 кОм (не потрібен, якщо DHT22 уже на платі-модулі з трьома виводами)
  • Макетна плата, дроти

Підключення

DHT22 ESP32
VCC (1) 3V3
DATA (2) GPIO 4 + підтяжка 10 кОм до 3V3
NC (3) —
GND (4) GND

Бібліотеки

У Library Manager встановіть:

  • DHT sensor library (Adafruit)
  • Adafruit Unified Sensor (підтягнеться як залежність)

Код

#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>

#define DHT_PIN  4
#define DHT_TYPE DHT22

const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASS = "YOUR_PASSWORD";

DHT dht(DHT_PIN, DHT_TYPE);
WebServer server(80);

float temperature = NAN;
float humidity = NAN;
unsigned long lastRead = 0;

const char PAGE[] = R"rawliteral(
<!doctype html><html><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ESP32 Weather</title>
<style>
  body{font-family:system-ui;background:#0f1720;color:#e8eef3;display:grid;place-items:center;min-height:100vh;margin:0}
  .box{display:flex;gap:48px;text-align:center}
  .v{font-size:3.5rem;font-weight:700}.l{opacity:.7}
</style></head><body>
<div class="box">
  <div><div class="v" id="t">--</div><div class="l">°C</div></div>
  <div><div class="v" id="h">--</div><div class="l">% RH</div></div>
</div>
<script>
async function update() {
  const d = await (await fetch('/data')).json();
  document.getElementById('t').textContent = d.t === null ? '--' : d.t.toFixed(1);
  document.getElementById('h').textContent = d.h === null ? '--' : d.h.toFixed(0);
}
update();
setInterval(update, 5000);
</script></body></html>
)rawliteral";

String jsonNumber(float v) {
  return isnan(v) ? String("null") : String(v, 1);
}

void readSensor() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (!isnan(t) && !isnan(h)) {
    temperature = t;
    humidity = h;
  } else {
    Serial.println("DHT read failed");
  }
}

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

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.println(WiFi.localIP());

  server.on("/", [] { server.send(200, "text/html", PAGE); });
  server.on("/data", [] {
    String json = "{\"t\":" + jsonNumber(temperature) + ",\"h\":" + jsonNumber(humidity) + "}";
    server.send(200, "application/json", json);
  });
  server.begin();
}

void loop() {
  server.handleClient();
  // DHT22 не можна опитувати частіше ніж раз на 2 секунди
  if (millis() - lastRead > 2500) {
    lastRead = millis();
    readSensor();
  }
}

Нюанси

  • Не блокуйте loop(): читання датчика винесене в неблокуючий таймер на millis(), тож сервер відповідає миттєво.
  • Якщо бачите DHT read failed — перевірте підтяжку 10 кОм і що живлення саме 3.3 В.
  • Не кладіть датчик поруч із платою: ESP32 гріється на 3–5 °C і завищує покази.

Ідеї для розвитку

  • Замініть DHT22 на BME280 (I²C) — отримаєте ще й атмосферний тиск.
  • Зберігайте історію в кільцевому буфері й малюйте графік на сторінці (Chart.js).
  • Додайте OLED-дисплей з проєкту «Годинник NTP» — і станція працюватиме без телефона.