Smart Manufacturing

Kühlhaus-Temperaturüberwachung mit MQTT-Sensoren und Alarmen bei Abweichungen

Überwachen Sie Tiefkühler und Kühlräume mit ESP32-Sensoren, die über MQTT veröffentlichen, erkennen Sie echte Temperaturabweichungen ohne Störalarme durch Türöffnungen, melden Sie ausgefallene Sensoren und führen Sie ein Abweichungsprotokoll.

Kühlhaus-Temperaturüberwachung mit Funksensoren in einem begehbaren Tiefkühlraum, die Abweichungsalarme an ein Cloud-MQTT-Dashboard senden
Probieren Sie es auf Ihrem eigenen MQTT-Broker ausHolen Sie sich im Free-Tarif einen privaten, verwalteten MQTT-Broker und starten Sie mit fertigen Codebeispielen.
Kostenlos testen Codebeispiele Keine Kreditkarte erforderlich

Die Kühlhaus-Temperaturüberwachung schützt Lebensmittel, Zutaten, Arzneimittel und Proben, die innerhalb weniger Stunden verloren sein können, wenn ein Tiefkühler oder Kühlraum ausfällt. Dieser Anwendungsfall zeigt, wie Sie MQTT-Sensoren in Tiefkühler und Kühlräume bringen, echte Temperaturabweichungen von harmlosen Türöffnungen unterscheiden, ausgefallene Sensoren erkennen und ein Abweichungsprotokoll führen, das Sie einem Auditor vorlegen können.

Was im Kühlhaus schiefgehen kann

Die meisten Verluste im Kühlhaus entstehen nicht durch spektakuläre Ausfälle, sondern durch alltägliche Ereignisse, die niemand rechtzeitig bemerkt:

  • Eine Tür, die nach einer nächtlichen Anlieferung angelehnt bleibt.
  • Ein Verdichter, der an einem heißen Nachmittag abschaltet und nicht wieder anläuft.
  • Ein Verdampfer, der vereist, sodass sich der Raum über Stunden langsam erwärmt.
  • Ein Stromausfall am Wochenende.
  • Ein Abtauzyklus, der nach einer Reglerumstellung zu lange läuft.

Ein manuelles Temperaturprotokoll, das zweimal pro Schicht ausgefüllt wird, erkennt nichts davon zwischen den Ablesungen. Kontinuierliche Überwachung mit Alarmen schließt diese Lücke. Dieselben Prinzipien gelten für gekühlte Transporte, die im Artikel zur Kühlkettenüberwachung behandelt werden; dieser hier konzentriert sich auf fest installierte Tiefkühler und Kühlräume in Werk, Lager oder Küche.

Das Setup

Komponente Aufgabe Beispiel
Temperaturfühler Misst Luft- oder Produkttemperatur Wasserdichter DS18B20 an einem Flachkabel durch die Türdichtung
Türkontakt Erklärt kurze Temperaturanstiege Reedschalter am Türrahmen
Sensorknoten Liest Fühler und Tür, veröffentlicht ESP32 außerhalb des Tiefkühlers mit Netzversorgung
MQTT-Broker Empfängt Messwerte und Alarme Verwalteter MQTT-Broker von ConnectMQ
Alarmlogik Erkennung von Abweichungen und Ausfällen Schwellenwertregeln im Portal plus ein Python-Dienst
Abweichungsprotokoll Nachweis für Audits und Reklamationen Datenbank, die der Alarmdienst beschreibt

Halten Sie den ESP32 außerhalb des Kühlbereichs. Elektronik und Batterien kommen mit Tiefkühltemperaturen schlecht zurecht, und WLAN-Signale dringen nicht durch die Metallwände eines Kühlraums. Nur das Fühlerkabel kommt nach innen.

Wo der Fühler hingehört

Die Lufttemperatur nahe dem Verdampfer ändert sich schnell und übertreibt jede Türöffnung. Die Produkttemperatur ändert sich langsam und spiegelt wider, worauf es tatsächlich ankommt. Ein gängiger Kompromiss ist, den Fühler im wärmsten Bereich des Raums, entfernt vom Verdampferauslass, zu platzieren und ihn optional in eine kleine Flasche mit Glykol oder einen Produktsimulator zu stecken, der ihn puffert, sodass die Messwerte der Produkttemperatur folgen statt Luftstößen. Kartieren Sie den Raum einmal mit einigen Fühlern, um die warme Stelle zu finden, bevor Sie die dauerhafte Position wählen.

Sensor-Firmware

