Caso práctico: Monitor de congelador Wi-Fi con ESP32

Caso práctico: Monitor de congelador Wi-Fi con ESP32 — hero

case-device-block-diagram,
.prometeo-educational-note,
.prometeo-device-postcode-section,
.prometeo-device-section-card {
margin: 2.4rem 0;
padding: 1.45rem 1.55rem;
border: 1px solid rgba(148, 163, 184, 0.30);
border-radius: 14px;
background:
linear-gradient(135deg, rgba(30, 41, 59, 0.50), rgba(15, 23, 42, 0.18)),
rgba(17, 24, 39, 0.48);
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.20);
}
.case-objective > h2:first-of-type,
.case-device-block-diagram > h2:first-of-type,
.prometeo-device-postcode-section > h2:first-of-type,
.prometeo-device-section-card > h2:first-of-type {
margin-top: 0;
}
.prometeo-device-section-card > :last-child,
.case-objective > :last-child,
.case-device-block-diagram > :last-child,
.prometeo-device-postcode-section > :last-child {
margin-bottom: 0;
}
.prometeo-device-section-card.prometeo-device-section-card-code {
border-left: 4px solid rgba(56, 189, 248, 0.86);
background:
linear-gradient(135deg, rgba(8, 47, 73, 0.42), rgba(15, 23, 42, 0.18)),
rgba(15, 23, 42, 0.58);
}
.prometeo-device-section-card.prometeo-device-section-card-compact {
padding: 1.2rem 1.35rem;
}
.prometeo-device-section-card pre,
.case-objective pre,
.case-device-block-diagram pre,
.prometeo-device-postcode-section pre {
max-width: 100%;
}
.prometeo-device-postcode-section .prometeo-device-flow-item {
background:
linear-gradient(135deg, rgba(15, 23, 42, 0.50), rgba(30, 41, 59, 0.28)),
rgba(15, 23, 42, 0.28);
}
@media print {
.case-objective,
.case-device-block-diagram,
.prometeo-educational-note,
.prometeo-device-postcode-section,
.prometeo-device-section-card {
background: #fff;
color: #111827;
box-shadow: none;
break-inside: avoid;
page-break-inside: avoid;
}
}

Objetivo y caso de uso

Qué construirás: Un sistema de monitorización de temperatura de congeladores con Wi-Fi que lee un termistor NTC analógico, activa una alarma local sonora y visual cuando las temperaturas superan un umbral seguro (por ejemplo, > -10°C) y sirve datos en tiempo real a un panel web local con una latencia de <1s.

Por qué es importante / Casos de uso

  • Seguridad y almacenamiento de alimentos: Evita el deterioro de los alimentos alertando a los usuarios de inmediato si la puerta del congelador se deja entreabierta o si falla el compresor.
  • Monitorización de activos de laboratorio: Proporciona una base educativa para monitorizar muestras biológicas sensibles o productos químicos que requieren un almacenamiento estricto en cadena de frío.
  • Diagnóstico de HVAC y refrigeración: Actúa como un prototipo de herramienta de diagnóstico para que los técnicos registren los ciclos de enfriamiento e identifiquen unidades de refrigeración ineficientes.
  • Monitorización remota de instalaciones: Ofrece visibilidad remota continua sobre el estado del almacenamiento en frío fuera de las instalaciones sin requerir inspección física.

Resultado esperado

  • Un circuito de microcontrolador desplegado leyendo valores del termistor NTC con una precisión estimada de ±0.5°C.
  • Activación instantánea de alarma local mediante zumbador y LED (latencia inferior a 2 segundos) ante la superación de un umbral de temperatura.
  • Un servidor web local ligero que aloja un panel de control que renderiza gráficos de temperatura en vivo actualizándose a 1Hz.

Público: Aficionados al IoT, estudiantes de electrónica e ingenieros de prototipos; Nivel: Intermedio

Arquitectura/flujo: Termistor NTC → ADC del microcontrolador → Lógica de umbral (Zumbador/LED GPIO) → Punto de acceso/Estación Wi-Fi → Interfaz de usuario web local.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

Sonda de agua

GPIO/ADC ESP32

Lógica de umbral

LED/buzzer

Alerta Wi-Fi

Flujo conceptual: detección de humedad, decisión local y aviso al usuario.

Ruta de validación

Código fuente

PlatformIO build

Flash

Monitor serie

Resumen conceptual de las herramientas usadas para comprobar el proyecto ESP32 publicado.

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: 4 apartados, 1 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

