Caso práctico: Monitor de buzón IoT con ESP32

Caso práctico: Monitor de buzón IoT con ESP32 — ESP32 con reed switch, imán y módulo LiPo para detectar apertura de buzón

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

Botón local

ESP32 BLE

Paquete advertising

LED de estado

Móvil escáner

Flujo conceptual: configuración local, emisión BLE y lectura desde el móvil.

Ruta de validación

Código fuente

PlatformIO build

Flash

Monitor serie

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

ComponentePin/TerminalPin del ESP32 DevKitCNotas
Módulo de batería LiPoSalida 5V / VOUT5V (o VIN)Proporciona energía cuando el USB está desconectado.
Módulo de batería LiPoGND / TierraGNDTierra común.
Interruptor ReedTerminal 13V3Proporciona 3.3V cuando el interruptor está cerrado.
Interruptor ReedTerminal 2GPIO 33Pin de señal para el despertar RTC.
Resistencia de 10kΩPata 1GPIO 33Configuración pull-down.
Resistencia de 10kΩPata 2GNDConfiguració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
    }
// ...

🔒 Este contenido es premium. Con la suscripción mensual (7 días gratis) podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Desbloquéalo — 7 días gratis
#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ónComandoPropósito
Compilar códigopio runCompila el código C++ y las bibliotecas sin subirlo.
Subir firmwarepio run --target uploadFlashea el binario compilado al ESP32 por USB.
Monitor seriepio device monitorAbre la terminal para ver las salidas de Serial.print.

Flujo de trabajo

  1. Conecta el ESP32 DevKitC a tu computadora usando un cable micro-USB con capacidad de transferencia de datos.
  2. Abre la terminal de VSCode en el directorio de tu proyecto.
  3. Compila y sube el firmware ejecutando:
    pio run --target upload
  4. 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.

  1. 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.
  2. 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).
  3. 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.
  4. 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.
  5. 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íntomaCausa probableSolució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 despertarLa 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 agotadoCredenciales 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) activadoEnergí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 serieDiscrepancia 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.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a 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.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del proyecto descrito en el artículo?




Pregunta 2: ¿Qué método utiliza el dispositivo para enviar la alerta cuando se abre el buzón?




Pregunta 3: ¿Cuál es el consumo de corriente aproximado del ESP32 durante el estado de suspensión profunda según el texto?




Pregunta 4: ¿Qué concepto fundamental de redes de sensores comerciales enseña este proyecto?




Pregunta 5: Además de buzones, ¿qué otro caso de uso de seguridad se menciona para esta arquitectura?




Pregunta 6: ¿Cuál es el límite máximo de consumo de corriente esperado cuando el ESP32 entra en estado de suspensión profunda?




Pregunta 7: ¿En cuánto tiempo se activa el despertar por hardware cuando se abre la puerta?




Pregunta 8: ¿A través de qué componente se activa el despertar por hardware del ESP32?




Pregunta 9: ¿Cuánto tiempo tarda el dispositivo en conectarse al Wi-Fi, transmitir el payload y apagarse?




Pregunta 10: ¿A qué nivel de audiencia está dirigido este artículo?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:
Scroll al inicio