Fabricación inteligente

Monitorización de temperatura en cámaras frigoríficas con sensores MQTT y alertas de desviación

Monitoriza congeladores y cámaras frigoríficas con sensores ESP32 que publican por MQTT, detecta desviaciones reales de temperatura sin alarmas molestas por aperturas de puerta, señala sensores desconectados y mantén un registro de desviaciones.

Monitorización de temperatura en cámaras frigoríficas con sensores inalámbricos en una cámara de congelación que envían alertas de desviación a un dashboard MQTT en la nube
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

La monitorización de temperatura en cámaras frigoríficas protege alimentos, ingredientes, medicamentos y muestras que pueden perderse en pocas horas cuando falla un congelador o una cámara de frío. Este caso de uso muestra cómo instalar sensores MQTT en congeladores y cámaras frigoríficas, distinguir las desviaciones reales de temperatura de las aperturas de puerta inofensivas, detectar sensores que dejan de comunicar y mantener un registro de desviaciones que puedas enseñar a un auditor.

Qué puede fallar en una cámara frigorífica

La mayoría de las pérdidas en almacenamiento en frío no proceden de averías espectaculares. Proceden de sucesos corrientes que nadie advierte a tiempo:

  • Una puerta que queda entreabierta tras una entrega nocturna.
  • Un compresor que salta una tarde calurosa y no vuelve a arrancar.
  • Un evaporador que se congela, de modo que la cámara se calienta lentamente durante horas.
  • Un corte de luz durante el fin de semana.
  • Un ciclo de desescarche que dura demasiado tras un cambio en el controlador.

Un registro manual de temperatura, rellenado dos veces por turno, no detecta ninguno de estos sucesos entre lecturas. La monitorización continua con alertas cierra ese hueco. Los mismos principios se aplican al transporte refrigerado, tratado en el artículo de monitorización de la cadena de frío; este se centra en congeladores y cámaras fijas en una planta, un almacén o una cocina.

La configuración

Componente Función Ejemplo
Sonda de temperatura Mide la temperatura del aire o del producto DS18B20 estanca con cable plano que pasa por la junta de la puerta
Contacto de puerta Explica las subidas breves de temperatura Interruptor reed en el marco de la puerta
Nodo sensor Lee la sonda y la puerta, publica ESP32 montado fuera del congelador con alimentación de red
Broker MQTT Recibe lecturas y alertas Broker MQTT gestionado de ConnectMQ
Lógica de alertas Detección de desviaciones y de sensores desconectados Reglas de umbral del portal más un servicio en Python
Registro de desviaciones Evidencia para auditorías y reclamaciones Base de datos escrita por el servicio de alertas

Mantén el ESP32 fuera del espacio frío. La electrónica y las baterías sufren a temperaturas de congelación, y las señales Wi-Fi no atraviesan las paredes metálicas de una cámara. Solo el cable de la sonda entra.

Dónde colocar la sonda

La temperatura del aire cerca del evaporador cambia rápido y exagera cada apertura de puerta. La temperatura del producto cambia despacio y refleja lo que realmente importa. Un compromiso habitual es colocar la sonda en la zona más cálida de la cámara, lejos de la salida del evaporador y, opcionalmente, dentro de una pequeña botella de glicol o un simulador de producto que la amortigüe, para que las lecturas sigan la temperatura del producto y no las ráfagas de aire. Haz una vez un mapeo de la cámara con varias sondas para encontrar el punto caliente antes de elegir la posición definitiva.

Firmware del sensor

El sketch siguiente publica la temperatura y el estado de la puerta cada 30 segundos, e inmediatamente cuando la puerta cambia. Define un mensaje Last Will, de modo que el broker anuncia el sensor como desconectado si desaparece. Instala PubSubClient, OneWire y DallasTemperature. Para los detalles de cableado del sensor, consulta el tutorial ESP32 DS18B20 con MQTT.

#include <WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* CLIENT_ID = "freezer2-6c0f3b";
const char* BASE = "connectmq/demo/6c0f3b/warehouse/freezer2";