Der folgende Sketch veröffentlicht Temperatur und Türzustand alle 30 Sekunden sowie sofort bei einer Türänderung. Er setzt eine Last-Will-Nachricht, sodass der Broker den Sensor als offline meldet, wenn er verschwindet. Installieren Sie PubSubClient, OneWire und DallasTemperature. Details zur Verdrahtung des Sensors finden Sie im Tutorial ESP32 DS18B20 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;      // Reedschalter gegen GND, Tür geschlossen = 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 entfernt = offen
  if (door != lastDoor || millis() - lastPub >= PERIOD_MS) {
    publishReading(door);
    lastDoor = door;
    lastPub = millis();
  }
  delay(200);
}

Der Last Will ist das Sicherheitsnetz, das ein manuelles Protokoll nie hatte: Verliert der Knoten Strom oder WLAN, veröffentlicht der Broker nach Ablauf des Keepalive-Timeouts offline auf dem Status-Topic. Die Anleitung ESP32 MQTT Last Will erklärt den Mechanismus.

Abweichungslogik ohne Störalarme

Der naive Ansatz, bei jeder Grenzwertüberschreitung zu alarmieren, scheitert innerhalb eines Tages. Jede Anlieferung öffnet die Tür, die Lufttemperatur springt nach oben, und das Personal lernt, den Alarm zu ignorieren. Eine gute Kühlhaus-Temperaturüberwachung kombiniert mehrere Regeln:

  1. Grenzwert plus Verzögerung. Eine Abweichung wird nur gemeldet, wenn die Temperatur eine festgelegte Zeit über dem Grenzwert bleibt, zum Beispiel 15 Minuten bei einem Tiefkühler.
  2. Türabhängige Verzögerung. Solange die Tür offen ist, gilt eine längere Karenzzeit, aber ein separater Tür-offen-Alarm wird ausgelöst, wenn sie zu lange offen bleibt.
  3. Harter Grenzwert. Eine deutlich höhere Temperatur löst unabhängig von der Verzögerung sofort aus.
  4. Ausfälle und Fühlerfehler. Ein verstummter Sensor oder ein abgeklemmter Fühler ist ein eigener Alarm.
  5. Abweichungsdatensatz. Jede Abweichung erhält Startzeit, Endzeit, Spitzentemperatur und Dauer.

Die Grenzwerte selbst ergeben sich aus Ihren Produkten und Ihrem Lebensmittelsicherheits- bzw. Qualitätsplan (etwa dem HACCP-Konzept). Verwenden Sie diese Unterlagen statt pauschaler Zahlen.

Abweichungsdienst in Python

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

PREFIX = "connectmq/demo/6c0f3b/warehouse"
LIMIT_C = -15.0          # aus Ihren Produktanforderungen
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()

Als Startzeit der Abweichung wird der Moment erfasst, in dem die Temperatur den Grenzwert erstmals überschritten hat, nicht der Ablauf der Verzögerung, sodass das Protokoll die tatsächliche Dauer zeigt. Für die einfachsten Fälle können Sie Schwellenwert-Alarmregeln auf das Feld temp_c auch direkt im ConnectMQ-Portal anlegen und jede Überschreitung im Alarmprotokoll nachvollziehen, während der Python-Dienst die Verzögerungs- und Türlogik übernimmt.

Alarme an die richtigen Personen bringen

Der Dienst veröffentlicht Alarme über MQTT; um 3 Uhr nachts muss aber trotzdem etwas ein Telefon erreichen. Da ConnectMQ selbst keine E-Mails oder SMS versendet, ist das ehrliche Muster ein externes Werkzeug, das die Alarm-Topics abonniert: ein Node-RED-Flow mit einem E-Mail- oder Messaging-Node, Home-Assistant-Benachrichtigungen für kleinere Standorte oder ein paar zusätzliche Zeilen im Python-Dienst, die Ihren Benachrichtigungsanbieter aufrufen. Legen Sie einen Eskalationspfad fest: zuerst die Schichtleitung, dann die Rufbereitschaft der Instandhaltung, dann die Standortleitung, falls niemand quittiert.

Umgang mit Abtauzyklen

Automatisches Abtauen ist die andere häufige Ursache für Fehlalarme. Während des Abtauens erwärmt sich der Verdampfer, und die Lufttemperatur in seiner Nähe steigt kurzzeitig an, was normal ist. Drei Maßnahmen verhindern, dass dadurch Abweichungen ausgelöst werden. Erstens halten Sie den Fühler wie oben beschrieben vom Verdampfer fern. Zweitens stellen Sie sicher, dass die Abweichungsverzögerung länger ist als ein normaler Abtauzyklus dieses Geräts, was Sie in den aufgezeichneten Daten eines Tages deutlich sehen. Drittens: Stellt der Kälteregler ein Abtausignal bereit, veröffentlichen Sie es zusammen mit der Temperatur und verlängern die Verzögerung während des Abtauens, genau wie es der Dienst bei Türöffnungen tut. Ein Abtauvorgang, der deutlich länger als üblich dauert, ist selbst einen Alarm wert, denn er deutet oft auf eine defekte Heizung, einen defekten Fühler oder eine falsche Reglereinstellung hin.