Este proyecto es un prototipo educativo de bajo voltaje, no un sistema certificado de alarma alimentaria. Verifica el pinout de tu ESP32 DevKitC y del sensor de temperatura, mantén todos los GPIO dentro de sus límites de 3,3 V y no conectes el circuito a la red eléctrica ni a la alimentación interna del congelador. Usa una fuente USB fiable, protege el cableado de la humedad y desconecta la alimentación antes de manipular el montaje.

Requisitos previos

Antes de comenzar este tutorial, asegúrese de tener listo lo siguiente:
* Software: Visual Studio Code con la extensión PlatformIO IDE instalada.
* Conocimientos: Comprensión básica de programación en C++, divisores de voltaje y conceptos fundamentales de redes Wi-Fi.
* Red: Acceso a una red Wi-Fi estándar de 2.4 GHz (los microcontroladores ESP32 no soportan redes de 5 GHz).


Materiales

Para garantizar que el código y el cableado se comporten exactamente como se describe, utilice los componentes precisos enumerados a continuación:

ComponenteEspecificación / Modelo exactoCantidad
MicrocontroladorESP32 DevKitC (variante de 38 pines o 30 pines)1
Sensor de temperaturaTermistor NTC de 10 kOhm (valor B ~3950)1
Resistencia fija10 kOhm (1/4 Watt, para el divisor de voltaje)1
Resistencia limitadora de corriente220 Ohm (1/4 Watt, para el LED)1
Indicador visualLED de estado (Estándar de 5mm, preferiblemente rojo)1
Indicador sonoroZumbador activo (compatible con 3.3V o 5V)1
PrototipadoProtoboard y cables puente surtidos1 juego
Energía/DatosCable de datos Micro-USB1

Configuración/Conexión

La configuración del hardware requiere cablear cuidadosamente el termistor NTC en una configuración de divisor de voltaje, junto con los periféricos de salida.

Nota de ingeniería importante sobre el ADC: Usamos GPIO34 para el termistor. GPIO34 pertenece al bloque ADC1 del ESP32. No utilice pines del ADC2 (como GPIO4 o GPIO2) porque el ADC2 es utilizado por el controlador Wi-Fi y no podrá leer voltajes analógicos mientras la radio Wi-Fi esté activa.

1. Divisor de voltaje del termistor NTC

  • Conecte una pata de la resistencia fija de 10 kOhm al pin de 3.3V en el ESP32 DevKitC.
  • Conecte la otra pata de la resistencia fija de 10 kOhm a una fila vacía en la protoboard.
  • Conecte una pata del termistor NTC de 10 kOhm a esa misma fila de la protoboard.
  • Conecte la otra pata del termistor NTC a GND.
  • Conecte un cable puente desde la unión entre la resistencia fija y el termistor al GPIO34 del ESP32.

2. Zumbador activo

  • Conecte el pin positivo (a menudo marcado con un + o la pata más larga) del zumbador activo al GPIO26.
  • Conecte el pin negativo a GND.

3. LED de estado

  • Conecte el ánodo (pata más larga) del LED de estado a una pata de la resistencia de 220 Ohm.
  • Conecte la otra pata de la resistencia de 220 Ohm al GPIO27.
  • Conecte el cátodo (pata más corta) del LED a GND.

4. Configuración del controlador USB

  • Dependiendo del fabricante exacto de su ESP32 DevKitC, contará con un puente USB a UART CP210x o CH34x.
  • Si su computadora no reconoce automáticamente la placa al conectarla, descargue e instale los controladores CP210x o CH34x adecuados para su sistema operativo.

Código validado

El proyecto se basa en dos archivos dentro del entorno PlatformIO. Cree un nuevo proyecto en PlatformIO seleccionando la placa esp32dev y el framework Arduino. Reemplace el contenido de los archivos generados con el código a continuación.

platformio.ini

Este archivo de configuración define el objetivo de hardware, el framework y la velocidad de baudios del monitor serie.

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

src/main.cpp

Este es el código fuente principal. Asegúrese de actualizar las variables WIFI_SSID y WIFI_PASSWORD para que coincidan con las credenciales de su red local antes de compilar.

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 <WebServer.h>

// ------------------------------------------------------------------
// Network Credentials
// ------------------------------------------------------------------
const char* WIFI_SSID = "LabNetwork";
const char* WIFI_PASSWORD = "LabPassword123";

// ------------------------------------------------------------------
// Pin Definitions
// ------------------------------------------------------------------
const int NTC_PIN = 34;      // ADC1_CH6 - Safe to use with Wi-Fi
const int BUZZER_PIN = 26;   // Output for active buzzer
const int LED_PIN = 27;      // Output for status LED

