Bei der Kühlkettenüberwachung geht es darum nachzuweisen, dass gekühlte Lebensmittel, Impfstoffe oder Biologika ihren Temperaturbereich zwischen Depot und Kunde nie verlassen haben, und schnell zu reagieren, wenn es doch passiert. In diesem Artikel entwerfen Sie ein Überwachungssystem für Kühl-Lkw und Container, das Temperaturdaten per Mobilfunk-MQTT sendet, Funklöcher ohne Datenverlust übersteht und Abweichungsalarme danach auslöst, wie lange ein Grenzwert überschritten war, statt bei jeder einzelnen Spitze.
Was Kühlkettenüberwachung nachweisen muss
Die Temperaturaufzeichnung im Transport hat zwei Zielgruppen. Das Betriebspersonal braucht Live-Informationen, damit ein Fahrer eine angelehnte Tür oder ein ausfallendes Kühlaggregat beheben kann, bevor die Ladung verloren ist. Das Qualitätspersonal braucht nach der Fahrt eine lückenlose Aufzeichnung, oft um Kunden und die Anforderungen der Guten Vertriebspraxis (GDP) zu erfüllen, die jeden Messwert mit Zeit und Ort zeigt.
Diese beiden Anforderungen bestimmen den gesamten Entwurf:
| Anforderung | Warum sie wichtig ist | Konsequenz für den Entwurf |
|---|---|---|
| Live-Transparenz | Eingreifen, bevor die Ware beschädigt ist | Mobilfunkanbindung, MQTT-Telemetrie alle paar Minuten |
| Keine Lücken in der Aufzeichnung | Eine fehlende Stunde kann eine Sendung ungültig machen | Store-and-Forward-Pufferung auf dem Gerät |
| Vertrauenswürdige Zeitstempel | Reihenfolge und Dauer von Abweichungen müssen beweisbar sein | Zeitstempel zum Messzeitpunkt, nicht zum Eingangszeitpunkt |
| Kontext | War die Tür offen? Wo war der Lkw? | Türsensoren und GPS zusätzlich zur Temperatur |
| Aussagekräftige Alarme | Abtauzyklen und Türöffnungen verursachen kurze Spitzen | Dauerbasierte Abweichungsregeln |
Hardware im Fahrzeug
Ein typischer Aufbau besteht aus drei Teilen:
- Temperaturfühler im Laderaum, meist zwei oder mehr: einer nahe dem Verdampfer und einer hinten bei den Türen, wo warme Luft eindringt. Drahtlose BLE-Logger sind für die Überwachung auf Palettenebene verbreitet; kabelgebundene Fühler eignen sich für fest installierte Kühlaggregate.
- Ein Telematik-Gateway mit LTE-M-, NB-IoT- oder LTE-Modem und GPS. Das kann ein kommerzielles Gerät oder ein kleines Linux-Board mit Mobilfunk-HAT sein. Es liest die Fühler aus, puffert Daten und veröffentlicht per MQTT.
- Türkontaktsensoren, damit sich jeder Temperaturanstieg einer Öffnung zuordnen lässt.
Das Gateway ist das einzige Gerät, das mit dem Broker spricht. Selbst ein langer Auflieger voller BLE-Palettenlogger wird zu einer einzigen MQTT-Verbindung.
Topic-Design für die Kühlkettenüberwachung
Organisieren Sie nach Fahrzeug der Flotte statt nach Fahrt; Fahrten sind Metadaten im Payload:
coldchain/<fleet>/<asset-id>/telemetry {"ts":1760600000,"t_front":3.8,"t_rear":4.6,"door":"closed","lat":41.01,"lon":28.97,"trip":"TR-8812"}
coldchain/<fleet>/<asset-id>/status retained {"online":true,"fw":"1.4.2","battery_v":12.6}
coldchain/<fleet>/<asset-id>/alarm {"type":"excursion","probe":"t_rear","max":9.4,"duration_s":1260,"trip":"TR-8812"}
coldchain/<fleet>/<asset-id>/config retained {"min":2.0,"max":8.0,"grace_s":900}
Das config-Topic retained zu halten, ist ein eleganter Kniff. Das Gateway abonniert es beim Verbinden, sodass der Wechsel einer Ladung von gekühlt auf tiefgekühlt eine einzige retained Veröffentlichung aus dem Dispositionssystem ist, und ein neu gestartetes Gateway erhält seine Grenzwerte sofort zurück. Stationäre Kühlräume und Tiefkühllager am Depot oder im Werk hängen Sie dagegen besser in die ISA-95-Struktur Ihres Unified Namespace (UNS) ein, etwa acme/werk-muenchen/lager/tiefkuehlung/kuehlraum-2/temperatur, damit Lager- und Transportdaten gemeinsam auswertbar sind.
Gateway-Code mit Store-and-Forward
Die Mobilfunkabdeckung auf Autobahnen, in Alpentunneln und in Häfen ist lückenhaft. Das Gateway muss offline weiter messen und alles senden, sobald die Verbindung zurückkehrt. Die folgende Python-Skizze nutzt paho-mqtt 2.x, MQTT 5 und eine SQLite-Warteschlange auf dem Gateway. Sie zielt auf den öffentlichen MQTT-Broker, sodass Sie sie auf jedem Computer ausprobieren können; ersetzen Sie read_probes() durch Ihren tatsächlichen Sensorcode.
import json
import random
import sqlite3
import time
import paho.mqtt.client as mqtt
PREFIX = "connectmq/demo/f2q7b5" # Ihr eigenes zufälliges Präfix
ASSET = "TRK-104"
BASE = f"{PREFIX}/coldchain/fleet1/{ASSET}"
SAMPLE_EVERY = 60 # Sekunden
db = sqlite3.connect("buffer.db")
db.execute("CREATE TABLE IF NOT EXISTS q (id INTEGER PRIMARY KEY, payload TEXT)")
connected = False
limits = {"min": 2.0, "max": 8.0, "grace_s": 900}
def read_probes():
# durch echte Sensoren ersetzen; die Werte simulieren eine gekühlte Ladung
return {"t_front": round(random.uniform(3, 5), 1), "t_rear": round(random.uniform(3.5, 6), 1),
"door": "closed"}
def on_connect(client, userdata, flags, reason_code, properties):
global connected
connected = not reason_code.is_failure
if connected:
client.subscribe(f"{BASE}/config", qos=1)
client.publish(f"{BASE}/status", json.dumps({"online": True}), qos=1, retain=True)
def on_disconnect(client, userdata, flags, reason_code, properties):
global connected
connected = False
def on_message(client, userdata, msg):
limits.update(json.loads(msg.payload))
def flush(client, batch=50):
rows = db.execute("SELECT id, payload FROM q ORDER BY id LIMIT ?", (batch,)).fetchall()
for row_id, payload in rows:
info = client.publish(f"{BASE}/telemetry", payload, qos=1)
info.wait_for_publish(timeout=10)
if not info.is_published():
return # Verbindung abgebrochen; restliche Zeilen behalten
db.execute("DELETE FROM q WHERE id = ?", (row_id,))
db.commit()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"gw-{ASSET}-f2q7b5",
protocol=mqtt.MQTTv5)
client.will_set(f"{BASE}/status", json.dumps({"online": False}), qos=1, retain=True)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_message = on_message
client.reconnect_delay_set(min_delay=2, max_delay=120)
client.connect_async("broker.connectmq.com", 1883, keepalive=120)
client.loop_start()
while True:
reading = {"ts": int(time.time()), "trip": "TR-8812", **read_probes()}
db.execute("INSERT INTO q (payload) VALUES (?)", (json.dumps(reading),))
db.commit()
if connected:
flush(client)
time.sleep(SAMPLE_EVERY)
Jeder Messwert landet zuerst in der Warteschlange und wird erst gelöscht, wenn der Broker ihn mit QoS 1 bestätigt hat. Damit ist der Puffer die maßgebliche Datenquelle: Stromausfälle, Neustarts und lange Funklöcher können keine Lücken erzeugen, und das Feld ts hält fest, wann die Messung erfolgte, nicht wann sie ankam. Mehr zu Zustellgarantien finden Sie unter MQTT-QoS-Stufen erklärt.
Abweichungsalarme, die Rauschen ignorieren
Eine naive Regel „Alarm, wenn die Temperatur über 8 °C liegt“ schlägt jedes Mal an, wenn sich bei einem Lieferstopp die Türen öffnen oder der Verdampfer abtaut. Echte Kühlkettenalarmierung betrachtet die Dauer: Alarm nur dann, wenn ein Fühler länger als eine Karenzzeit außerhalb des Bereichs lag.
import json
import paho.mqtt.client as mqtt
PREFIX = "connectmq/demo/f2q7b5"
LIMITS = {"min": 2.0, "max": 8.0, "grace_s": 900}
state = {} # (asset, probe) -> Zeitstempel der ersten Bereichsüberschreitung
def check(client, asset, probe, value, ts):
key = (asset, probe)
out = value < LIMITS["min"] or value > LIMITS["max"]
if not out:
state.pop(key, None)
return
start = state.setdefault(key, ts)
if start is not None and ts - start >= LIMITS["grace_s"]:
alarm = {"type": "excursion", "probe": probe, "value": value, "since": start,
"duration_s": ts - start}
client.publish(f"{PREFIX}/coldchain/fleet1/{asset}/alarm", json.dumps(alarm), qos=1)
state[key] = None # ein Alarm pro Abweichung; Reset, sobald wieder im Bereich
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(f"{PREFIX}/coldchain/fleet1/+/telemetry", qos=1)
def on_message(client, userdata, msg):
asset = msg.topic.split("/")[-2]
r = json.loads(msg.payload)
for probe in ("t_front", "t_rear"):
if probe in r:
check(client, asset, probe, r[probe], r["ts"])
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="excursion-f2q7b5")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()
Da der Detektor den Messzeitstempel verwendet, verarbeitet er gepufferte Daten korrekt: Eine zwanzigminütige Abweichung in einem Tunnel wird auch dann als zwanzig Minuten erkannt, wenn der Rückstau eintrifft. Für einfache feste Grenzwerte auf einem Live-Wert sind die Schwellenwert-Alarmregeln im Portal ein schneller Einstieg; Dauerlogik wie diese gehört in Ihren eigenen Subscriber oder in Node-RED.
Die Flotte beobachten
Abonnieren Sie während der Tests einfach alles:
mosquitto_sub -h broker.connectmq.com -p 1883 -i ops-f2q7b5 -t "connectmq/demo/f2q7b5/coldchain/#" -v
Der öffentliche MQTT-Broker genügt für diesen Prototyp, doch er ist nicht für Produktionsdaten gedacht: Sendungsdaten und Kundenstandorte dürfen nicht über einen öffentlich lesbaren Broker laufen. Produktive Gateways sollten TLS auf Port 8883 und im Portal generierte Zugangsdaten verwenden.
Tipps zur Mobilfunkanbindung
- Payloads klein halten. Kurze Schlüssel und Messungen im Minutentakt halten die Datentarife überschaubar; bündeln Sie mehrere Messwerte pro Nachricht, wenn Ihr Tarif pro Nachricht abrechnet.
- Großzügiges Keep-Alive wählen. Werte von zwei bis fünf Minuten reduzieren das Aufwachen des Funkmoduls, ohne die Erkennung von Verbindungsabbrüchen zu stark zu verzögern.
- MQTT 5 Session Expiry nutzen, damit Abonnements kurze Abbrüche überstehen; siehe MQTT-5-Funktionen.
- Beim Wiederverbinden zurückhaltend sein. Exponentielle Verzögerungen verhindern, dass das Netz nach einem Zellwechsel überlastet wird.
- Das Modem im Blick behalten. Veröffentlichen Sie Signalstärke und Netztyp in
status, um Funklöcher zu diagnostizieren.
Häufige Fallstricke
Fühler nur am Verdampfer. Dieser Fühler zeigt die kälteste Luft im Laderaum und kann eine warme Zone an den Türen verdecken. Messen Sie dort, wo die Ware am stärksten gefährdet ist.
Serverseitige Zeitstempel. Wenn Sie Messwerte beim Eingang mit Zeitstempeln versehen, schrumpft ein gepufferter Rückstau auf eine einzige Minute zusammen, und Abweichungsdauern werden bedeutungslos. Versehen Sie Werte immer zum Messzeitpunkt mit einem Zeitstempel.
Alarmstürme nach dem Wiederverbinden. Ein Gateway, das eine Stunde Daten nachsendet, kann viele Alarme auf einmal auslösen. Alarmieren Sie einmal pro Abweichung, wie es der Detektor oben tut, und kennzeichnen Sie verspätete Alarme als „historisch“, damit Disponenten wissen, dass das Ereignis bereits vorbei ist.
Gemeinsame Zugangsdaten für die ganze Flotte. Ein einziges geleaktes Login legt dann jeden Lkw offen. Geben Sie jedem Gateway eigene Zugangsdaten und eine eigene Client-ID.
Checkliste für den Rollout
- Fühler an der wärmsten und kältesten Stelle des Laderaums platziert und kalibriert.
- Türsensoren installiert und in jeder Telemetrienachricht gemeldet.
- Gateway puffert in nichtflüchtigem Speicher und löscht erst nach Bestätigung.
- Zeitstempel von einer synchronisierten Uhr (GPS oder NTP).
- Grenzwerte als retained Konfiguration pro Fahrzeug bereitgestellt.
- Dauerbasierte Abweichungsregeln pro Produktkategorie.
- Ein dauerhafter Archiv-Subscriber, der jeden Messwert für Fahrtberichte in eine Datenbank schreibt.
- TLS und eigene Zugangsdaten pro Gateway.
Verwandte Muster
Flottenüberwachung hat viel mit anderen verteilten IoT-Systemen gemeinsam. Die Idee eines Gateways pro Fahrzeug entspricht den Feld-Gateways in einer Smart-City-IoT-Architektur, und viele Objekte zu Live-Statusansichten zu aggregieren, ist dasselbe Problem, das bei Smart Parking IoT gelöst wird. Für den Aufbau eines robusten Modells mit retained Zuständen zeigt unser Projekt zur Wasserleckerkennung retained Alarme in kleinerem Rahmen, und der Leitfaden zur IoT-Automatisierung enthält weitere Beispiele.
Betreiben Sie Ihre Kühlketten-Telemetrie auf ConnectMQ
Flottentelemetrie braucht einen Broker, der aus jedem Mobilfunknetz erreichbar, mit TLS abgesichert und rund um die Uhr gewartet ist. ConnectMQ bietet einen verwalteten MQTT-Broker mit MQTT 5, TLS, generierten Zugangsdaten und einem Live-Topic-Explorer, in dem Sie die Meldungen jedes Lkw verfolgen können. Starten Sie mit einem kostenlosen Serverless-Broker unter app.connectmq.com, ganz ohne Kreditkarte, und skalieren Sie auf einen kostenpflichtigen oder Dedicated-Tarif, wenn die Flotte wächst. Hintergründe zum Hosting finden Sie im Beitrag zum Cloud-MQTT-Broker.
Häufig gestellte Fragen
Wie oft sollte ein Kühl-Lkw die Temperatur melden?
Üblich ist eine Messung alle ein bis fünf Minuten. Messen Sie lokal in diesem Takt auch offline weiter und senden Sie die gepufferten Werte, sobald wieder Empfang besteht.
Was passiert, wenn der Lkw keinen Empfang hat?
Das Gateway speichert die Messwerte mit ihren Messzeitstempeln lokal und veröffentlicht sie nach dem Verbinden in der richtigen Reihenfolge, wobei jeder Wert erst gelöscht wird, wenn der Broker ihn bestätigt hat.
Warum auf die Dauer statt auf einen einzelnen hohen Messwert alarmieren?
Türöffnungen und Abtauzyklen verursachen kurze Spitzen, die der Ware nicht schaden. Eine Karenzzeit filtert diese heraus und erkennt trotzdem echte Abweichungen.
Speichert ConnectMQ den Temperaturverlauf?
Nein. ConnectMQ stellt Nachrichten in Echtzeit zu. Betreiben Sie einen Subscriber, der jeden Messwert für Fahrtberichte und Audits in Ihre eigene Datenbank schreibt.