Checkliste für den Rollout

  1. Kartieren Sie jeden Raum einen Tag lang mit mehreren Fühlern, um die warme Stelle zu finden.
  2. Installieren Sie einen Knoten pro Gerät, Elektronik außen, Fühler an der warmen Stelle.
  3. Legen Sie Grenzwerte und Verzögerungen anhand Ihrer Produktanforderungen und Ihres Qualitätsplans fest.
  4. Testen Sie die Alarme: Tür öffnen, Knoten vom Strom trennen, Fühler abklemmen, und bestätigen Sie, dass jeder Alarm ankommt.
  5. Kalibrieren Sie die Fühler gegen ein Referenzthermometer und dokumentieren Sie die Prüfung.
  6. Prüfen Sie das Abweichungsprotokoll wöchentlich und gehen Sie Wiederholungsfällen nach, etwa einer Tür, die oft offen bleibt.
  7. Wechseln Sie vor dem Go-live auf einen privaten Broker mit Zugangsdaten aus dem Portal und TLS auf Port 8883.

Von der Demo zur Produktion

Das Tutorial läuft auf dem öffentlichen MQTT-Broker, auf dem alle Topics für jeden sichtbar sind. Das ist zum Testen in Ordnung, nicht aber für Betriebsdaten. Für die Produktion gibt ein Cloud-MQTT-Broker jedem Tiefkühlknoten eine verschlüsselte, authentifizierte Verbindung und erlaubt Alarmdienst, Dashboards und Qualitätsteam, von überall zu abonnieren. Temperaturaufzeichnungen ergänzen außerdem die IoT-Qualitätskontrolle in der Fertigung und die chargenbezogene Rückverfolgbarkeit in der Fertigung, da sich Abweichungszeiträume mit den zu dieser Zeit gelagerten Losen verknüpfen lassen. Der Smart-Manufacturing-Leitfaden ordnet all das in eine werksweite Architektur ein.

Überwachen Sie Ihr Kühlhaus mit ConnectMQ

ConnectMQ bietet einen privaten MQTT-Broker mit TLS, Last-Will-Unterstützung, retained Messages, einem Live-Dashboard und Schwellenwert-Alarmregeln im Portal. Erstellen Sie unter app.connectmq.com einen Broker im kostenlosen Serverless-Plan, ganz ohne Kreditkarte, und verbinden Sie noch heute Ihren ersten Tiefkühler.

Häufig gestellte Fragen

Wie oft sollte die Kühlhaustemperatur erfasst werden?

Für die kontinuierliche Überwachung sind 30 Sekunden bis 5 Minuten üblich. Schnellere Meldungen ermöglichen schnellere Alarme, während die Abweichungsverzögerung Störalarme verhindert.

Wie vermeide ich Alarme bei jeder Türöffnung?

Verlangen Sie, dass die Temperatur eine Verzögerungszeit lang über dem Grenzwert bleibt, bevor alarmiert wird, verlängern Sie diese Verzögerung bei offener Tür und lösen Sie einen separaten Alarm aus, wenn die Tür zu lange offen bleibt.

Was passiert, wenn ein Sensor keinen Strom mehr hat?

Mit einer Last-Will-Nachricht veröffentlicht der Broker nach Ablauf des Keepalive-Timeouts einen Offline-Status, und der Alarmdienst behandelt ihn als Alarm.

Sollte der Fühler Luft- oder Produkttemperatur messen?

Die Produkttemperatur ist am wichtigsten. Wird der Fühler in einem Puffer wie einer Glykolflasche an der wärmsten Stelle platziert, folgen die Messwerte der Produkttemperatur und ignorieren kurze Luftspitzen.

Verwandte Artikel

OEE vs. TEEP vs. OOE: Welche Kennzahl sollten Sie verwenden?

OEE, OOE und TEEP teilen sich die Faktoren Leistung und Qualität, beziehen sich aber auf unterschiedliche Zeitbasen. Dieser Vergleich rechnet ein Beispiel durch und listet die MQTT-Signale, die jede Kennzahl benötigt.

7 Min. Lesezeit

Alle Artikel →

Ihr privater MQTT-Broker ist nur wenige Klicks entfernt

Konto anlegen, Broker-Zugangsdaten erhalten und das erste Gerät verbinden — ohne Server, die installiert, gepatcht oder skaliert werden müssen.