Node-RED

Node-RED Modbus zu MQTT: Geräte pollen und Werte publizieren

Bauen Sie ein Node-RED-Modbus-Gateway: Holding-Register und Coils mit node-red-contrib-modbus pollen, Skalierung und 32-Bit-Floats dekodieren, JSON nur bei Änderung an MQTT publizieren und Schreibbefehle sicher annehmen.

Node-RED-Modbus-Flow, der Holding-Register einer Pumpensteuerung pollt und JSON-Werte an MQTT publiziert
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

Node-RED-Modbus-Flows sind einer der schnellsten Wege, Daten aus Zählern, Antrieben und SPSen, die nur Modbus sprechen, nach MQTT zu bringen, wo Dashboards, Historians und Cloud-Werkzeuge sie nutzen können. In diesem Tutorial pollen Sie Holding-Register und Coils mit node-red-contrib-modbus, dekodieren skalierte Integer und 32-Bit-Floats korrekt und publizieren sauberes JSON nur dann an einen Broker, wenn sich Werte ändern. Außerdem sehen Sie, wie Sie Schreibbefehle sicher verarbeiten und alles ohne echte Hardware testen.

Warum Modbus mit Node-RED an MQTT anbinden

Modbus ist ein Request/Response-Protokoll von 1979: Ein Client (Master) fragt einen Server (Slave) nach einem Registerblock und erhält rohe 16-Bit-Zahlen zurück. Es gibt keine Einheiten, keine Namen, keine Zeitstempel und kein Push. Jeder Konsument, der die Daten will, muss das Gerät selbst pollen, und viele Geräte verkraften nur wenige gleichzeitige Verbindungen.

MQTT dreht das um. Ein Gateway pollt das Gerät, gibt den Zahlen eine Bedeutung und publiziert sie einmal an einen Broker. Beliebig viele Abonnenten erhalten dann benannte, skalierte Werte in dem Moment, in dem sie sich ändern. Node-RED ist ein naheliegendes Gateway, denn Pollen, Dekodieren, Filtern und Publizieren sind jeweils ein Node, und die Logik bleibt für die Instandhaltung sichtbar. Für das größere Architekturbild vergleicht der Leitfaden Modbus TCP zu MQTT Node-RED mit anderen Gateway-Optionen.

node-red-contrib-modbus installieren

Installieren Sie das Paket über Palette verwalten → Installieren oder über die Kommandozeile:

cd ~/.node-red
npm install node-red-contrib-modbus
# Node-RED danach neu starten

Es stellt unter anderem diese Nodes bereit:

Node Zweck
Modbus Read Pollt per Timer einen festen Registerblock
Modbus Getter Liest bei Bedarf, wenn eine Nachricht eintrifft
Modbus Flex Getter Liest, was die eingehende Nachricht vorgibt
Modbus Write Schreibt Coils oder Register
Modbus Server Ein einfacher Modbus-TCP-Server zum Testen
Modbus Client (Konfiguration) TCP- oder serielle Verbindung, die sich die Nodes teilen

Zuerst die Registertabelle verstehen

Jedes Modbus-Projekt beginnt mit der Registertabelle des Geräts. Stellen Sie sich für dieses Tutorial eine Pumpensteuerung mit folgender Belegung vor:

Daten Typ Adresse (0-basiert) Klassische Notation Skalierung
Temperatur Holding-Register, vorzeichenbehaftet 16 Bit 0 40001 Wert / 10, °C
Druck Holding-Register, vorzeichenlos 16 Bit 1 40002 Wert / 100, bar
Durchfluss Holding-Register, 32-Bit-Float, Big-Endian 2-3 40003-40004 keine, m³/h
Pumpe läuft Coil 0 00001 Boolean

Der mit Abstand häufigste Fehler bei Node-RED und Modbus ist die Adresse. Datenblätter verwenden oft die Notation "40001", die 1-basiert ist und ein Typ-Präfix enthält. Die Protokolladresse, die Sie in Node-RED eintragen, ist 0-basiert und ohne Präfix: Aus 40001 wird Holding-Register-Adresse 0. Wirken Ihre Werte um ein Register verschoben, liegt es daran.

Ohne Hardware testen: ein lokaler Modbus-Server