const int PROBE_PIN = 4;
const int DOOR_PIN = 27;      // reed switch to GND, closed door = LOW
const uint32_t PERIOD_MS = 30000;

OneWire oneWire(PROBE_PIN);
DallasTemperature probe(&oneWire);
WiFiClient net;
PubSubClient mqtt(net);
char topicTelemetry[96], topicStatus[96];
int lastDoor = -1;
uint32_t lastPub = 0;

void connectAll() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while (WiFi.status() != WL_CONNECTED) delay(250);
  }
  while (!mqtt.connected()) {
    if (mqtt.connect(CLIENT_ID, topicStatus, 1, true, "offline")) {
      mqtt.publish(topicStatus, "online", true);
    } else {
      delay(3000);
    }
  }
}

void publishReading(bool doorOpen) {
  probe.requestTemperatures();
  float t = probe.getTempCByIndex(0);
  char payload[128];
  if (t == DEVICE_DISCONNECTED_C) {
    snprintf(payload, sizeof(payload), "{\"temp_c\":null,\"door_open\":%s,\"fault\":\"probe\"}",
             doorOpen ? "true" : "false");
  } else {
    snprintf(payload, sizeof(payload), "{\"temp_c\":%.2f,\"door_open\":%s,\"rssi\":%d}",
             t, doorOpen ? "true" : "false", WiFi.RSSI());
  }
  mqtt.publish(topicTelemetry, payload, true);
}

void setup() {
  pinMode(DOOR_PIN, INPUT_PULLUP);
  snprintf(topicTelemetry, sizeof(topicTelemetry), "%s/telemetry", BASE);
  snprintf(topicStatus, sizeof(topicStatus), "%s/status", BASE);
  probe.begin();
  WiFi.mode(WIFI_STA);
  mqtt.setServer("broker.connectmq.com", 1883);
  connectAll();
}

void loop() {
  connectAll();
  mqtt.loop();
  int door = digitalRead(DOOR_PIN) == HIGH;  // HIGH = magnet away = open
  if (door != lastDoor || millis() - lastPub >= PERIOD_MS) {
    publishReading(door);
    lastDoor = door;
    lastPub = millis();
  }
  delay(200);
}

El Last Will es la red de seguridad que nunca tuvo un registro manual: si el nodo pierde la alimentación o el Wi-Fi, el broker publica offline en su topic de estado tras el timeout del keepalive. La guía de Last Will en MQTT con ESP32 explica el mecanismo.

Lógica de desviaciones sin alarmas molestas

El enfoque ingenuo, alarmar siempre que la temperatura supere el límite, fracasa en un día. Cada entrega abre la puerta, la temperatura del aire se dispara y el personal aprende a ignorar la alarma. Una buena monitorización de temperatura en cámaras frigoríficas combina varias reglas:

  1. Límite más retardo. Genera una desviación solo si la temperatura permanece por encima del límite durante un tiempo determinado, por ejemplo 15 minutos para un congelador.
  2. Retardo según la puerta. Mientras la puerta está abierta, permite un periodo de gracia más largo, pero genera una alerta independiente de puerta abierta si permanece abierta demasiado tiempo.
  3. Límite crítico. Una temperatura mucho más alta dispara la alerta de inmediato, sin retardo.
  4. Sensores desconectados y fallos de sonda. Un sensor silencioso o una sonda desconectada son una alerta por sí mismos.
  5. Registro de la desviación. Cada desviación obtiene hora de inicio, hora de fin, temperatura pico y duración.

Los límites en sí proceden de tus productos y de tu plan de seguridad alimentaria o de calidad. Usa esos documentos en lugar de cifras genéricas.

Servicio de desviaciones en Python

import json
import sqlite3
import time
import paho.mqtt.client as mqtt

PREFIX = "connectmq/demo/6c0f3b/warehouse"
LIMIT_C = -15.0          # from your product requirements
HARD_LIMIT_C = -5.0
DELAY_S = 15 * 60
DOOR_MAX_S = 5 * 60
STALE_S = 3 * 60

