Objetivo y caso de uso
Qué vas a construir: Un monitor de buzón IoT alimentado por batería y altamente eficiente que permanece en un estado de suspensión profunda de micropotencia, se despierta instantáneamente cuando la puerta del buzón se abre, transmite una alerta por Wi-Fi a través de una solicitud HTTP GET y vuelve a suspenderse inmediatamente.
Por qué es importante / Casos de uso
- Elimina viajes innecesarios: Los usuarios ya no necesitan revisar físicamente un buzón vacío en condiciones climáticas adversas o a través de entradas largas.
- Maximiza el ciclo de vida de la batería: Al utilizar las capacidades de suspensión profunda del ESP32 (consumiendo ~10µA), el dispositivo minimiza los ciclos de trabajo activos, demostrando habilidades cruciales de gestión de energía.
- Arquitectura orientada a eventos: Enseña la transición del sondeo continuo a los despertares impulsados por interrupciones de hardware, un concepto fundamental en las redes de sensores comerciales.
- Seguridad y registro de acceso: La misma arquitectura puede reutilizarse para monitorear armarios restringidos, cajas fuertes o puertas perimetrales sin requerir energía cableada.
Resultado esperado
- El ESP32 entra en un estado de suspensión profunda consumiendo una corriente mínima (menos de 15µA).
- Abrir la puerta activa un despertar por hardware a través del GPIO del RTC (Reloj de Tiempo Real) en menos de 500 milisegundos.
- El dispositivo se conecta exitosamente al Wi-Fi, transmite el payload HTTP y se apaga en menos de 3 segundos para preservar la vida útil de la batería.
Audiencia: Desarrolladores de IoT, Ingenieros de Sistemas Embebidos; Nivel: Intermedio
Arquitectura/flujo: Interruptor Reed (Interrupción de hardware) → Despertar RTC del ESP32 (latencia <500ms) → Conexión Wi-Fi → Solicitud HTTP GET → Suspensión profunda (Deep Sleep)
Nota educativa de validación
Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. Para este perfil ESP32 DevKitC, el proyecto se comprobó como proyecto PlatformIO: el validador extrajo platformio.ini y src/main.cpp, creó un proyecto temporal y ejecutó pio run contra platform = espressif32, board = esp32dev y framework = arduino. También revisó la estructura del artículo, que los comandos sean copiables con guiones ASCII, y que no aparezcan stacks no soportados como ESP-IDF directo o placas ESP32 no acotadas.
Evidencia de validación publicada
- Resultado automático: PASS.
- Estructura parseada: 3 apartados, 3 tablas y 2 bloques de código detectados antes de publicar.
- Código comprobado: 1 PlatformIO config + 1 ESP32 source/pio run.
- Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo y los stacks no soportados bloquean la publicación.
- Hallazgos del informe: sin hallazgos bloqueantes.
Esta validación confirma compatibilidad sintáctica y de herramientas para el código publicado, pero no sustituye la prueba física sobre tu placa ESP32 DevKitC exacta, tu cableado, alimentación y entorno WiFi local.
Nota educativa de seguridad
Advertencia sobre los límites del prototipo: Este proyecto está destinado estrictamente como un prototipo educativo.
* Seguridad de la batería: Este proyecto involucra baterías de polímero de litio (LiPo). El mal manejo, la sobrecarga o el cortocircuito de las baterías LiPo pueden provocar incendios o explosiones. Utiliza siempre un controlador de carga dedicado (como el TP4056 con circuito de protección integrado) y nunca conectes una celda LiPo directamente al ESP32 sin una regulación de voltaje adecuada. No dejes circuitos de baterías experimentales desatendidos mientras se cargan. Asegúrate de que tu módulo de batería incluya protección contra sobredescarga para evitar daños a la celda durante despliegues prolongados.
Diagrama de bloques conceptual
Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.
Arquitectura funcional
Flujo conceptual: configuración local, emisión BLE y lectura desde el móvil.
Ruta de validación
Resumen conceptual de las herramientas usadas para comprobar el proyecto ESP32 publicado.
Requisitos previos
Antes de comenzar este tutorial, asegúrate de tener listo lo siguiente:
* Una computadora con Windows, macOS o Linux.
* Visual Studio Code (VSCode) instalado.
* La extensión PlatformIO IDE instalada en VSCode.
* Familiaridad básica con la sintaxis de C++ y circuitos electrónicos (redes pull-up/pull-down).
* Una red Wi-Fi de 2.4 GHz (ESP32 no soporta Wi-Fi de 5 GHz).
* Un servidor HTTP local o un endpoint de webhook para recibir la alerta.
Materiales
Para este proyecto, utiliza la siguiente configuración exacta de hardware:
* ESP32 DevKitC: La placa del microcontrolador principal que incluye el módulo ESP-WROOM-32.
* Interruptor Reed: Un interruptor de contacto magnético (normalmente abierto). Cuando el imán está cerca, el interruptor se cierra. Cuando se retira el imán (se abre la puerta), el interruptor se abre.
* Módulo de batería LiPo: Una batería de polímero de litio de 3.7V emparejada con un módulo de carga/elevación de 5V (por ejemplo, un módulo de power bank basado en TP4056) para suministrar 5V de manera segura al pin 5V (o VIN) del ESP32 DevKitC.
* Componentes pasivos:
* Una resistencia de 10kΩ (usada como resistencia pull-down para el interruptor Reed).
* Accesorios: Protoboard, cables puente (jumpers) y un cable de datos micro-USB.
Configuración/Conexión
Notas de configuración de hardware
El ESP32 DevKitC requiere controladores específicos para comunicarse por USB. Dependiendo de la revisión exacta de tu placa, utilizará un puente USB a UART CP210x o CH34x. Si tu sistema operativo o PlatformIO no reconocen tu placa, descarga e instala los controladores oficiales CP210x de Silicon Labs o CH340 de WCH.
Lógica del circuito
El núcleo de este proyecto es la interrupción de hardware. El procesador principal del ESP32 se apaga durante la suspensión profunda. Solo el coprocesador de ultra bajo consumo (ULP) y la memoria/periféricos del RTC permanecen activos. Usaremos la fuente de despertar ext0, que permite que un GPIO del RTC despierte al procesador principal cuando se detecta un nivel lógico específico.
Usaremos el GPIO 33 (un pin compatible con RTC) para el interruptor Reed.
* Buzón cerrado: El imán está cerca del interruptor Reed. El interruptor está cerrado, conectando el GPIO 33 a 3.3V. El ESP32 ve una señal HIGH.
* Buzón abierto: La puerta se abre, el imán se aleja y el interruptor se abre. La resistencia pull-down de 10kΩ fuerza el GPIO 33 a LOW.
* Condición de despertar: Configuraremos el ESP32 para que se despierte cuando el GPIO 33 cambie a LOW.
Tabla de cableado
| Componente | Pin/Terminal | Pin del ESP32 DevKitC | Notas |
|---|---|---|---|
| Módulo de batería LiPo | Salida 5V / VOUT | 5V (o VIN) | Proporciona energía cuando el USB está desconectado. |
| Módulo de batería LiPo | GND / Tierra | GND | Tierra común. |
| Interruptor Reed | Terminal 1 | 3V3 | Proporciona 3.3V cuando el interruptor está cerrado. |
| Interruptor Reed | Terminal 2 | GPIO 33 | Pin de señal para el despertar RTC. |
| Resistencia de 10kΩ | Pata 1 | GPIO 33 | Configuración pull-down. |
| Resistencia de 10kΩ | Pata 2 | GND | Configuración pull-down. |
Nota: Desconecta la línea de 5V del módulo de batería LiPo del ESP32 cuando conectes el ESP32 a tu computadora por USB para evitar conflictos de energía.
Firmware de la aplicación
El siguiente código maneja la transición a la suspensión profunda, la conexión Wi-Fi, la solicitud HTTP y la lógica de despertar por hardware.
platformio.ini
Crea un nuevo proyecto de PlatformIO para el ESP32 DevKitC y reemplaza el contenido de platformio.ini con la siguiente configuración:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
src/main.cpp
Reemplaza el contenido de src/main.cpp con el siguiente código. Actualiza las variables de red y del webhook para que coincidan con tu entorno antes de la implementación.
Vista pública parcial del archivo validado. El código completo se muestra a miembros y en PDF/Print.
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
// ==========================================
// Configuration
// ==========================================
const char* WIFI_SSID = "IoT_Network";
const char* WIFI_PASSWORD = "SecurePassword123";
const char* WEBHOOK_URL = "http://192.168.1.100/mailbox-alert";
// Pin Definitions
const gpio_num_t REED_SWITCH_PIN = GPIO_NUM_33; // Must be an RTC GPIO for ext0 wakeup
// Timeouts
const int WIFI_TIMEOUT_MS = 10000; // 10 seconds max to connect
// ==========================================
// Helper Functions
// ==========================================
void printWakeupReason() {
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup caused by external signal using RTC_IO (Door Opened!)");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup caused by timer");
break;
default:
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
break;
}
}
void sendAlert() {
Serial.print("Connecting to Wi-Fi: ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long startAttemptTime = millis();
// Wait for connection with a timeout to prevent draining battery
while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS) {
Serial.print(".");
delay(500);
}
Serial.println();
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Failed to connect to Wi-Fi. Going back to sleep.");
return; // Abort and let the main loop put the device to sleep
}
// ...#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
// ==========================================
// Configuration
// ==========================================
const char* WIFI_SSID = "IoT_Network";
const char* WIFI_PASSWORD = "SecurePassword123";
const char* WEBHOOK_URL = "http://192.168.1.100/mailbox-alert";
// Pin Definitions
const gpio_num_t REED_SWITCH_PIN = GPIO_NUM_33; // Must be an RTC GPIO for ext0 wakeup
// Timeouts
const int WIFI_TIMEOUT_MS = 10000; // 10 seconds max to connect
// ==========================================
// Helper Functions
// ==========================================
void printWakeupReason() {
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("Wakeup caused by external signal using RTC_IO (Door Opened!)");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("Wakeup caused by timer");
break;
default:
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
break;
}
}
void sendAlert() {
Serial.print("Connecting to Wi-Fi: ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long startAttemptTime = millis();
// Wait for connection with a timeout to prevent draining battery
while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS) {
Serial.print(".");
delay(500);
}
Serial.println();
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Failed to connect to Wi-Fi. Going back to sleep.");
return; // Abort and let the main loop put the device to sleep
}
Serial.println("Wi-Fi connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Send HTTP GET request
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
Serial.print("Sending alert to: ");
Serial.println(WEBHOOK_URL);
http.begin(WEBHOOK_URL);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
} else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
http.end();
}
// Disconnect Wi-Fi to save power before sleeping
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
// ==========================================
// Main Setup and Loop
// ==========================================
void setup() {
Serial.begin(115200);
delay(1000); // Allow serial monitor to catch up
Serial.println("\n--- Mailbox Monitor Booting ---");
// Determine why the ESP32 woke up
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
printWakeupReason();
// If woke up because the door opened (EXT0)
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
sendAlert();
} else {
// Normal boot (e.g., first power on or reset)
Serial.println("Initial boot. System is armed and ready.");
}
// Configure Deep Sleep Wakeup
// Door open = magnet away = switch open = pull-down resistor pulls to LOW (0).
// Wake up when GPIO 33 goes LOW (0).
esp_sleep_enable_ext0_wakeup(REED_SWITCH_PIN, 0);
Serial.println("Entering deep sleep now. Waiting for door to open...");
Serial.flush();
// Enter Deep Sleep
esp_deep_sleep_start();
}
void loop() {
// The loop is intentionally empty.
// The ESP32 goes to sleep in setup() and resets entirely upon waking.
}
Comandos de Compilación/Flasheo/Ejecución
Para desplegar el código en tu ESP32 DevKitC usando PlatformIO, utiliza la terminal integrada en VSCode.
Referencia de comandos
| Acción | Comando | Propósito |
|---|---|---|
| Compilar código | pio run | Compila el código C++ y las bibliotecas sin subirlo. |
| Subir firmware | pio run --target upload | Flashea el binario compilado al ESP32 por USB. |
| Monitor serie | pio device monitor | Abre la terminal para ver las salidas de Serial.print. |
Flujo de trabajo
- Conecta el ESP32 DevKitC a tu computadora usando un cable micro-USB con capacidad de transferencia de datos.
- Abre la terminal de VSCode en el directorio de tu proyecto.
- Compila y sube el firmware ejecutando:
pio run --target upload - Abre inmediatamente el monitor serie para observar la secuencia de arranque:
pio device monitor
Validación paso a paso
Sigue estos puntos de control agrupados para asegurarte de que tu prototipo funcione correctamente.
- Arranque inicial y armado
- Acción: Presiona el botón
EN(Reinicio) en el ESP32. - Observación esperada: El monitor serie imprime «Initial boot. System is armed and ready.» Luego, el monitor imprime «Entering deep sleep now.»
- Condición de éxito: El dispositivo entra exitosamente en suspensión profunda sin volver a despertarse inmediatamente.
- Acción: Presiona el botón
- Simulando buzón cerrado
- Acción: Coloca el imán directamente junto al interruptor Reed.
- Observación esperada: No sucede nada. El ESP32 permanece en suspensión profunda.
- Condición de éxito: El sistema ignora el estado cerrado (el GPIO 33 está en HIGH).
- Activando el despertar (Buzón abierto)
- Acción: Aleja rápidamente el imán del interruptor Reed.
- Observación esperada: El monitor serie imprime «Wakeup caused by external signal using RTC_IO (Door Opened!)».
- Condición de éxito: La interrupción de hardware despierta exitosamente al ESP32 de la suspensión profunda.
- Conexión de red y transmisión
- Acción: Espera de 2 a 5 segundos mientras observas el monitor serie.
- Observación esperada: El monitor imprime «Wi-Fi connected!», seguido de la dirección IP y luego «HTTP Response code: 200».
- Condición de éxito: El endpoint del webhook registra la solicitud GET entrante.
- Retorno a la suspensión
- Acción: Observa las salidas finales del monitor serie.
- Observación esperada: El monitor imprime «Entering deep sleep now. Waiting for door to open…»
- Condición de éxito: El ESP32 interrumpe la conexión Wi-Fi y apaga su procesador principal, listo para el siguiente evento.
Solución de problemas
Si el sistema no se comporta como se espera, consulta la siguiente tabla.
| Síntoma | Causa probable | Solución |
|---|---|---|
| El código no se sube (Tiempo de espera agotado) | El ESP32 no está entrando en modo bootloader. | Mantén presionado el botón BOOT en el DevKitC mientras ejecutas el comando de subida, y suéltalo cuando comience la conexión. |
| Bucles constantes de despertar | La lógica del interruptor Reed está flotante. | Verifica que la resistencia pull-down de 10kΩ esté conectada de forma segura entre el GPIO 33 y GND. Asegúrate de que el imán esté lo suficientemente cerca para cerrar el interruptor inicialmente. |
| La conexión Wi-Fi falla / Tiempo de espera agotado | Credenciales incorrectas o red de 5GHz. | Verifica WIFI_SSID y WIFI_PASSWORD. Asegúrate de que tu enrutador esté transmitiendo una red de 2.4GHz. |
| Detector de caída de voltaje (Brownout) activado | Energía insuficiente durante la transmisión Wi-Fi. | El puerto USB o el módulo LiPo no pueden suministrar el pico de ~300mA requerido para el Wi-Fi. Intenta usar un cable USB de mejor calidad o asegúrate de que la batería LiPo esté completamente cargada. |
| Sin salida en el monitor serie | Discrepancia en los baudios. | Asegúrate de que monitor_speed = 115200 esté configurado en platformio.ini y coincida con Serial.begin(115200) en el código. |
Mejoras
Una vez que se haya validado el prototipo básico, considera estas mejoras para un dispositivo listo para producción:
- Optimización de energía:
- IP estática: Asigna una dirección IP estática al ESP32 en lugar de usar DHCP. Esto puede reducir el tiempo de conexión Wi-Fi de ~3 segundos a menos de 500ms, ahorrando drásticamente la vida útil de la batería.
- Reemplazo del LDO de hardware: Las placas ESP32 DevKitC estándar utilizan un regulador de voltaje AMS1117 con una alta corriente de reposo (~1.5mA). Para un verdadero funcionamiento con micropotencia, haz la transición a una placa personalizada o a un regulador de baja caída (LDO) como el HT7333.
- Conectividad y confiabilidad:
- Implementación de MQTT: Reemplaza la solicitud HTTP GET con una publicación MQTT a través de la biblioteca
PubSubClient. MQTT tiene menor sobrecarga y es más adecuado para ecosistemas IoT. - Monitoreo del voltaje de la batería: Conecta la salida de la batería LiPo a un pin ADC del ESP32 (a través de un divisor de voltaje) para transmitir el estado de la batería junto con la alerta de puerta abierta.
- Implementación de MQTT: Reemplaza la solicitud HTTP GET con una publicación MQTT a través de la biblioteca
Encuentra este producto y/o libros sobre este tema en Amazon
Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.




