Ein Node-RED OEE-Dashboard ist einer der schnellsten Wege, einem Team eine echte Fertigungskennzahl vor Augen zu führen, ohne ein MES zu kaufen. In diesem Tutorial berechnen Sie Verfügbarkeit, Leistung und Qualität aus zwei MQTT-Topics, Maschinenzustand und Stückzählern, und zeigen die OEE live auf Dashboard-2.0-Gauges an. Außerdem publizieren Sie die Kennzahlen erneut an MQTT, damit andere Werkzeuge sie nutzen können, und lernen die Sonderfälle kennen, die naive OEE-Werte verfälschen. Für viele Mittelständler ist das ein pragmatischer Einstieg in Industrie 4.0.
OEE in einer Minute
Die Gesamtanlageneffektivität (Overall Equipment Effectiveness, OEE) multipliziert drei Verhältnisse, die jeweils zwischen 0 und 1 liegen:
| Faktor | Formel | Was verloren geht |
|---|---|---|
| Verfügbarkeit | Laufzeit / geplante Produktionszeit | Störungen, Rüstvorgänge, Warten auf Material |
| Leistung | (Ideale Taktzeit x Gesamtstückzahl) / Laufzeit | Langsame Takte, Mikrostopps |
| Qualität | Gutteile / Gesamtstückzahl | Ausschuss und Nacharbeit |
| OEE | Verfügbarkeit x Leistung x Qualität | Alles oben Genannte |
Das Schöne an der Formel ist, dass sie sehr wenige Daten braucht: wann die Maschine lief, wie viele Teile sie gefertigt hat und wie viele davon gut waren. Das lässt sich elegant auf MQTT abbilden. Für einen tieferen Blick auf die Definitionen, einschließlich geplanter und ungeplanter Stopps, lesen Sie, wie man OEE berechnet.
Das MQTT-Datenmodell
Die Maschine oder ein vorgeschaltetes Gateway publiziert zwei Topics:
| Topic | Payload | Retained | Wann |
|---|---|---|---|
connectmq/demo/a7f3k2/plant1/line1/press1/state |
RUNNING, IDLE oder DOWN |
Ja | Bei jeder Änderung |
connectmq/demo/a7f3k2/plant1/line1/press1/count |
{"total": 1234, "good": 1201} |
Nein | Alle paar Sekunden |
Zwei Designentscheidungen machen das robust:
- Der Zustand ist ereignisgesteuert und retained. Node-RED kennt den aktuellen Zustand sofort nach dem Verbinden und summiert die Laufzeit aus den Änderungsereignissen.
- Zähler sind kumulativ, nicht pro Teil. Geht eine Nachricht verloren, trägt die nächste trotzdem die korrekte Summe. Node-RED berechnet die Differenzen, und ein rückwärts laufender Zähler wird als SPS-Reset behandelt statt als negative Produktion.
Das Topic folgt hinter einem Demo-Präfix einer Hierarchie im ISA-95-Stil (Standort, Linie, Maschine). Genau diese Struktur bildet in einem Unified Namespace (UNS) das Rückgrat: Jede Maschine hat ihren festen Platz im Topic-Baum, und Kennzahlen wie die OEE landen direkt daneben. Ersetzen Sie a7f3k2 durch eine eigene Zufallszeichenfolge, denn der öffentliche Broker ist für jeden lesbar.
Eine Maschine simulieren
Dieses Python-Skript verhält sich wie eine Presse mit einer idealen Taktzeit von 2 Sekunden, gelegentlichen Stopps und etwa 3 Prozent Ausschuss. Es publiziert an broker.connectmq.com, den öffentlichen MQTT-Broker.
# pip install "paho-mqtt>=2.0"
import json
import random
import time
import uuid
import paho.mqtt.client as mqtt
BASE = "connectmq/demo/a7f3k2/plant1/line1/press1"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"press-sim-{uuid.uuid4().hex[:8]}")
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
state = None
total = 0
good = 0
next_cycle = time.time()
last_count_pub = 0.0
def set_state(new_state):
global state
if new_state != state:
state = new_state
client.publish(f"{BASE}/state", state, qos=1, retain=True)
print("State:", state)
set_state("RUNNING")
try:
while True:
now = time.time()
if state == "RUNNING":
if random.random() < 0.004:
set_state(random.choice(["IDLE", "DOWN"]))
elif now >= next_cycle:
total += 1
if random.random() > 0.03:
good += 1
# Echte Takte sind etwas langsamer als ideal
next_cycle = now + random.uniform(2.0, 2.6)
elif random.random() < 0.02:
set_state("RUNNING")
next_cycle = time.time() + 2.0
if now - last_count_pub >= 5:
client.publish(f"{BASE}/count",
json.dumps({"total": total, "good": good}), qos=1)
last_count_pub = now
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
client.loop_stop()
client.disconnect()
Den Flow für das Node-RED OEE-Dashboard bauen
Sie brauchen Node-RED 4.x mit installiertem Dashboard 2.0 (@flowfuse/node-red-dashboard). Haben Sie es noch nicht genutzt, behandelt das Dashboard-2.0-Tutorial die Installation und die Struktur aus Seiten und Gruppen.
Eingänge
- Ein
mqtt in-Node auf.../press1/state, Ausgabe "a UTF-8 string". - Ein
mqtt in-Node auf.../press1/count, Ausgabe "a parsed JSON object". - Ein Inject-Node namens "tick", der alle 5 Sekunden auslöst, mit
msg.topicgleichtick. - Ein
ui-buttonmit der Beschriftung "Start new shift" undmsg.topicgleichshift/reset, dazu ein Inject-Node mit demselben Topic, der zu Ihren Schichtwechselzeiten auslöst (zum Beispiel 06:00, 14:00 und 22:00 Uhr).
Verwenden Sie zwei konkrete Abonnements statt einer Wildcard press1/#. Sie publizieren die Kennzahlen später unter demselben Maschinenpfad, und eine Wildcard würde Ihre eigene Ausgabe zurück in die Berechnung speisen.
Die OEE-Berechnung
Verbinden Sie alle vier Eingänge mit einem Function-Node mit fünf Ausgängen:
// Function node "OEE calculator" - Outputs auf 5 stellen
const IDEAL_CYCLE_S = 2.0; // ideale Sekunden pro Teil für diese Maschine
const now = Date.now();
function newShift() {
return { shiftStart: now, state: "UNKNOWN", since: now, runMs: 0,
lastTotal: null, lastGood: null, total: 0, good: 0 };
}
let s = flow.get("oee") || newShift();
const topic = String(msg.topic || "");
if (topic === "shift/reset") {
const keepState = s.state;
s = newShift();
s.state = keepState; // die Maschine ist noch im selben Zustand
flow.set("oee", s);
return null;
}
if (topic.endsWith("/state")) {
const st = String(msg.payload).trim().toUpperCase();
if (s.state === "RUNNING") s.runMs += now - s.since;
s.state = st;
s.since = now;
flow.set("oee", s);
return null;
}
if (topic.endsWith("/count")) {
const total = Number(msg.payload.total);
const good = Number(msg.payload.good);
if (!Number.isFinite(total) || !Number.isFinite(good)) return null;
if (s.lastTotal !== null) {
// Ein rückwärts laufender Zähler bedeutet, dass die SPS ihn zurückgesetzt hat
const dTotal = total >= s.lastTotal ? total - s.lastTotal : total;
const dGood = good >= s.lastGood ? good - s.lastGood : good;
s.total += dTotal;
s.good += Math.min(dGood, dTotal);
}
s.lastTotal = total;
s.lastGood = good;
flow.set("oee", s);
return null;
}
if (topic !== "tick") return null;
// Kennzahlen für die bisherige Schicht berechnen
const runMs = s.runMs + (s.state === "RUNNING" ? now - s.since : 0);
const plannedMs = now - s.shiftStart;
const availability = plannedMs > 0 ? runMs / plannedMs : 0;
const rawPerformance = runMs > 0 ? (IDEAL_CYCLE_S * 1000 * s.total) / runMs : 0;
const performance = Math.min(1, rawPerformance);
const quality = s.total > 0 ? s.good / s.total : 0;
const oee = availability * performance * quality;
if (rawPerformance > 1.05) {
node.warn("Performance above 100%: check IDEAL_CYCLE_S");
}
const pct = v => Math.round(v * 1000) / 10;
node.status({ fill: s.state === "RUNNING" ? "green" : "red", shape: "dot",
text: `${s.state} OEE ${pct(oee)}%` });
return [
{ payload: pct(availability) },
{ payload: pct(performance) },
{ payload: pct(quality) },
{ payload: pct(oee) },
{ topic: "connectmq/demo/a7f3k2/plant1/line1/press1/oee",
payload: { availability: pct(availability), performance: pct(performance),
quality: pct(quality), oee: pct(oee), total: s.total, good: s.good,
state: s.state, shiftStart: new Date(s.shiftStart).toISOString() },
retain: true }
];
Klicken Sie nach dem Deployment einmal auf Start new shift, damit die Schicht zu einem bekannten Zeitpunkt beginnt.
Widgets
- Die Ausgänge 1 bis 4 führen zu vier
ui-gauge-Nodes, Bereich 0 bis 100, Einheit%. Ein verbreitetes Farbschema für OEE ist Rot unter 60, Gelb von 60 bis 85 und Grün über 85, wählen Sie aber Bänder, die Ihre eigene Ausgangslage widerspiegeln. - Ausgang 5 führt zu einem
mqtt out-Node mit leeren Feldern für Topic und Retain, sodass ermsg.topicundmsg.retainaus der Nachricht verwendet. Fügen Sie hinter einem Change-Node, derpayload.stateextrahiert, einenui-text-Node hinzu, wenn Sie auch den Maschinenzustand auf dem Bildschirm sehen möchten.
Öffnen Sie /dashboard und beobachten Sie, wie sich die Werte in den ersten Minuten einpendeln. Früh in einer Schicht lässt ein einzelner Stopp die Verfügbarkeit stark schwanken; das ist mathematisch korrekt, und Bediener gewöhnen sich schnell daran.
Fallstricke, die die OEE verfälschen
- Falsche ideale Taktzeit. Liegt die Leistung über 100 Prozent, ist Ihre ideale Taktzeit zu langsam angesetzt. Begrenzen Sie den Wert nicht einfach und machen weiter; die Begrenzung im Code verdeckt ein Datenproblem.
- Geplante Stopps als Stillstand zählen. Pausen, geplante Wartung und Zeiten ohne Auftrag werden üblicherweise aus der geplanten Produktionszeit herausgerechnet. Fügen Sie einen Zustand
PLANNED_STOPhinzu und lassen Sie diese Zeit ausplannedMsheraus, wenn Ihr Werk diese Definition verwendet. - Zustand bei Neustarts verlieren. Der Flow-Kontext liegt standardmäßig im Arbeitsspeicher. Speichern Sie das Objekt
oeein einem dateibasierten Context Store, damit ein Node-RED-Neustart mitten in der Schicht die Kennzahlen nicht zurücksetzt. - Nachrichten in falscher Reihenfolge. Bei QoS 1 mit einem Publisher erhält MQTT die Reihenfolge pro Topic, aber Zustand und Zähler sind getrennte Topics. Die Berechnung per Timer, wie oben, macht kleine zeitliche Unterschiede irrelevant.
- Zählerüberlauf. 16-Bit-SPS-Zähler laufen bei 65.535 über. Die Reset-Logik behandelt einen Überlauf wie einen Reset, wodurch höchstens die Zählungen eines Intervalls verloren gehen.
Stillstandsgründe sind der naheliegende nächste Schritt: Ergänzen Sie den Zustand DOWN um einen Grundcode und summieren Sie die Minuten pro Grund. Der Leitfaden zur Erfassung von Maschinenstillständen zeigt, wie Sie diese Codes strukturieren.
OEE-Historie aufbewahren
Die Gauges zeigen nur die aktuelle Schicht. Um Schichten zu vergleichen, schreiben Sie die retained Kennzahlen-Nachricht am Ende jeder Schicht oder jede Minute in eine Zeitreihendatenbank. Das Node-RED-InfluxDB-Tutorial zeigt, wie Sie genau diese Art von JSON mit Tags wie Linie und Maschine speichern und anschließend visualisieren.
Skalierung auf eine ganze Linie oder ein Werk
Ein Function-Node pro Maschine funktioniert für einen Pilot. Für eine ganze Linie abonnieren Sie mit einer einstufigen Wildcard wie plant1/line1/+/state, halten ein Kontextobjekt pro Maschine mit der Topic-Ebene als Schlüssel und publizieren die Kennzahlen jeder Maschine auf ein eigenes Topic. Da die Berechnung nur von MQTT-Topics abhängt, ist es egal, ob die Daten von einem SPS-Gateway, einem ESP32-Zähler oder einem Edge-Gerät stammen.
Hier kommt es auch auf den Broker an. Ein Werk mit Dutzenden Maschinen, einem Node-RED-Server, einem Historian und vielleicht einem SCADA-Client, die alle gleichzeitig verbunden sind, braucht einen zuverlässigen Cloud-MQTT-Broker mit Authentifizierung statt eines öffentlichen Testdienstes. ConnectMQ erkennt Topics im ISA-95-Stil wie plant1/line1/press1/state und gruppiert Geräte im Portal nach diesen Ebenen, sodass Sie leicht sehen, welche Maschinen sich melden; so wird der ISA-95-Baum zum sichtbaren UNS Ihres Werks. Schwellwert-Alarmregeln im ConnectMQ-Portal können außerdem einen numerischen Wert markieren, der eine von Ihnen gewählte Grenze überschreitet, während Node-RED für die Berechnung selbst zuständig bleibt. Wenn Sie diese Infrastruktur nicht selbst betreiben möchten, hält ein vollständig verwalteter MQTT-Broker die Broker-Seite von Ihrer Wartungsliste fern. Für die Grundlagen zu Broker und Node-RED beginnen Sie mit dem Node-RED-MQTT-Tutorial.
Ihre OEE-Daten auf ConnectMQ bringen
Registrieren Sie sich unter app.connectmq.com für den kostenlosen Serverless-Plan, ohne Kreditkarte. Legen Sie einen Broker an, verwenden Sie den generierten Benutzernamen, das Passwort und die Client-ID in Ihren Maschinen und in Node-RED und stellen Sie auf TLS über Port 8883 um. Ihre private OEE-Pipeline läuft dann noch vor dem nächsten Schichtwechsel.
Häufig gestellte Fragen
Welche Daten brauche ich, um in Node-RED die OEE zu berechnen?
Sie brauchen den Maschinenzustand über die Zeit, eine Gesamtstückzahl, eine Gutteilzahl und die ideale Taktzeit. Mit diesen vier Eingaben kann Node-RED Verfügbarkeit, Leistung, Qualität und OEE berechnen.
Warum sollten Maschinen kumulative Zähler publizieren?
Kumulative Zähler machen die Berechnung tolerant gegenüber verlorenen oder verspäteten Nachrichten, weil jede Nachricht die volle Summe trägt. Node-RED berechnet die Differenz und behandelt Resets.
Wie oft sollte das OEE-Dashboard aktualisiert werden?
Alle 5 bis 30 Sekunden genügt für Bediener. Die Berechnung per Timer statt bei jeder Nachricht hält das Dashboard außerdem flüssig, wenn viele Maschinen gleichzeitig publizieren.
Kann ich die OEE mehrerer Maschinen auf einer Seite anzeigen?
Ja. Verwenden Sie ein Wildcard-Abonnement, halten Sie ein Kontextobjekt pro Maschine und legen Sie eine Dashboard-Gruppe pro Maschine an oder bauen Sie eine Tabelle mit einem ui-template-Node.



