DPOIT · IoT · ESP32
ESP32 con WiFiManager, OLED, DHT22 y PHP
Sistema de monitoreo ambiental: un ESP32 mide temperatura y humedad con un DHT22, las muestra en una pantalla OLED y las envía a un servidor PHP que las guarda en el archivo json.json. La red WiFi se configura con WiFiManager, sin tocar el código.
- ESP32 DevKit V1
- OLED SSD1306 I2C
- DHT22
- WiFiManager
- HTTP + JSON
- PHP
Resumen del proyecto
Qué se necesita y cómo se conecta todo.
Componentes
- ESP32 DevKit V1
- Pantalla OLED SSD1306 (I2C)
- Sensor DHT22
- Cables de conexión
- Cable USB para programación
Pantalla OLED (I2C)
- SDA → GPIO21
- SCL → GPIO22
- VCC → 3.3V
- GND → GND
Sensor DHT22
- DATA → GPIO33 (según el código)
- VCC → 3.3V
- GND → GND
Librerías requeridas
- WiFiManager (by tzapu)
- DHTesp
- U8g2lib
- HTTPClient
- ArduinoJson
dht22.h el pin definido es pinDHT = 33. El texto original del tutorial menciona GPIO15; conecta el sensor al pin que realmente uses en el código.Tutorial
Guía paso a paso del funcionamiento y configuración del proyecto.
Índice
01Estructura del programa
El programa está dividido en varios archivos para mejor organización.
esp32_wifimanager_oled_dht22_php.ino
Archivo principal que coordina todo el sistema.
oled.h
Manejo de la pantalla OLED.
wm.h
Gestión de la conexión WiFi.
dht22.h
Lectura del sensor DHT22.
php.h
Envío de datos al servidor PHP.
php.php
Programa del servidor que almacena los datos. Crea json.json.
vistaprevia.html
Visualización de los datos en tiempo real.
02Configuración inicial
En setup() se realizan estas operaciones, y después loop() mantiene todo en marcha.
Inicialización (setup)
- Inicia la comunicación serial a 115200 baudios
- Configura la pantalla OLED
- Muestra un mensaje inicial en la OLED
- Inicia WiFiManager
- Configura el sensor DHT22
Bucle principal (loop)
loopWM(): mantiene la conexión WiFiloopDHT22(): lee el sensorloopPHP(): envía los datos al servidor
03Configuración WiFi
El sistema usa WiFiManager para facilitar la conexión sin modificar el código.
- Al iniciar por primera vez, el ESP32 crea un punto de acceso WiFi.
- Conéctate a la red del ESP32 desde un dispositivo (en el tutorial original, "ESP32_AP").
- Abre el navegador y accede a
192.168.4.1. - Selecciona la red WiFi e introduce la contraseña.
- El ESP32 se conectará automáticamente a esa red.
04Lectura de sensores
El programa lee los datos del DHT22 cada 10 segundos.
Temperatura
En grados Celsius.
Humedad
Humedad relativa en porcentaje.
Los datos se muestran en la pantalla OLED y se almacenan en variables globales para su envío.
05Envío de datos PHP (php.h)
El ESP32 envía un JSON por POST cada 10 segundos y el servidor responde con otro JSON.
URL a modificar en php.h:
const char* serverUrl = "https://unicarlos.es/arduino/esp32_wifimanager_oled_dht22_php/php.php";
json.json.06Visualización
Los datos pueden verse de tres formas.
Pantalla OLED
Muestra los valores actuales de temperatura y humedad.
Monitor Serial
Información de depuración y estado del sistema.
Interfaz web
Gráficas y medidores en tiempo real.
Vista previa
Interfaz web del Sistema de Monitoreo Ambiental con ESP32: temperatura y humedad actuales y gráfica de temperatura a lo largo del tiempo.
Código del proyecto
Elige un archivo para ver su contenido.
#include "oled.h"
#include "wm.h"
#include "dht22.h"
#include "php.h"
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Iniciando...");
setupOled();
mostrarOled("Iniciando...", "WiFiManager", "OLED", "ESP32");
setupWM();
setupDHT22();
}
void loop() {
loopWM();
loopDHT22();
loopPHP();
}#include <DHTesp.h>
DHTesp dht;
const int pinDHT = 33;
TempAndHumidity datosTH;
String temperatura;
String humedad;
float temperaturaFloat;
float humedadFloat;
unsigned long tiempoAnterior = 0;
const long intervalo = 10000; // intervalo de 10seg
void setupDHT22() {
dht.setup(pinDHT, DHTesp::DHT22);
}
void loopDHT22() {
unsigned long tiempoActual = millis();
if (tiempoActual - tiempoAnterior >= intervalo) {
tiempoAnterior = tiempoActual;
datosTH = dht.getTempAndHumidity();
temperatura = String(datosTH.temperature, 2) + " C";
humedad = String(datosTH.humidity, 1) + " %";
temperaturaFloat = datosTH.temperature;
humedadFloat = datosTH.humidity;
Serial.print("Temperatura: ");
Serial.print(temperatura);
Serial.print(" Humedad: ");
Serial.print(humedad);
Serial.println();
mostrarOled("ip: "+ipActual, "Temperatura: "+temperatura,"Humedad: "+humedad,"cvf");
}
}#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);
void setupOled() {
u8g2.begin();
}
void mostrarOled(String cad1="", String cad2="", String cad3="", String cad4="") {
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.setCursor(5, 14);
u8g2.print(cad1);
u8g2.setCursor(5, 30);
u8g2.print(cad2);
u8g2.setCursor(5, 46);
u8g2.print(cad3);
u8g2.setCursor(5, 62);
u8g2.print(cad4);
u8g2.sendBuffer(); // transfer internal memory to the display
}#include <HTTPClient.h>
#include <ArduinoJson.h>
HTTPClient http;
//const char* serverUrl = "http://192.168.1.105/arduino/esp32_wifimanager_oled_dht22_php/php.php";
const char* serverUrl = "https://unicarlos.es/arduino/esp32_wifimanager_oled_dht22_php/php.php";
unsigned long lastTime = 0;
const long interval = 10000; // Intervalo de 10 segundos
void enviarDatosJSON(float temperatura, float humedad) {
if (WiFi.status() == WL_CONNECTED) {
// Crear documento JSON
StaticJsonDocument<200> doc;
doc["accion"] = "guardarTemHum";
doc["temp"] = temperatura;
doc["hum"] = humedad;
// Serializar JSON
String jsonString;
serializeJson(doc, jsonString);
// Configurar petición HTTP
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
// Enviar POST
int httpCode = http.POST(jsonString);
Serial.print("Enviando: ");
Serial.println(jsonString);
if (httpCode > 0) {
String response = http.getString();
Serial.print("Respuesta del servidor: ");
Serial.println(response);
// Procesar respuesta JSON
StaticJsonDocument<200> respDoc;
DeserializationError error = deserializeJson(respDoc, response);
if (!error) {
bool exito = respDoc["exito"];
const char* mensaje = respDoc["mensaje"];
Serial.print("Éxito: ");
Serial.println(exito);
Serial.print("Mensaje: ");
Serial.println(mensaje);
}
} else {
Serial.print("Error en HTTP request: ");
Serial.println(httpCode);
}
http.end();
}
}
void loopPHP() {
unsigned long currentTime = millis();
if (currentTime - lastTime >= interval) {
lastTime = currentTime;
enviarDatosJSON(temperaturaFloat, humedadFloat);
}
}#include "WiFi.h"
#include <WiFiManager.h>
const int pinCero = 0;
const int pinDos = 2;
WiFiManager wm;
String ipActual = "ninguna";
unsigned long tiempoPulsado = 0;
bool botonCeroPulsado = false;
bool estadoLedDos = LOW;
unsigned long tiempoRetardo = 0;
void setupWM() {
pinMode(pinCero, INPUT);
pinMode(pinDos, OUTPUT);
digitalWrite(pinDos, LOW);
// conectando
Serial.println();
Serial.println(WiFi.getHostname());
digitalWrite(pinDos, HIGH);
mostrarOled("SSID", WiFi.getHostname(), "Portal Cautivo", "192.168.4.1");
if (wm.autoConnect(WiFi.getHostname(), "")) {
IPAddress ip = WiFi.localIP();
ipActual = ip.toString();
mostrarOled("IP: " + ipActual);
digitalWrite(pinDos, LOW);
} else {
Serial.println("Ha fallado la conexión");
}
}
void loopWM() {
if (digitalRead(pinCero) == LOW) {
if (!botonCeroPulsado) {
tiempoPulsado = millis();
botonCeroPulsado = true;
Serial.println("Boton boot pulsado");
mostrarOled("Boton 0 pulsado", "", "", "");
}
int segundos = (millis() - tiempoPulsado) / 1000;
mostrarOled("Boton 0 pulsado", "Tiempo: " + String(segundos) + " s", "Restante: " + String(3 - segundos) + " s");
// Si el botón ha sido presionado por menos de 3 segundos, parpadea el LED
if (millis() - tiempoPulsado < 3000) {
if (millis() - tiempoRetardo >= 200) { // Parpadea cada 500 ms
estadoLedDos = !estadoLedDos;
digitalWrite(pinDos, estadoLedDos);
tiempoRetardo = millis();
}
} else {
// Si el botón ha sido presionado por más de 3 segundos, mantén el LED encendido
digitalWrite(pinDos, HIGH);
mostrarOled("", "Reseteando WiFi...", "", "");
wm.resetSettings(); // borra los datos de la memoria interna (SSID y contraseña)
ESP.restart();
}
} else {
if (botonCeroPulsado) {
digitalWrite(pinDos, LOW);
botonCeroPulsado = false;
mostrarOled("IP: " + ipActual);
}
}
}<?php
header('Content-Type: application/json');
// Función para enviar respuestas JSON
function enviarRespuesta($exito, $mensaje, $datos = null) {
$respuesta = [
'exito' => $exito,
'mensaje' => $mensaje
];
if ($datos !== null) {
$respuesta['datos'] = $datos;
}
echo json_encode($respuesta);
exit;
}
// Verificar que sea método POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
enviarRespuesta(false, 'Método no permitido');
}
// Obtener y decodificar JSON recibido
$jsonData = file_get_contents('php://input');
$data = json_decode($jsonData, true);
// Verificar JSON válido
if ($data === null) {
enviarRespuesta(false, 'JSON inválido');
}
// Verificar acción y datos requeridos
if (!isset($data['accion']) || $data['accion'] !== 'guardarTemHum' ||
!isset($data['temp']) || !isset($data['hum'])) {
enviarRespuesta(false, 'Datos incompletos o acción inválida');
}
// Preparar nuevo registro
$registro = [
'temperatura' => $data['temp'],
'humedad' => $data['hum'],
'fecha_hora' => date('Y-m-d H:i:s')
];
// Nombre del archivo JSON
$archivo = 'json.json';
// Leer datos existentes o crear array vacío
$datosExistentes = [];
if (file_exists($archivo)) {
$contenido = file_get_contents($archivo);
if ($contenido) {
$datosExistentes = json_decode($contenido, true) ?? [];
}
}
// Añadir nuevo registro
$datosExistentes[] = $registro;
// Mantener solo los últimos 10 registros
if (count($datosExistentes) > 10) {
array_shift($datosExistentes);
}
// Guardar en archivo
if (file_put_contents($archivo, json_encode($datosExistentes, JSON_PRETTY_PRINT))) {
enviarRespuesta(true, 'Datos guardados correctamente', $registro);
} else {
enviarRespuesta(false, 'Error al guardar los datos');
}
?>Notas importantes
- Modifica las URL en
php.hsegún tu configuración. - La pantalla OLED debe estar conectada a los pines I2C (21 y 22).
- Comprueba el pin del DHT22: el código usa GPIO33 (el tutorial original cita GPIO15).
- El intervalo de envío de datos es de 10 segundos.