db = sqlite3.connect("excursions.db", check_same_thread=False)
db.execute("""CREATE TABLE IF NOT EXISTS excursions (
    unit TEXT, start_ts INTEGER, end_ts INTEGER, peak_c REAL, reason TEXT)""")
units = {}

def alert(client, unit, kind, detail):
    msg = {"ts": int(time.time()), "unit": unit, "kind": kind, **detail}
    client.publish(f"{PREFIX}/{unit}/alert", json.dumps(msg), qos=1, retain=True)
    print("ALERT", msg)

def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{PREFIX}/+/telemetry", qos=1)
    client.subscribe(f"{PREFIX}/+/status", qos=1)

def on_message(client, userdata, msg):
    unit = msg.topic.split("/")[4]
    now = time.time()
    u = units.setdefault(unit, {"above_since": None, "door_since": None,
                                "excursion": None, "seen": now})
    if msg.topic.endswith("/status"):
        if msg.payload == b"offline":
            alert(client, unit, "offline", {})
        return

    d = json.loads(msg.payload)
    u["seen"] = now
    if d.get("temp_c") is None:
        alert(client, unit, "probe_fault", {})
        return
    t = d["temp_c"]

    u["door_since"] = (u["door_since"] or now) if d["door_open"] else None
    if u["door_since"] and now - u["door_since"] > DOOR_MAX_S:
        alert(client, unit, "door_open_too_long", {"seconds": int(now - u["door_since"])})
        u["door_since"] = now

    if t > LIMIT_C:
        u["above_since"] = u["above_since"] or now
        delay = DELAY_S * (2 if d["door_open"] else 1)
        exc = u["excursion"]
        if exc:
            exc["peak"] = max(exc["peak"], t)
        elif t > HARD_LIMIT_C or now - u["above_since"] > delay:
            u["excursion"] = {"start": u["above_since"], "peak": t}
            alert(client, unit, "excursion_start", {"temp_c": t, "limit_c": LIMIT_C})
    else:
        exc = u["excursion"]
        if exc:
            db.execute("INSERT INTO excursions VALUES (?,?,?,?,?)",
                       (unit, int(exc["start"]), int(now), exc["peak"], "above_limit"))
            db.commit()
            alert(client, unit, "excursion_end",
                  {"duration_min": round((now - exc["start"]) / 60, 1), "peak_c": exc["peak"]})
        u["above_since"] = None
        u["excursion"] = None

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="cold-alerts-6c0f3b")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()

while True:
    time.sleep(30)
    for unit, u in units.items():
        if time.time() - u["seen"] > STALE_S:
            alert(client, unit, "stale", {"seconds_silent": int(time.time() - u["seen"])})
            u["seen"] = time.time()

La hora de inicio de la desviación se registra como el momento en que la temperatura cruzó el límite por primera vez, no cuando expiró el retardo, para que el registro muestre la duración real. En los casos más sencillos también puedes crear reglas de alerta por umbral sobre el campo temp_c directamente en el portal de ConnectMQ y revisar cada cruce en su registro de alertas, manteniendo el servicio en Python para la lógica de retardo y de puerta.

Hacer llegar las alertas a las personas

El servicio publica las alertas en MQTT; algo tiene que llegar todavía a un teléfono a las 3 de la madrugada. Como ConnectMQ no envía correos electrónicos ni SMS por sí mismo, el patrón honesto es una herramienta externa que se suscriba a los topics de alerta: un flujo de Node-RED con un nodo de correo o de mensajería, notificaciones de Home Assistant para instalaciones pequeñas, o unas pocas líneas más en el servicio de Python que llamen a tu proveedor de notificaciones. Define una ruta de escalado: primero el responsable de turno, después el técnico de guardia de mantenimiento y, si nadie responde, el director del centro.

Gestionar los ciclos de desescarche

