Stație meteo cu ESP32 și web server - temperatură și umiditate accesibile din orice browser

Stație meteo cu ESP32 și web server - temperatură și umiditate accesibile din orice browser

ESP32 este alegerea numărul unu pentru proiecte IoT care au nevoie de WiFi rapid, BLE și putere de calcul reală - dual-core la 240 MHz, 520 KB RAM, plus un coprocesor ULP pentru sarcini low-power. Față de ESP8266 (predecesorul), are mai multă memorie, mai mulți pini și suport nativ pentru servere web asincrone, ceea ce face diferența când vrei să servești pagini multiple sau să gestionezi zeci de conexiuni simultan.

În acest ghid folosești toate aceste avantaje într-un proiect concret: o mini-stație meteo care citește temperatura și umiditatea de la un senzor DHT22 și le publică pe o pagină web. Pagina se autoreîmprospătează din 10 în 10 secunde, fără reload manual, și e accesibilă din telefon, laptop sau orice device din aceeași rețea WiFi.

Ce vei construi

  • Un server web pe ESP32 care răspunde pe IP-ul local din rețeaua ta.
  • O pagină HTML curată cu două valori live: temperatură (°C) și umiditate (%).
  • Auto-refresh prin JavaScript cu XMLHttpRequest - cere doar valorile noi, nu reîncarcă toată pagina.
  • Server asincron (ESPAsyncWebServer), care nu blochează loop-ul chiar dacă ai mai mulți clienți conectați simultan.

Interfața web servită de ESP32 cu temperatură și umiditate

Lista de componente

Componentă Detalii
Placă ESP32 WROOM-32D Microcontroler dual-core cu WiFi 2.4 GHz și Bluetooth
Senzor DHT22 (sau DHT11) Temperatură și umiditate pe un singur fir digital
Rezistență 4.7 kΩ Pull-up pentru linia de date (nu e necesară dacă senzorul vine pe modul)
Breadboard + fire jumper Prototipare
Cablu micro-USB Alimentare și programare

DHT22 e mai precis (±0.5°C, ±2% RH) decât DHT11 și are domeniu mai larg. Diferența de preț e mică, recomand DHT22.

De ce ESP32 pentru un web server

Un web server are nevoie de două lucruri: stack TCP/IP funcțional și capacitate de a procesa cereri HTTP fără să blocheze restul logicii. ESP32 le are pe ambele integrate:

  • WiFi nativ - nu ai nevoie de shield extern; te conectezi direct la rețeaua casei.
  • Două nuclee - unul poate gestiona WiFi-ul, celălalt logica aplicației tale.
  • Bibliotecă ESPAsyncWebServer - permite gestionarea cererilor în paralel, fără cozi de așteptare.
  • Memorie suficientă pentru a stoca pagini HTML și CSS direct în PROGMEM, fără card SD.

Schema de conexiuni

DHT22 → ESP32

Pin DHT22 Pin ESP32
VCC 3.3V
DATA GPIO 27
GND GND

Dacă folosești DHT22 ca senzor „gol" (4 pini), trebuie să adaugi rezistența de pull-up 4.7 kΩ între VCC și pinul DATA. Dacă ai un modul (3 pini, deja cu PCB), pull-up-ul e deja integrat.

Schema cablaj ESP32 cu DHT22 pe breadboard

Biblioteci necesare

Din Library Manager (Sketch → Include Library → Manage Libraries):

  • DHT sensor library (Adafruit)
  • Adafruit Unified Sensor

Următoarele două trebuie descărcate manual de pe GitHub (caută în Google după nume și descarcă ZIP-ul, apoi Sketch → Include Library → Add .ZIP Library):

  • ESPAsyncWebServer (de la me-no-dev)
  • AsyncTCP (de la me-no-dev)

În plus, asigură-te că ai instalat suportul ESP32 în Arduino IDE (din Boards Manager).

Codul sursă

Codul are trei părți: cititul senzorului, pagina HTML servită și logica serverului async. Înainte de upload, înlocuiește SSID și PASSWORD cu datele rețelei tale WiFi.

// Stație meteo ESP32 + DHT22 cu web server
// Adaptat dupa: randomnerdtutorials.com (link in finalul articolului)

#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include <Adafruit_Sensor.h>
#include <DHT.h>

const char* ssid = "NUMELE_RETELEI_TALE";
const char* password = "PAROLA_TA";

#define DHTPIN 27
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
AsyncWebServer server(80);

String readDHTTemperature() {
  float t = dht.readTemperature();
  if (isnan(t)) { Serial.println("DHT citire esuata!"); return "--"; }
  return String(t);
}

String readDHTHumidity() {
  float h = dht.readHumidity();
  if (isnan(h)) { Serial.println("DHT citire esuata!"); return "--"; }
  return String(h);
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html { font-family: Arial; text-align: center; }
    h2 { font-size: 3rem; }
    p { font-size: 3rem; }
    .units { font-size: 1.2rem; }
    .dht-labels { font-size: 1.5rem; }
  </style>
</head>
<body>
  <h2>Stație meteo ESP32</h2>
  <p><span class="dht-labels">Temperatura</span>
     <span id="temperature">%TEMPERATURE%</span><sup class="units">°C</sup></p>
  <p><span class="dht-labels">Umiditate</span>
     <span id="humidity">%HUMIDITY%</span><sup class="units">%</sup></p>
</body>
<script>
setInterval(function() {
  var x = new XMLHttpRequest();
  x.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200)
      document.getElementById("temperature").innerHTML = this.responseText;
  };
  x.open("GET", "/temperature", true); x.send();
}, 10000);
setInterval(function() {
  var x = new XMLHttpRequest();
  x.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200)
      document.getElementById("humidity").innerHTML = this.responseText;
  };
  x.open("GET", "/humidity", true); x.send();
}, 10000);
</script>
</html>)rawliteral";

