En este proyecto vas a aprender cómo construir un servidor web asíncrono con el ESP32 y un sensor DHT11 o DHT22 que muestre la temperatura y la humedad usando Arduino IDE. El servidor web que construiremos actualiza las lecturas automáticamente sin necesidad de refrescar la página web.
Con este proyecto aprenderás: cómo leer la temperatura y la humedad de los sensores DHT, cómo construir un servidor web asíncrono usando la librería ESPAsyncWebServer y cómo actualizar las lecturas del sensor automáticamente sin necesidad de refrescar la página web.
Para una explicación más detallada sobre cómo usar los sensores de temperatura y humedad DHT22 y DHT11 con el ESP32, consulta nuestra guía completa.
¿Qué es un servidor web asíncrono y por qué usarlo?
Para construir el servidor web usaremos la libería ESPAsyncWebServer, que proporciona una forma sencilla de construir un servidor web asíncrono. Construir un servidor web asíncrono tiene varias ventajas importantes, tal y como se menciona en la página de GitHub de la librería:
“Maneja más de una conexión al mismo tiempo”. “Cuando envías la respuesta, estás inmediatamente listo para manejar otras conexiones mientras el servidor se encarga de enviar la respuesta en segundo plano”. “Motor de procesamiento de plantillas simple para manejar plantillas”. Y mucho más.
La diferencia clave: con un servidor asíncrono, el ESP32 puede atender a varios clientes simultáneamente y actualizar las lecturas en segundo plano sin bloquearse. Esto es fundamental cuando vas a tener varios dispositivos conectados a la vez (tu móvil, tu tablet, tu ordenador…).
Componentes necesarios
Para completar este tutorial necesitas: una placa de desarrollo ESP32, un sensor de temperatura y humedad DHT22 o DHT11, una resistencia de 4,7 kΩ, una protoboard y cables jumper.
Esquema de conexión
Antes de proceder con el servidor web, necesitas conectar el sensor DHT11 o DHT22 al ESP32. En este caso, estamos conectando el pin de datos al GPIO 27, pero puedes conectarlo a cualquier otro pin digital. Puedes usar este esquema tanto para el DHT11 como para el DHT22. Recuerda que la resistencia pull-up de 4,7 kΩ entre el pin de datos y 3,3 V es obligatoria para que el sensor funcione correctamente.
Nota: si estás usando un módulo con un sensor DHT, normalmente viene con solo tres pines. Los pines deberían estar etiquetados para que sepas cómo cablearlos. Además, muchos de estos módulos ya incluyen una resistencia pull-up interna, así que no necesitas añadir una al circuito.
Nota: este esquema usa la versión del módulo ESP32 DEVKIT V1 con 36 GPIOs. Si usas otro modelo, comprueba el pinout de tu placa.
Instalar las librerías necesarias
Necesitas instalar un par de librerías para este proyecto: las liberías DHT y Adafruit Unified Sensor Driver para leer del sensor DHT, y las liberías ESPAsyncWebServer y AsyncTCP de ESP32Async para construir el servidor web asíncrono.
Puedes instalar esas librerías en el Gestor de Librerías de Arduino IDE. Ve a Programa > Incluir Librería > Gestionar Librerías y busca los nombres de las librerías.
Código completo del servidor web
Vamos a programar el ESP32 usando Arduino IDE, así que asegúrate de tener el complemento ESP32 instalado antes de continuar. Abre tu Arduino IDE y copia el siguiente código:
/*
Rui Santos
Detalles completos del proyecto en https://randomnerdtutorials.com
*/
// Importa las librerías requeridas
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include <Adafruit_Sensor.h>
#include <DHT.h>
// Reemplaza con las credenciales de tu red
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
#define DHTPIN 27 // Pin digital conectado al sensor DHT
// Descomenta el tipo de sensor que estás usando:
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);
// Crea el objeto AsyncWebServer en el puerto 80
AsyncWebServer server(80);
String readDHTTemperature() {
// Las lecturas del sensor también pueden tener hasta 2 segundos de antigüedad (es un sensor muy lento)
// Lee la temperatura en Celsius (por defecto)
float t = dht.readTemperature();
// Lee la temperatura en Fahrenheit (isFahrenheit = true)
//float t = dht.readTemperature(true);
// Comprueba si alguna lectura falló y sale temprano (para intentarlo de nuevo).
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(t);
return String(t);
}
}
String readDHTHumidity() {
// Las lecturas del sensor también pueden tener hasta 2 segundos de antigüedad
float h = dht.readHumidity();
if (isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(h);
return String(h);
}
}
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
</head>
<body>
<h2>ESP32 DHT Server</h2>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="dht-labels">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">°C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
</html>)rawliteral";
// Reemplaza el placeholder con los valores del DHT
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return readDHTTemperature();
}
else if(var == "HUMIDITY"){
return readDHTHumidity();
}
return String();
}
void setup(){
// Puerto serie para propósitos de depuración
Serial.begin(115200);
dht.begin();
// Conecta a Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
// Imprime la dirección IP local del ESP32
Serial.println(WiFi.localIP());
// Ruta para la raíz / página web
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());
});
// Inicia el servidor
server.begin();
}
void loop(){
}
Inserta las credenciales de tu red en las siguientes variables y el código funcionará inmediatamente:
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Cómo funciona el código paso a paso
Importar las librerías
Primero, se importan las librerías requeridas. Las librerías WiFi, ESPAsyncWebServer y AsyncTCP son necesarias para construir el servidor web. Las librerías Adafruit_Sensor y DHT son necesarias para leer de los sensores DHT11 o DHT22.
Configurar las credenciales de red
Se insertan las credenciales de red en las variables correspondientes, para que el ESP32 pueda conectarse a tu red local.
Definición de variables
Se define el GPIO al que está conectado el pin de datos del DHT. En este caso, está conectado al GPIO 27. Después, se selecciona el tipo de sensor DHT que estás usando. En nuestro ejemplo, estamos usando el DHT22. Si estás usando otro tipo, solo necesitas descomentar tu sensor y comentar todos los demás.
Se instancia un objeto DHT con el tipo y el pin que hemos definido antes. Se crea un objeto AsyncWebServer en el puerto 80.
Funciones de lectura de temperatura y humedad
Hemos creado dos funciones: una para leer la temperatura (readDHTTemperature()) y otra para leer la humedad (readDHTHumidity()).
Obtener lecturas del sensor es tan sencillo como usar los métodos readTemperature() y readHumidity() en el objeto dht. También tenemos una condición que devuelve dos guiones (--) en caso de que el sensor falle al obtener las lecturas. Las lecturas se devuelven como tipo string. Para convertir un float a un string, usa la función String().
Por defecto, estamos leyendo la temperatura en grados Celsius. Para obtener la temperatura en grados Fahrenheit, comenta la temperatura en Celsius y descomenta la temperatura en Fahrenheit.
Construir la página web
Veamos la página del servidor web. La página web muestra un encabezado y dos párrafos. Hay un párrafo para mostrar la temperatura y otro para mostrar la humedad. También hay dos iconos para estilizar nuestra página.
Todo el texto HTML con los estilos incluidos se almacena en la variable index_html.
La siguiente etiqueta <meta> hace que tu página web sea responsive en cualquier navegador. La etiqueta <link> es necesaria para cargar los iconos de la web de Font Awesome.
Estilos CSS
Entre las etiquetas <style> y </style>, añadimos algo de CSS para estilizar la página web. Básicamente, configuramos la página HTML para mostrar el texto con fuente Arial en bloque sin margen y alineado al centro. Se establece el tamaño de fuente para el encabezado (h2), el párrafo (p) y las unidades (.units) de las lecturas. Las etiquetas de las lecturas se estilizan según lo mostrado.
Todas las etiquetas anteriores deberían ir entre las etiquetas <head> y </head>. Estas etiquetas se usan para incluir contenido que no es directamente visible para el usuario, como la <meta>, las <link> tags y los estilos.
Cuerpo HTML
Dentro de las etiquetas <body> y </body> es donde añadimos el contenido de la página web. Las etiquetas <h2> y </h2> añaden un encabezado a la página web. En este caso, el texto “ESP32 DHT Server”, pero puedes añadir cualquier otro texto.
Después, hay dos párrafos. Uno para mostrar la temperatura y otro para mostrar la humedad. Los párrafos están delimitados por las etiquetas <p> y </p>. Las etiquetas <i> muestran los iconos de Font Awesome.
Cómo mostrar iconos
Para elegir los iconos, ve a la web de Font Awesome Icons. Busca el icono que estás buscando. Por ejemplo, “thermometer”. Pulsa el icono deseado. Después, solo necesitas copiar el texto HTML proporcionado.
Para elegir el color, solo necesitas pasar el parámetro style con el color en hexadecimal.
Continuando con el texto HTML… La siguiente línea escribe la palabra “Temperature” en la página web. El texto TEMPERATURE entre signos % es un placeholder para el valor de temperatura. Esto significa que este texto %TEMPERATURE% es como una variable que será reemplazada por el valor real de temperatura del sensor DHT. Los placeholders en el texto HTML deben ir entre signos %.
Finalmente, se añade el símbolo de grado. Las etiquetas <sup> y </sup> hacen el texto superíndice. Usamos el mismo enfoque para el párrafo de humedad, pero usa un icono diferente y el placeholder %HUMIDITY%.
Actualizaciones automáticas
Finalmente, hay algo de código JavaScript en nuestra página web que actualiza la temperatura y la humedad automáticamente, cada 10 segundos. Los scripts en texto HTML deben ir entre las etiquetas <script> y </script>.
Para actualizar la temperatura en segundo plano, tenemos una función setInterval() que se ejecuta cada 10 segundos. Básicamente, hace una petición en la URL /temperature para obtener la última lectura de temperatura. Cuando recibe ese valor, actualiza el elemento HTML cuyo id es temperature.
En resumen, esta sección anterior es responsable de actualizar la temperatura de forma asíncrona. El mismo proceso se repite para las lecturas de humedad.
Importante: como el sensor DHT es bastante lento obteniendo las lecturas, si planeas tener múltiples clientes conectados a un ESP32 al mismo tiempo, recomendamos aumentar el intervalo de petición o eliminar las actualizaciones automáticas.
La función processor()
Ahora, necesitamos crear la función processor(), que reemplazará los placeholders en nuestro texto HTML con los valores reales de temperatura y humedad.
Cuando se solicita la página web, comprobamos si el HTML tiene algún placeholder. Si encuentra el placeholder %TEMPERATURE%, devolvemos la temperatura llamando a la función readDHTTemperature() creada antes. Si el placeholder es %HUMIDITY%, devolvemos el valor de humedad.
La función setup()
En el setup(), se inicializa el Monitor Serie para propósitos de depuración. Se inicializa el sensor DHT. Se conecta a tu red local y se imprime la dirección IP del ESP32.
Finalmente, se añaden las siguientes líneas de código para manejar el servidor web. Cuando hacemos una petición en la URL raíz, enviamos el texto HTML que está almacenado en la variable index_html. También necesitamos pasar la función processor, que reemplazará todos los placeholders con los valores correctos.
Necesitamos añadir dos manejadores adicionales para actualizar las lecturas de temperatura y humedad. Cuando recibimos una petición en la URL /temperature, simplemente necesitamos enviar el valor actualizado de temperatura. Es texto plano, y debería enviarse como char, así que usamos el método c_str(). El mismo proceso se repite para la humedad.
Por último, podemos iniciar el servidor. Como este es un servidor web asíncrono, no necesitamos escribir nada en el loop(). Toda la lógica ocurre en callbacks que se ejecutan cuando llegan las peticiones, sin bloquear el flujo principal.
Subir el código
Ahora, sube el código a tu ESP32. Asegúrate de tener la placa y el puerto COM correctos seleccionados. Después de subir, abre el Monitor Serie a 115200 baudios. Pulsa el botón de reset del ESP32. La dirección IP del ESP32 debería imprimirse en el monitor serie.
Demostración del servidor web
Abre un navegador y escribe la dirección IP del ESP32. Tu servidor web debería mostrar las últimas lecturas del sensor. Fíjate en que las lecturas de temperatura y humedad se actualizan automáticamente sin necesidad de refrescar la página web.
Solución de problemas
Si tu sensor DHT falla al obtener las lecturas, lee nuestra guía de solución de problemas del DHT para ayudarte a solucionar el problema. La causa más común es un cableado incorrecto o la falta de la resistencia pull-up de 4,7 kΩ.
Conclusión: lo que has aprendido
En este tutorial te hemos mostrado cómo construir un servidor web asíncrono con el ESP32 para mostrar las lecturas de un sensor DHT11 o DHT22 y cómo actualizar las lecturas automáticamente.
Este proyecto es la base de cualquier estación meteorológica casera o sistema de monitorización ambiental con el ESP32. La combinación de un servidor web asíncrono con actualizaciones automáticas vía JavaScript te permite construir interfaces profesionales que se actualizan en tiempo real sin que el usuario tenga que hacer nada. Añadiendo más sensores, puedes crear dashboards completos de temperatura, humedad, presión, calidad del aire y cualquier otra variable ambiental que necesites monitorizar.
La actualización automática cada 10 segundos es un equilibrio perfecto entre frescura de datos y carga del servidor. Si necesitas datos en tiempo real, puedes reducir el intervalo; si trabajas con muchos clientes simultáneos, auméntalo para evitar saturar el sensor DHT, que es notoriamente lento. Dominar este patrón te permite adaptar el servidor web a cualquier escenario, desde una sola persona consultando el clima hasta un edificio entero monitorizando decenas de puntos de medición.
Descubre más desde CIBERED
Suscríbete y recibe las últimas entradas en tu correo electrónico.