// ------------------------------------------------------------------
// Thermistor & Steinhart-Hart Parameters
// ------------------------------------------------------------------
const float SERIES_RESISTOR = 10000.0;    // 10k Ohm fixed resistor
const float NOMINAL_RESISTANCE = 10000.0; // 10k Ohm NTC at 25 degrees C
const float NOMINAL_TEMPERATURE = 25.0;   // Nominal temperature in Celsius
const float B_COEFFICIENT = 3950.0;       // Beta value of the thermistor
const float ALARM_THRESHOLD = -10.0;      // Alarm triggers if temp rises above -10.0 C

// ------------------------------------------------------------------
// Global Variables
// ------------------------------------------------------------------
WebServer server(80);
float currentTemperature = 0.0;
bool isAlarmActive = false;

// Timing variables for non-blocking alarm
unsigned long previousMillis = 0;
const long blinkInterval = 500; // 500ms toggle rate for buzzer/LED
bool toggleState = false;

// ------------------------------------------------------------------
// Function Prototypes
// ------------------------------------------------------------------
void connectWiFi();
void handleRoot();
float readTemperature();
void handleAlarmLogic();

// ------------------------------------------------------------------
// Setup
// ------------------------------------------------------------------
void setup() {
    Serial.begin(115200);
    delay(1000); // Allow serial monitor to stabilize

    // Initialize output pins
    pinMode(BUZZER_PIN, OUTPUT);
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(BUZZER_PIN, LOW);
    digitalWrite(LED_PIN, LOW);

    // Initialize ADC
    analogReadResolution(12); // 12-bit ADC (0 - 4095)

    Serial.println("\n--- Freezer Temperature Alarm System ---");

    connectWiFi();

    // Setup Web Server Routes
    server.on("/", handleRoot);
    server.begin();
    Serial.println("Web server started.");
}

// ------------------------------------------------------------------
// Main Loop
// ------------------------------------------------------------------
void loop() {
    server.handleClient(); // Listen for incoming HTTP requests

    // Read temperature every cycle
    currentTemperature = readTemperature();

    // Evaluate and execute alarm logic
    handleAlarmLogic();

    // Small delay to stabilize ADC reads and prevent watchdog resets
    delay(50);
}
// ...

🔒 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 <WebServer.h>

// ------------------------------------------------------------------
// Network Credentials
// ------------------------------------------------------------------
const char* WIFI_SSID = "LabNetwork";
const char* WIFI_PASSWORD = "LabPassword123";

// ------------------------------------------------------------------
// Pin Definitions
// ------------------------------------------------------------------
const int NTC_PIN = 34;      // ADC1_CH6 - Safe to use with Wi-Fi
const int BUZZER_PIN = 26;   // Output for active buzzer
const int LED_PIN = 27;      // Output for status LED

// ------------------------------------------------------------------
// Thermistor & Steinhart-Hart Parameters
// ------------------------------------------------------------------
const float SERIES_RESISTOR = 10000.0;    // 10k Ohm fixed resistor
const float NOMINAL_RESISTANCE = 10000.0; // 10k Ohm NTC at 25 degrees C
const float NOMINAL_TEMPERATURE = 25.0;   // Nominal temperature in Celsius
const float B_COEFFICIENT = 3950.0;       // Beta value of the thermistor
const float ALARM_THRESHOLD = -10.0;      // Alarm triggers if temp rises above -10.0 C

// ------------------------------------------------------------------
// Global Variables
// ------------------------------------------------------------------
WebServer server(80);
float currentTemperature = 0.0;
bool isAlarmActive = false;

// Timing variables for non-blocking alarm
unsigned long previousMillis = 0;
const long blinkInterval = 500; // 500ms toggle rate for buzzer/LED
bool toggleState = false;

// ------------------------------------------------------------------
// Function Prototypes
// ------------------------------------------------------------------
void connectWiFi();
void handleRoot();
float readTemperature();
void handleAlarmLogic();

// ------------------------------------------------------------------
// Setup
// ------------------------------------------------------------------
void setup() {
    Serial.begin(115200);
    delay(1000); // Allow serial monitor to stabilize

    // Initialize output pins
    pinMode(BUZZER_PIN, OUTPUT);
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(BUZZER_PIN, LOW);
    digitalWrite(LED_PIN, LOW);

    // Initialize ADC
    analogReadResolution(12); // 12-bit ADC (0 - 4095)

    Serial.println("\n--- Freezer Temperature Alarm System ---");

    connectWiFi();

    // Setup Web Server Routes
    server.on("/", handleRoot);
    server.begin();
    Serial.println("Web server started.");
}