Sie können das gesamte Tutorial ohne Gerät durchspielen, indem Sie einen Modbus-Server in Node-RED betreiben.

  1. Ziehen Sie einen Modbus Server-Node auf einen separaten Tab. Lassen Sie ihn auf 0.0.0.0, Port 10502 lauschen (unprivilegiert, also ohne Root-Rechte). Deployen Sie.
  2. Legen Sie einen Modbus Client-Konfigurations-Node an: Typ TCP, Host 127.0.0.1, Port 10502, Unit-ID 1.
  3. Fügen Sie einen Inject-Node hinzu, der alle 2 Sekunden auslöst, einen Function-Node, der simulierte Registerwerte erzeugt, und einen Modbus Write-Node mit diesem Client, Funktionscode 16 (Preset Multiple Registers), Adresse 0, Anzahl 4.

Die Simulator-Funktion:

// Function node "simulate pump registers" -> Modbus Write (FC16, address 0, quantity 4)
const temperature = 40 + Math.random() * 5;           // °C
const pressure = 3.2 + Math.random() * 0.3;           // bar
const flowRate = 12 + Math.random() * 2;              // m³/h

const buf = Buffer.alloc(4);
buf.writeFloatBE(flowRate, 0);

msg.payload = [
    Math.round(temperature * 10),      // Register 0
    Math.round(pressure * 100),        // Register 1
    buf.readUInt16BE(0),               // Register 2: Float, High-Word
    buf.readUInt16BE(2)                // Register 3: Float, Low-Word
];
return msg;

Fügen Sie einen zweiten Write-Node für die Coil hinzu: Funktionscode 5 (Force Single Coil), Adresse 0, gespeist mit true aus einem Inject-Node. Ihre simulierte Pumpensteuerung läuft jetzt.

Den Node-RED-Modbus-Polling-Flow bauen

Schritt 1: Die Register pollen

Fügen Sie einen Modbus Read-Node mit demselben Client hinzu:

  • FC: 3, Read Holding Registers
  • Adresse: 0, Anzahl: 4
  • Pollrate: 2 Sekunden

Sein erster Ausgang liefert msg.payload als Array aus vier Rohwerten, zum Beispiel [423, 334, 16708, 26214]. Der zweite Ausgang enthält den Roh-Buffer und Antwortdetails, was beim Debuggen der Byte-Reihenfolge hilft.

Für die Coil fügen Sie einen zweiten Modbus Read-Node mit FC 1 (Read Coil Status), Adresse 0, Anzahl 1 und einer langsameren Pollrate von 5 Sekunden hinzu.

Schritt 2: Rohregister in technische Werte dekodieren

// Function node "decode pump registers"
const r = msg.payload;
if (!Array.isArray(r) || r.length < 4) {
    node.warn("Unexpected register block");
    return null;
}

// Vorzeichenbehaftete 16-Bit-Umrechnung für die Temperatur
const int16 = v => (v > 32767 ? v - 65536 : v);

// 32-Bit-Float aus zwei Registern, Big-Endian-Wortreihenfolge
const buf = Buffer.alloc(4);
buf.writeUInt16BE(r[2], 0);
buf.writeUInt16BE(r[3], 2);
const flowRate = buf.readFloatBE(0);

const values = {
    temperature: Math.round(int16(r[0])) / 10,
    pressure: Math.round(r[1]) / 100,
    flow: Math.round(flowRate * 100) / 100
};

// Speichern, um es mit dem Coil-Wert zu kombinieren
flow.set("pump1_values", values);

msg.topic = "connectmq/demo/a7f3k2/plant1/utilities/pump1/telemetry";
msg.payload = {
    ...values,
    running: flow.get("pump1_running") === true
};
return msg;

Verbinden Sie das Coil-Read mit einer winzigen Funktion, die den Zustand speichert: flow.set("pump1_running", msg.payload[0] === true); return null;. Viele Geräte verwenden "wortvertauschte" Floats, bei denen das Low-Word zuerst kommt. Wirkt Ihr Durchflusswert absurd, etwa 1.2e-38 oder -4.5e+12, vertauschen Sie r[2] und r[3] und versuchen Sie es erneut.

Schritt 3: Nur bei Änderungen publizieren