String processor(const String& var){
  if (var == "TEMPERATURE") return readDHTTemperature();
  if (var == "HUMIDITY")    return readDHTHumidity();
  return String();
}

void setup(){
  Serial.begin(115200);
  dht.begin();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000); Serial.println("Conectare WiFi...");
  }
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHTTemperature().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHTHumidity().c_str());
  });
  server.begin();
}

void loop(){}

Cum funcționează partea de web server

Logica are trei piese care lucrează împreună:

  1. Pagina HTML e stocată în PROGMEM (memorie flash) ca șablon cu placeholdere %TEMPERATURE% și %HUMIDITY%. La prima cerere, funcția processor() înlocuiește placeholdere-le cu valorile actuale.
  2. JavaScript-ul din pagină pornește două timere care la fiecare 10 secunde trimit cereri AJAX către /temperature și /humidity. Răspunsurile sunt simple stringuri (ex: „24.3") și înlocuiesc direct conținutul span-urilor din pagină.
  3. Serverul async are trei handlere - unul pentru rădăcină (servește pagina), două pentru endpoint-urile de date. Fiecare răspunde imediat, nu blochează loop-ul.

Rezultatul: o pagină care se simte „live" fără reload, cu trafic minim între ESP32 și browser.

Pași de implementare

  1. Conectează DHT22 la ESP32 conform tabelului. Verifică direcția pinilor pe senzor.
  2. Conectează ESP32 la PC prin USB.
  3. În Arduino IDE selectează Tools → Board → ESP32 Dev Module și COM-portul corect.
  4. Instalează cele 4 biblioteci (două din Library Manager, două din ZIP).
  5. În cod, înlocuiește NUMELE_RETELEI_TALE și PAROLA_TA cu datele tale WiFi.
  6. Apasă Upload. Dacă upload-ul rămâne blocat pe „Connecting...", ține apăsat butonul BOOT de pe ESP32 până începe transferul.
  7. Deschide Serial Monitor la 115200 baud. După conectare la WiFi vei vedea IP-ul local al ESP32 (ex: 192.168.1.123).
  8. Deschide acel IP în browser de pe orice device din aceeași rețea. Vei vedea pagina cu temperatură și umiditate.

Serial Monitor afisand IP-ul ESP32 dupa conectare WiFi

Idei de upgrade

  • IP fix prin DHCP reservation - din routerul tău, leagă MAC-ul ESP32 de un IP fix. Așa nu mai trebuie să verifici de fiecare dată IP-ul în Serial Monitor.
  • mDNS (Bonjour/Avahi) - cu librăria ESPmDNS poți accesa stația ca http://meteo.local în loc de IP. Funcționează pe macOS și Linux out-of-the-box, pe Windows necesită Bonjour Print Services instalat.
  • Graficele istorice - cu librăria Chart.js servești un grafic care arată ultima oră / zi de date. Trebuie să stochezi valorile într-un buffer circular pe ESP32 sau pe card SD.
  • MQTT către Home Assistant - publică temperatura și umiditatea pe un broker MQTT (de exemplu Mosquitto) și Home Assistant le ridică automat ca senzori.
  • Senzori suplimentari - adaugă BMP280 pentru presiune atmosferică, BH1750 pentru luminozitate, PMS5003 pentru calitate aer. ESP32 are pini suficienți pentru toate.
  • OLED local - adaugă un ecran OLED 0.96" pe I2C ca să vezi valorile și fără browser, util când ești în aceeași cameră.
  • OTA Updates - cu ArduinoOTA poți actualiza firmware-ul wireless, nu mai e nevoie să conectezi cablu USB după primul upload.

Probleme frecvente

  • „Failed to read from DHT sensor": verifică alimentarea (3.3V), pinul de date și rezistența de pull-up. DHT22 cere o pauză de ~2 secunde între citiri - dacă încerci mai des, vei primi NaN.
  • ESP32 nu se conectează la WiFi: dublu-check SSID și parola. ESP32 funcționează doar pe rețele 2.4 GHz, nu 5 GHz. Dacă routerul tău e dual-band, asigură-te că te conectezi la SSID-ul de 2.4 GHz.
  • Upload eșuat „Failed to connect": ține apăsat butonul BOOT în timpul upload-ului. Unele plăci ESP32 cer asta din cauza că nu au auto-reset hardware.
  • Pagina se deschide dar valorile sunt „--": probabil senzorul nu răspunde (vezi prima problemă). Verifică Serial Monitor pentru mesaje de eroare.
  • Erori de compilare cu ESPAsyncWebServer: verifică că ai instalat și AsyncTCP. Cele două merg împreună - una fără cealaltă nu compilează.
  • Pagina nu se deschide din rețeaua locală: verifică firewall-ul pe routerul tău. Unele routere izolează clienții WiFi între ei (AP isolation) - dezactivează această opțiune.

Proiect adaptat după tutorialul ESP32 DHT11/DHT22 Web Server using Arduino IDE de pe Random Nerd Tutorials, una dintre cele mai bune resurse de proiecte ESP32. Pentru variante cu MQTT, deep sleep sau alte senzori, recomandăm consultarea sursei originale.

0 comentarii

Lasă un comentariu

Nu uita: comentariile trebuie aprobate înainte de publicare.