// ------------------------------------------------------------------
// Main Loop
// ------------------------------------------------------------------
void loop() {
    server.handleClient(); // Listen for incoming HTTP requests

    // Read temperature every cycle
    currentTemperature = readTemperature();

    // Evaluate and execute alarm logic
    handleAlarmLogic();

    // Small delay to stabilize ADC reads and prevent watchdog resets
    delay(50);
}

// ------------------------------------------------------------------
// Functions
// ------------------------------------------------------------------

void connectWiFi() {
    Serial.print("Connecting to Wi-Fi: ");
    Serial.println(WIFI_SSID);

    WiFi.mode(WIFI_STA);
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("\nWi-Fi Connected!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());
}

float readTemperature() {
    // Read the analog value (0-4095)
    int adcValue = analogRead(NTC_PIN);

    // Prevent division by zero if pin is shorted to Ground or 3.3V
    if (adcValue == 0) return -99.0;
    if (adcValue >= 4095) return 99.0;

    // Calculate NTC Resistance
    // Based on Voltage Divider: Vout = Vcc * (R_NTC / (R_NTC + R_SERIES))
    // Derives to: R_NTC = R_SERIES * (ADC / (4095 - ADC))
    float ntcResistance = SERIES_RESISTOR * ((float)adcValue / (4095.0 - (float)adcValue));

    // Apply Steinhart-Hart equation
    float steinhart;
    steinhart = ntcResistance / NOMINAL_RESISTANCE;       // (R/Ro)
    steinhart = log(steinhart);                           // ln(R/Ro)
    steinhart /= B_COEFFICIENT;                           // 1/B * ln(R/Ro)
    steinhart += 1.0 / (NOMINAL_TEMPERATURE + 273.15);    // + (1/To)
    steinhart = 1.0 / steinhart;                          // Invert
    steinhart -= 273.15;                                  // Convert Kelvin to Celsius

    return steinhart;
}

void handleAlarmLogic() {
    if (currentTemperature > ALARM_THRESHOLD) {
        isAlarmActive = true;

        // Non-blocking toggle for LED and Buzzer
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis >= blinkInterval) {
            previousMillis = currentMillis;
            toggleState = !toggleState;
            digitalWrite(LED_PIN, toggleState ? HIGH : LOW);
            digitalWrite(BUZZER_PIN, toggleState ? HIGH : LOW);
        }
    } else {
        isAlarmActive = false;
        // Ensure outputs are turned off when temperature is safe
        digitalWrite(LED_PIN, LOW);
        digitalWrite(BUZZER_PIN, LOW);
        toggleState = false;
    }
}

void handleRoot() {
    // Construct a simple, auto-refreshing HTML dashboard
    String html = "<!DOCTYPE html><html><head>";
    html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
    html += "<meta http-equiv='refresh' content='5'>"; // Auto-refresh every 5 seconds
    html += "<style>";
    html += "body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }";
    html += ".temp { font-size: 3em; font-weight: bold; }";
    html += ".status-ok { color: green; font-size: 2em; }";
    html += ".status-alarm { color: red; font-size: 2em; font-weight: bold; animation: blinker 1s linear infinite; }";
    html += "@keyframes blinker { 50% { opacity: 0; } }";
    html += "</style></head><body>";

    html += "<h1>Freezer Monitor Dashboard</h1>";
    html += "<div class='temp'>" + String(currentTemperature, 1) + " &deg;C</div>";

    if (isAlarmActive) {
        html += "<div class='status-alarm'>WARNING: TEMPERATURE HIGH</div>";
    } else {
        html += "<div class='status-ok'>STATUS: NORMAL</div>";
    }

    html += "</body></html>";

    // Send the response to the client
    server.send(200, "text/html", html);
}

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: ¿Qué tipo de sensor de temperatura utiliza el sistema de monitorización descrito?




Pregunta 2: ¿Qué tipo de alarma activa el sistema cuando la temperatura supera el umbral seguro?




Pregunta 3: ¿Cuál es el umbral de temperatura de ejemplo mencionado para activar la alarma?




Pregunta 4: ¿Cuál es la latencia esperada al servir datos en tiempo real al panel web local?




Pregunta 5: En el contexto de seguridad alimentaria, ¿qué problema busca evitar este sistema?




Pregunta 6: ¿Para qué tipo de muestras de laboratorio es útil este sistema de monitorización?




Pregunta 7: ¿Qué función cumple el sistema para los técnicos de HVAC y refrigeración?




Pregunta 8: ¿Qué ventaja ofrece el sistema para la monitorización de instalaciones remotas?




Pregunta 9: ¿Qué tecnología de conectividad inalámbrica utiliza el sistema de monitorización?




Pregunta 10: ¿Qué tipo de panel se utiliza para visualizar los datos en tiempo real?




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