Alle 2 Sekunden zu pollen und jedes Ergebnis zu publizieren, verschwendet Bandbreite und überschüttet Abonnenten mit doppelten Daten. Fügen Sie einen filter-Node (früher RBE genannt) ein, eingestellt auf "block unless value changes" für msg.payload, oder nutzen Sie eine Deadband-Variante für einzelne Werte, wenn diese schwanken. Der Filter vergleicht das ganze Objekt, weshalb die Dekodierfunktion keinen Zeitstempel hinzufügt. Fügen Sie nach dem Filter einen Change-Node ein, der msg.payload.ts auf einen Zeitstempel setzt. Report by Exception ist ein Kernmuster von MQTT, für sich langsam ändernde Werte lohnt sich aber trotzdem ein periodischer Heartbeat, damit Abonnenten ein ruhiges Gerät von einem ausgefallenen unterscheiden können.

Schritt 4: An MQTT publizieren

Fügen Sie einen mqtt out-Node mit leerem Topic hinzu, damit msg.topic verwendet wird. Konfigurieren Sie zum Testen den Broker broker.connectmq.com, Port 1883, mit einer eindeutigen Client-ID, also den öffentlichen MQTT-Broker. Ersetzen Sie a7f3k2 durch eine eigene Zeichenfolge. Beobachten Sie dann die Ausgabe:

mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-modbus-a7f3k2 -v \
  -t 'connectmq/demo/a7f3k2/plant1/#'

Sie sollten Nachrichten wie {"temperature":42.3,"pressure":3.34,"flow":12.81,"running":true,"ts":...} sehen. Senden Sie keine echten Anlagendaten an den öffentlichen Broker: Jeder kann sie abonnieren.

Sicher von MQTT nach Modbus schreiben

Lesen ist risikoarm, das Schreiben auf eine Pumpe nicht. Wenn Sie Befehle aus MQTT annehmen, bauen Sie Leitplanken in den Flow ein:

  1. Abonnieren Sie ein eigenes Befehls-Topic wie .../pump1/cmd, niemals eine Wildcard.
  2. Validieren Sie den Payload in einem Function-Node gegen eine Whitelist erlaubter Aktionen und Wertebereiche.
  3. Ordnen Sie jeder Aktion ein festes Register oder eine feste Coil zu. Lassen Sie niemals die Nachricht die Adresse bestimmen.
  4. Publizieren Sie das Ergebnis auf ein Topic .../pump1/cmd/ack, damit der Absender weiß, ob geschrieben wurde.
  5. Verwenden Sie für jedes Topic, das den Zustand von Anlagen ändern kann, einen privaten Broker mit Authentifizierung.
// Function node "validate pump command" -> Modbus Write (FC5, coil 0)
const cmd = String(msg.payload).trim().toUpperCase();
if (cmd !== "START" && cmd !== "STOP") {
    node.warn("Rejected command: " + cmd);
    return null;
}
msg.payload = cmd === "START";
return msg;

Modbus RTU über RS-485

Für serielle Geräte ändern Sie nur die Client-Konfiguration: Typ Serial, Port wie /dev/ttyUSB0, Baudrate, Parität und Stoppbits passend zum Gerät (9600 8N1 ist üblich) und den seriellen Typ RTU. Jedes Gerät am Bus hat seine eigene Unit-ID. Wählen Sie die Pollraten konservativ, denn ein RS-485-Bus bedient alle Geräte nacheinander, und ein Timeout bei einem Gerät verzögert die anderen. Der Leitfaden Modbus RTU zu MQTT behandelt Verdrahtung und Terminierung.

Fehlerbehebung bei Node-RED-Modbus-Flows

Symptom Wahrscheinliche Ursache Lösung
Timeout-Fehler Falsche IP, falscher Port oder falsche Unit-ID; Firewall Zuerst mit einem Desktop-Modbus-Tool prüfen
Illegal data address (Exception 2) Adresse um eins verschoben oder falscher Funktionscode 0-basierte Adressen verwenden; Holding- vs. Input-Register
Werte um ein Register verschoben 40001-Notation wörtlich eingetragen Den Offset abziehen
Absurde Float-Werte Abweichende Wortreihenfolge Die beiden Register vertauschen
Negative Zahlen erscheinen als 65.000+ Vorzeichenbehafteter Wert als vorzeichenlos gelesen Die int16-Umrechnung anwenden
Gerät reagiert unter Last nicht mehr Zu viele Clients oder zu schnelles Pollen Ein Gateway, langsamere Polls, Lesevorgänge zu Blöcken zusammenfassen

Vom Gateway in die Produktion