El desescarche automático es la otra fuente frecuente de falsas alarmas. Durante el desescarche, el evaporador se calienta y la temperatura del aire cercano sube durante un breve periodo, lo cual es normal. Tres medidas evitan que provoque desviaciones. Primero, mantén la sonda lejos del evaporador, como se ha descrito. Segundo, asegúrate de que el retardo de desviación sea más largo que un desescarche normal en esa unidad, algo que se ve claramente en un día de datos registrados. Tercero, si el controlador de refrigeración expone una señal de desescarche, publícala junto a la temperatura y alarga el retardo mientras el desescarche esté activo, igual que hace el servicio con las aperturas de puerta. Un desescarche que dura mucho más de lo habitual merece en sí mismo una alerta, porque suele indicar una resistencia, un sensor o un ajuste del controlador defectuosos.

Checklist de despliegue

  1. Mapea cada cámara con varias sondas durante un día para encontrar el punto caliente.
  2. Instala un nodo por unidad, con la electrónica fuera y la sonda en el punto caliente.
  3. Define límites y retardos a partir de los requisitos de tus productos y tu plan de calidad.
  4. Prueba las alarmas: abre la puerta, desenchufa un nodo, desconecta una sonda y confirma que llega cada alerta.
  5. Calibra las sondas frente a un termómetro de referencia y registra la comprobación.
  6. Revisa el registro de desviaciones cada semana y actúa sobre los reincidentes, como una puerta que se deja abierta a menudo.
  7. Pasa a un broker privado con credenciales del portal y TLS en el puerto 8883 antes de entrar en producción.

De la demo a producción

El tutorial se ejecuta en el servidor MQTT público gratuito, donde todos los topics son visibles para cualquiera, lo que está bien para pruebas pero no para datos operativos. Para producción, un broker MQTT en la nube da a cada nodo de congelador una conexión cifrada y autenticada y permite que el servicio de alertas, los dashboards y el equipo de calidad se suscriban desde cualquier lugar. Los registros de temperatura también complementan el control de calidad con IoT en fabricación y la trazabilidad en fabricación por lotes, ya que las ventanas de desviación pueden vincularse a los lotes almacenados en ese momento. La guía de fabricación inteligente integra todo esto en una arquitectura para toda la planta.

Monitoriza tus cámaras frigoríficas con ConnectMQ

ConnectMQ ofrece un broker MQTT gestionado y privado con TLS, soporte de Last Will, retained messages, un dashboard en directo y reglas de alerta por umbral en el portal. Crea un broker con el plan gratuito Serverless en app.connectmq.com, sin tarjeta de crédito, y conecta hoy tu primer congelador.

Preguntas frecuentes

¿Con qué frecuencia debe registrarse la temperatura de una cámara frigorífica?

Lo habitual en monitorización continua es cada 30 segundos a 5 minutos. Informar más rápido permite alertas más tempranas, mientras que el retardo de desviación evita las alarmas molestas.

¿Cómo evito alarmas cada vez que se abre la puerta?

Exige que la temperatura permanezca por encima del límite durante un periodo de retardo antes de alertar, alarga ese retardo mientras la puerta está abierta y genera una alerta independiente si la puerta permanece abierta demasiado tiempo.

¿Qué ocurre si un sensor se queda sin alimentación?

Con un mensaje Last Will, el broker publica un estado offline tras el timeout del keepalive, y el servicio de alertas lo trata como una alarma.

¿La sonda debe medir la temperatura del aire o la del producto?

La temperatura del producto es la que más importa. Colocar la sonda en un amortiguador, como una botella de glicol, en el punto más cálido da lecturas que siguen la temperatura del producto e ignoran los picos breves del aire.

Artículos relacionados

OEE vs TEEP vs OOE: ¿qué indicador deberías usar?

OEE, OOE y TEEP comparten los mismos factores de rendimiento y calidad, pero se miden frente a bases de tiempo distintas. Esta comparativa resuelve un único ejemplo y enumera las señales MQTT que necesita cada indicador.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.