Introducción
En esta clase aprenderemos la configuración completa del sensor DHT11 con ESP32, incluyendo las conexiones físicas, instalación de librerías necesarias y configuración de pines GPIO. El DHT11 es un sensor de temperatura y humedad ampliamente utilizado en proyectos IoT debido a su simplicidad y bajo costo.
Integraremos este sensor en nuestro stack tecnológico completo: ESP32 como microcontrolador, Mosquitto como broker MQTT para comunicación, y Flask como framework web para visualización de datos. Esta configuración forma la base de muchos sistemas de monitoreo ambiental profesionales.
- Entender las especificaciones técnicas del DHT11
- Realizar conexiones físicas correctas
- Configurar librerías y pines GPIO
- Implementar comunicación MQTT
- Crear interfaz web con Flask
Conceptos Fundamentales
Especificaciones del DHT11
El DHT11 es un sensor digital de temperatura y humedad que utiliza un protocolo de comunicación propietario de un solo cable:
- Rango de temperatura: 0-50°C (±2°C precisión)
- Rango de humedad: 20-90% RH (±5% RH precisión)
- Voltaje de operación: 3.5-5.5V DC
- Corriente: 0.3mA (medición), 60µA (standby)
- Frecuencia de muestreo: Máximo 1Hz (1 muestra por segundo)
Pinout del DHT11
Pin | Nombre | Descripción |
---|---|---|
1 | VCC | Alimentación (3.3V-5V) |
2 | DATA | Señal de datos (bidireccional) |
3 | NC | No conectado |
4 | GND | Tierra |
Pines GPIO del ESP32
El ESP32 tiene múltiples pines GPIO que pueden utilizarse para el DHT11. Es importante seleccionar pines que no interfieran con otras funciones:
- Pines recomendados: GPIO 4, 16, 17, 18, 19, 21, 22, 23
- Pines a evitar: GPIO 0, 2 (boot), GPIO 6-11 (flash), GPIO 1, 3 (UART)
- Pull-up interno: El ESP32 puede activar resistencias pull-up internas
Protocolo de Comunicación DHT11
El DHT11 utiliza un protocolo de comunicación específico:
- Inicio: MCU envía señal de inicio (LOW por 18ms)
- Respuesta: DHT11 responde con señal de sincronización
- Datos: 40 bits de datos (16 humedad + 16 temperatura + 8 checksum)
- Timing crítico: Requiere timing preciso para lectura correcta
Implementación Práctica
Conexiones Físicas
Diagrama de conexiones para ESP32 DevKit v1:
ESP32 DevKit v1 → DHT11 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.3V → VCC (Pin 1) GPIO 4 → DATA (Pin 2) NC (Pin 3) - No conectar GND → GND (Pin 4) Resistencia pull-up de 10kΩ entre VCC y DATA (opcional con ESP32)
Instalación de Librerías
En Arduino IDE, instalar las siguientes librerías desde el Library Manager:
Librerías necesarias:
/*
Librerías a instalar en Arduino IDE:
1. DHT sensor library by Adafruit (versión 1.4.4 o superior)
2. Adafruit Unified Sensor by Adafruit
3. PubSubClient by Nick O'Leary (para MQTT)
4. ArduinoJson by Benoit Blanchon (para formateo JSON)
*/
// Includes necesarios en el código
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>
Configuración completa del ESP32 con DHT11:
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>
// Configuración DHT11
#define DHT_PIN 4 // GPIO 4 para datos del DHT11
#define DHT_TYPE DHT11 // Tipo de sensor DHT
DHT dht(DHT_PIN, DHT_TYPE);
// Configuración WiFi
const char* ssid = "Tu_Red_WiFi";
const char* password = "Tu_Password_WiFi";
// Configuración MQTT
const char* mqtt_server = "localhost"; // IP del broker Mosquitto
const int mqtt_port = 1883;
const char* mqtt_user = "esp32_user";
const char* mqtt_password = "esp32_pass";
const char* client_id = "ESP32_DHT11_001";
// Tópicos MQTT
const char* topic_temperature = "sensors/dht11/temperature";
const char* topic_humidity = "sensors/dht11/humidity";
const char* topic_status = "sensors/dht11/status";
// Objetos WiFi y MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// Variables de tiempo
unsigned long lastMsg = 0;
const unsigned long MSG_INTERVAL = 30000; // 30 segundos entre lecturas
void setup() {
Serial.begin(115200);
Serial.println("Iniciando ESP32 con DHT11...");
// Inicializar DHT11
dht.begin();
Serial.println("DHT11 inicializado en GPIO " + String(DHT_PIN));
// Configurar WiFi
setup_wifi();
// Configurar MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
// Mensaje de inicio
Serial.println("Sistema listo. Intervalo de lectura: " + String(MSG_INTERVAL/1000) + " segundos");
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Conectando a ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("");
Serial.println("WiFi conectado!");
Serial.println("IP asignada: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("Error: No se pudo conectar al WiFi");
ESP.restart();
}
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Mensaje recibido [");
Serial.print(topic);
Serial.print("]: ");
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
}
void reconnect() {
while (!client.connected()) {
Serial.print("Intentando conexión MQTT...");
if (client.connect(client_id, mqtt_user, mqtt_password)) {
Serial.println("Conectado al broker MQTT");
client.publish(topic_status, "ESP32_DHT11_ONLINE");
client.subscribe("sensors/dht11/commands");
} else {
Serial.print("Falló conexión MQTT, rc=");
Serial.print(client.state());
Serial.println(" reintentando en 5 segundos...");
delay(5000);
}
}
}
void readAndPublishSensorData() {
// Leer temperatura y humedad
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
// Verificar si las lecturas son válidas
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Error: Falló lectura del sensor DHT11!");
client.publish(topic_status, "DHT11_READ_ERROR");
return;
}
// Mostrar valores en Serial
Serial.printf("Temperatura: %.2f°C, Humedad: %.2f%%\n", temperature, humidity);
// Crear JSON con los datos
StaticJsonDocument<200> doc;
doc["device_id"] = client_id;
doc["timestamp"] = millis();
doc["temperature"] = round(temperature * 100) / 100.0; // Redondear a 2 decimales
doc["humidity"] = round(humidity * 100) / 100.0;
doc["heat_index"] = dht.computeHeatIndex(temperature, humidity, false);
char jsonString[200];
serializeJson(doc, jsonString);
// Publicar datos individuales
client.publish(topic_temperature, String(temperature, 2).c_str());
client.publish(topic_humidity, String(humidity, 2).c_str());
// Publicar JSON completo
client.publish("sensors/dht11/data", jsonString);
Serial.println("Datos publicados via MQTT");
}
void loop() {
// Mantener conexión MQTT
if (!client.connected()) {
reconnect();
}
client.loop();
// Verificar conexión WiFi
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Conexión WiFi perdida. Reintentando...");
setup_wifi();
}
// Leer y publicar datos del sensor
unsigned long now = millis();
if (now - lastMsg > MSG_INTERVAL) {
lastMsg = now;
readAndPublishSensorData();
}
delay(100); // Pequeña pausa para evitar watchdog reset
}
Configuración del broker Mosquitto:
# /etc/mosquitto/mosquitto.conf
port 1883
allow_anonymous true
listener 1883 0.0.0.0
# Para producción, configurar autenticación:
# password_file /etc/mosquitto/passwd
# allow_anonymous false
# Logging
log_dest file /var/log/mosquitto/mosquitto.log
log_type error
log_type warning
log_type notice
log_type information
# Persistencia
persistence true
persistence_location /var/lib/mosquitto/
# Reiniciar servicio
sudo systemctl restart mosquitto
sudo systemctl enable mosquitto
Aplicación Flask para visualización:
from flask import Flask, render_template, jsonify
import paho.mqtt.client as mqtt
import json
import threading
import time
from datetime import datetime
app = Flask(__name__)
# Variables globales para almacenar datos del sensor
sensor_data = {
'temperature': 0.0,
'humidity': 0.0,
'last_update': None,
'status': 'Desconectado',
'history': []
}
# Configuración MQTT
MQTT_BROKER = "localhost"
MQTT_PORT = 1883
MQTT_USERNAME = "esp32_user"
MQTT_PASSWORD = "esp32_pass"
def on_connect(client, userdata, flags, rc):
print(f"Conectado al broker MQTT con código: {rc}")
if rc == 0:
sensor_data['status'] = 'Conectado'
# Suscribirse a todos los tópicos del DHT11
client.subscribe("sensors/dht11/+")
client.subscribe("sensors/dht11/data")
else:
sensor_data['status'] = 'Error de conexión'
def on_message(client, userdata, msg):
topic = msg.topic
payload = msg.payload.decode('utf-8')
print(f"