Sobald Werte fließen, ist das Gateway nur so nützlich wie der Broker, an den es publiziert. An einem Standort mit mehreren Node-RED-Gateways, einem SCADA-Client und einem Historian sollten sich alle einen authentifizierten Broker teilen, der sowohl aus dem Werks- als auch aus dem Büronetz erreichbar ist. Ein Cloud-MQTT-Broker ist ein einfacher Weg dorthin, denn jedes Gateway verbindet sich ausgehend auf Port 8883, und es werden keine eingehenden Ports ins OT-Netz geöffnet. ConnectMQ erkennt außerdem Topics im ISA-95-Stil wie plant1/utilities/pump1/telemetry und zeigt Geräte im Portal nach diesen Ebenen an. Genau so entsteht ein Unified Namespace (UNS): Die ISA-95-Hierarchie aus Unternehmen, Werk, Bereich, Linie und Zelle wird zur Topic-Struktur auf dem Broker, und jedes Modbus-Gateway publiziert seine Werte an die passende Stelle. Wenn Sie überhaupt keine Broker-Infrastruktur betreiben möchten, nimmt Ihnen ein verwalteter MQTT-Broker Patching und Monitoring ab.

Andere Industrieprotokolle folgen demselben Muster: Siehe Node-RED OPC UA zu MQTT für moderne Steuerungen und Node-RED mit Siemens S7 für S7-SPSen. Für die Broker-Einrichtung in Node-RED liefert das Node-RED-MQTT-Tutorial die Grundlagen.

Ihr Modbus-Gateway mit ConnectMQ verbinden

Registrieren Sie sich unter app.connectmq.com für den kostenlosen Serverless-Plan, ohne Kreditkarte. Legen Sie einen Broker an, tragen Sie den generierten Benutzernamen, das Passwort und die Client-ID in den Node-RED-Konfigurations-Node ein, aktivieren Sie TLS auf Port 8883, und Ihre Modbus-Werte werden privat und verschlüsselt publiziert. Prüfen Sie mit dem Live-Topic-Explorer von ConnectMQ jedes Register, das Sie dekodiert haben.

Häufig gestellte Fragen

Unterstützt node-red-contrib-modbus sowohl Modbus TCP als auch RTU?

Ja. Der Modbus Client-Konfigurations-Node unterstützt TCP- und serielle Verbindungen, einschließlich RTU über RS-485-Adapter. Die Lese- und Schreib-Nodes funktionieren für beide gleich.

Warum ist meine Modbus-Adresse in Node-RED um eins verschoben?

Datenblätter verwenden oft eine 1-basierte Nummerierung im Stil 40001, während Node-RED 0-basierte Protokolladressen nutzt. Holding-Register 40001 ist im Modbus Read-Node die Adresse 0.

Wie lese ich in Node-RED einen 32-Bit-Float aus Modbus?

Lesen Sie zwei aufeinanderfolgende Register, schreiben Sie sie in einen 4-Byte-Buffer und rufen Sie readFloatBE auf. Sieht das Ergebnis falsch aus, vertauschen Sie die beiden Wörter, denn manche Geräte nutzen die umgekehrte Wortreihenfolge.

Wie oft sollte Node-RED ein Modbus-Gerät pollen?

So langsam, wie es Ihr Anwendungsfall erlaubt, für Monitoring oft 1 bis 10 Sekunden. Fassen Sie Register zu Blöcken zusammen und publizieren Sie nur bei Änderungen, damit Gerät und Broker gering belastet bleiben.

Verwandte Artikel

Node-RED als OPC-UA-Client zu MQTT mit ISA-95-Topics

Mit node-red-contrib-opcua OPC-UA-Variablen auf einer SPS oder einem Simulationsserver abonnieren, Node-IDs auf MQTT-Topics im ISA-95-Stil abbilden und Werte mit Qualität und Zeitstempel publizieren.

9 Min. Lesezeit

Node-RED Diagramm-Verlauf: MQTT-Chartdaten über Neustarts hinweg behalten

Dashboard-Diagramme vergessen alles, wenn Node-RED neu startet. Dieser Leitfaden zeigt zwei zuverlässige Wege, den Node-RED Diagramm-Verlauf für MQTT-Daten zu behalten: dateibasierten Context-Speicher und eine kleine SQLite-Tabelle, beide beim Start in Dashboard 2.0 zurückgespielt.

8 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.