Mit einem Gateway von Modbus RTU zu MQTT lesen Sie Messwerte von RS-485-Energiezählern, Durchflussmessern, Antrieben und Sensoren aus und veröffentlichen sie an einen Broker, wo Dashboards und Analytics sie nutzen können. Dieses Tutorial behandelt die physikalische Schicht, die die meisten Probleme verursacht (Verdrahtung, Terminierung, serielle Einstellungen), das Lesen einer Registerbelegung des Herstellers und ein vollständiges Python-Gateway, das mehrere Geräte an einem Bus pollt und ihre Werte per MQTT veröffentlicht. Ein Raspberry Pi oder ein beliebiger Linux-Rechner mit USB-RS-485-Adapter genügt, um mitzumachen.
Was Modbus RTU von Modbus TCP unterscheidet
Das Modbus-Datenmodell ist dasselbe: Coils, Discrete Inputs, Holding Register und Input Register. Was sich ändert, ist der Transport. Modbus RTU läuft über eine serielle Leitung, fast immer RS-485, als Multi-Drop-Bus. Ein Master pollt bis zu 247 Slave-Geräte, jedes mit einer eindeutigen Geräteadresse. Frames sind binär mit CRC, und Frame-Grenzen werden durch Ruhepausen auf der Leitung definiert.
Das hat praktische Folgen:
- Nur ein Master pro Bus. Pollt bereits eine Gebäudeleittechnik oder ein HMI die Zähler, kann sich Ihr Gateway nicht einfach an dieselben Leitungen hängen. Sie brauchen einen separaten Bus, ein Gerät mit zweiter Schnittstelle oder ein Gateway, das vor beiden sitzt.
- Der Bus ist langsam und geteilt. Bei 9600 Baud dauern Anfrage und Antwort jeweils einige zehn Millisekunden, und Anfragen an verschiedene Geräte laufen nacheinander. Die Polling-Planung zählt.
- Elektrische Probleme sehen aus wie Softwareprobleme. Fehlende Terminierung oder ein vertauschtes Adernpaar erzeugen Timeouts und CRC-Fehler, die kein Code der Welt behebt.
Wenn Ihre Geräte am Ethernet hängen, verwenden Sie stattdessen unser Tutorial Modbus TCP zu MQTT.
Benötigte Hardware
- Ein Gateway-Rechner: ein Raspberry Pi, ein Industrie-PC oder ein beliebiger Linux-Rechner.
- Ein USB-RS-485-Adapter, idealerweise galvanisch getrennt und mit zuschaltbaren Terminierungs- und Bias-Widerständen. Die galvanische Trennung schützt das Gateway vor Potenzialunterschieden zwischen Schaltschränken.
- Verdrilltes Kabel für den Bus, vorzugsweise geschirmt, mit einem dritten Leiter für die Signalmasse.
- Das Modbus-Handbuch jedes Geräts. Sie brauchen die Registerbelegung und die seriellen Standardeinstellungen.
RS-485 richtig verdrahten
RS-485 ist robust, wenn es wie vorgesehen verdrahtet ist, und frustrierend, wenn nicht. Befolgen Sie diese Regeln:
- Linie, nicht Stern. Führen Sie den Bus in einer Linie von Gerät zu Gerät. Kurze Stichleitungen sind tolerierbar; lange Abzweige verursachen Reflexionen.
- Beide Enden terminieren. Setzen Sie an den beiden physischen Enden des Busses einen 120-Ohm-Widerstand über das A/B-Paar, und nirgendwo sonst. Viele Adapter und Zähler haben dafür einen Schalter oder Jumper.
- Nur einmal biasen. Bias-Widerstände (Fail-Safe) halten die Leitung in einem definierten Zustand, wenn niemand sendet. Aktivieren Sie sie an genau einer Stelle, meist am Master-Adapter.
- Die Masse verbinden. Trotz der Bezeichnung „Zweidraht" verbinden Sie die Signalmasse (oft GND, COM oder C beschriftet) zwischen den Geräten, damit die Empfänger einen gemeinsamen Bezug haben.
- Auf die A/B-Beschriftung achten. Hersteller sind sich uneinig, ob A positiv oder negativ ist, und manche verwenden D+ und D-. Antwortet nichts, ist das Tauschen von A und B am Adapter ein legitimer erster Test.
- Abstand zu Stromkabeln halten. Verlegen Sie den Bus getrennt von Motor- und Frequenzumrichterkabeln und erden Sie den Schirm an einem Ende.
Serielle Einstellungen: Baudrate, Parität und Stoppbits
Alle Geräte an einem Bus müssen dieselben Einstellungen verwenden, und jedes Gerät braucht eine eindeutige Adresse.
| Einstellung | Übliche Werte | Hinweise |
|---|---|---|
| Baudrate | 9600, 19200, 38400 | 9600 und 19200 sind die häufigsten Standardwerte; lange Kabel sprechen für niedrigere Raten |
| Datenbits | 8 | Modbus RTU verwendet immer 8 Datenbits |
| Parität | Even, None, Odd | Die Modbus-Spezifikation sieht standardmäßig gerade Parität vor, viele Geräte werden aber ohne Parität ausgeliefert |
| Stoppbits | 1 oder 2 | Ohne Parität fordert die Spezifikation 2 Stoppbits, viele Geräte akzeptieren aber 1 |
| Geräteadresse | 1 bis 247 | Am Bedienfeld des Geräts oder per Software eingestellt; muss am Bus eindeutig sein |
Notieren Sie die Einstellungen als Kurzcode wie 9600 8E1 oder 19200 8N2 und stellen Sie alle Geräte entsprechend ein, bevor Sie etwas anschließen.
Eine Registerbelegung lesen
Ein Gerätehandbuch listet Register in einer Tabelle mit Adresse, Beschreibung, Datentyp, Einheit und manchmal einem Skalierungsfaktor. Das folgende Beispiel ist ein hypothetischer Drehstrom-Energiezähler für dieses Tutorial; echte Zähler weichen ab, entnehmen Sie Adressen daher immer Ihrem eigenen Handbuch.
| Beschreibung | Funktion | Adresse (nullbasiert) | Typ | Einheit |
|---|---|---|---|---|
| Spannung L1-N | 04 Input | 0 | float32 | V |
| Strom L1 | 04 Input | 6 | float32 | A |
| Wirkleistung gesamt | 04 Input | 52 | float32 | W |
| Frequenz | 04 Input | 70 | float32 | Hz |
| Bezogene Wirkenergie | 04 Input | 72 | float32 | kWh |
Drei Dinge sollten Sie in jedem Handbuch prüfen: ob Adressen nullbasiert sind oder im Stil 30001 geschrieben werden (Versatz abziehen), ob 32-Bit-Werte das höherwertige oder das niederwertige Wort zuerst verwenden und ob Integer-Register einen Skalierungsfaktor brauchen.
Voraussetzungen auf dem Gateway
sudo usermod -aG dialout $USER # Zugriff auf die serielle Schnittstelle erlauben, dann ab- und wieder anmelden
ls -l /dev/serial/by-id/ # stabiler Gerätepfad für Ihren Adapter
python3 -m venv ~/rtu-gw && source ~/rtu-gw/bin/activate
pip install "pymodbus[serial]>=3.8,<3.9" "paho-mqtt>=2.0"
Verwenden Sie den Pfad /dev/serial/by-id/... statt /dev/ttyUSB0, weil sich USB-Gerätenummern nach einem Neustart ändern können.
Der Code des Gateways von Modbus RTU zu MQTT
Das Gateway pollt jeden Zähler nacheinander, liest jeden Registerblock nach Möglichkeit in einer Anfrage und veröffentlicht eine JSON-Nachricht pro Zähler und Zyklus. Die Werte eines Zählers in einer Nachricht zu bündeln hält die Nachrichtenrate niedrig, was Sie auf einem langsamen Bus und einem volumenbasiert abgerechneten Uplink wollen.
# rtu_mqtt_gateway.py - Modbus-RTU-Zähler über RS-485 pollen, an MQTT veröffentlichen
import json, logging, struct, time, uuid
import paho.mqtt.client as mqtt
from pymodbus.client import ModbusSerialClient
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("rtu-gw")
# In der Produktion den Port durch Ihren /dev/serial/by-id/...-Pfad ersetzen
SERIAL = dict(port="/dev/ttyUSB0", baudrate=9600, parity="E", stopbits=1, bytesize=8, timeout=0.5)
POLL_SECONDS = 10
TOPIC_ROOT = "connectmq/demo/e5a1/plant1/energy" # eigene Zufalls-ID verwenden
MQTT_HOST, MQTT_PORT = "broker.connectmq.com", 1883 # Produktion: 8883 mit TLS
MQTT_USER, MQTT_PASS = None, None # Produktion: "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = f"rtu-gw-{uuid.uuid4().hex[:8]}" # Produktion: "YOUR_CLIENT_ID"
# Zähler am Bus: Modbus-Geräteadresse -> Topic-Name
METERS = [
{"unit": 1, "name": "mdb1_incomer"},
{"unit": 2, "name": "mdb1_compressors"},
]
def f32(regs, offset, big_endian_words=True):
words = regs[offset:offset + 2] if big_endian_words else regs[offset:offset + 2][::-1]
return struct.unpack(">f", struct.pack(">HH", *words))[0]
def read_meter(client, unit):
"""Liest die float32-Input-Register des hypothetischen Zählers in zwei Blockanfragen."""
block_a = client.read_input_registers(0, count=8, slave=unit) # Spannung, Strom
block_b = client.read_input_registers(52, count=24, slave=unit) # Leistung .. Energie
for rr in (block_a, block_b):
if rr.isError():
raise IOError(str(rr))
a, b = block_a.registers, block_b.registers
return {
"voltage_l1": round(f32(a, 0), 1),
"current_l1": round(f32(a, 6), 2),
"power_total": round(f32(b, 0), 0),
"frequency": round(f32(b, 18), 2),
"energy_import": round(f32(b, 20), 1),
}
def main():
mq = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
if MQTT_USER:
mq.username_pw_set(MQTT_USER, MQTT_PASS)
mq.tls_set()
mq.will_set(f"{TOPIC_ROOT}/gateway", "offline", qos=1, retain=True)
mq.on_connect = lambda c, u, f, rc, p: c.publish(f"{TOPIC_ROOT}/gateway", "online", qos=1, retain=True)
mq.connect(MQTT_HOST, MQTT_PORT, keepalive=60)
mq.loop_start()
bus = ModbusSerialClient(**SERIAL)
errors = {m["unit"]: 0 for m in METERS}
while True:
cycle_start = time.monotonic()
if not bus.connected and not bus.connect():
log.error("cannot open serial port %s", SERIAL["port"])
time.sleep(5)
continue
for meter in METERS:
topic = f"{TOPIC_ROOT}/{meter['name']}"
try:
values = read_meter(bus, meter["unit"])
errors[meter["unit"]] = 0
payload = {**values, "quality": "good",
"ts": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())}
mq.publish(topic, json.dumps(payload), qos=1, retain=True)
log.info("%s %s", meter["name"], values)
except Exception as exc:
errors[meter["unit"]] += 1
log.warning("unit %s: %s", meter["unit"], exc)
if errors[meter["unit"]] == 3: # schlechte Qualität einmal melden, nach 3 Fehlversuchen
mq.publish(topic, json.dumps({"quality": "bad"}), qos=1, retain=True)
time.sleep(0.05) # kleine Pause zwischen Geräten am Bus
time.sleep(max(0, POLL_SECONDS - (time.monotonic() - cycle_start)))
if __name__ == "__main__":
main()
Beachten Sie die Offsets in read_meter: Block B beginnt bei Register 52, daher liegt die Frequenz bei Register 70 auf Offset 18 und die bezogene Energie bei 72 auf Offset 20. Falsche Offsets sind der häufigste Fehler beim Bündeln von Lesevorgängen, geben Sie bei der Inbetriebnahme daher einmal die Rohregister aus.
Ausführen und prüfen
Starten Sie das Gateway und beobachten Sie die Ausgabe von einem beliebigen Rechner aus:
python rtu_mqtt_gateway.py
mosquitto_sub -h broker.connectmq.com -p 1883 -i rtu-viewer-e5a1 -t "connectmq/demo/e5a1/#" -v
connectmq/demo/e5a1/plant1/energy/mdb1_incomer {"voltage_l1": 231.4, "current_l1": 18.72, "power_total": 12890.0, "frequency": 50.01, "energy_import": 48213.6, "quality": "good", "ts": "2026-10-16T10:05:00Z"}
Der öffentliche MQTT-Broker ist für jeden lesbar und für Tests und Prototypen gedacht, verwenden Sie ihn also nur für Testdaten, nie für Produktionsdaten. Für einen echten Standort legen Sie einen privaten Broker an und wechseln mit Ihren Zugangsdaten auf Port 8883.
Fehlerbehebung bei Modbus RTU
| Symptom | Wahrscheinliche Ursache | Was Sie versuchen sollten |
|---|---|---|
| Kein Gerät antwortet | A/B vertauscht, falsche Baudrate oder Parität, falscher Port | A/B tauschen, 8E1 vs. 8N1 prüfen, /dev/serial/by-id prüfen |
| Manche Geräte antworten, andere laufen in Timeouts | Doppelte oder falsche Geräteadresse, Leitungsbruch | Alle Geräte bis auf eines abklemmen und jedes einzeln testen |
| Sporadische CRC-Fehler | Fehlende Terminierung, Sterntopologie, Störungen durch Antriebe | Beide Enden terminieren, Kabel neu verlegen, geschirmtes verdrilltes Kabel verwenden |
| Funktioniert bei 9600, scheitert bei höheren Raten | Langes Kabel oder schlechte Verdrahtung | Bei der niedrigeren Rate bleiben oder die Verkabelung reparieren |
| Exception-Code 2 (Illegal Data Address) | Adresse außerhalb der Gerätebelegung oder Block überspannt eine Lücke | Block in kleinere Lesevorgänge aufteilen |
| Zufällige Timeouts, während ein anderes System läuft | Zwei Master am selben Bus | Dem Gateway einen eigenen Bus oder Port geben |
Skalieren
Eine einzelne RS-485-Schnittstelle reicht für eine Handvoll Zähler. Bei Dutzenden sollten Sie einen Adapter pro Schaltschrank in Betracht ziehen oder Konverter von Modbus RTU zu TCP, über die ein Gateway mehrere Busse per Ethernet erreicht, und dann die TCP-Brücke wiederverwenden. Veröffentlichen bei Änderung statt in jedem Zyklus, wie in unserem Leitfaden zu Report by Exception beschrieben, hält den Uplink zusätzlich ruhig. Für entfernte Standorte mit Mobilfunkdaten lesen Sie MQTT über Mobilfunk.
Sobald mehrere Gateways in mehreren Hallen oder Werken laufen, lohnt sich eine einheitliche Topic-Struktur. Bewährt hat sich ein Unified Namespace (UNS), dessen Topic-Baum der Equipment-Hierarchie nach ISA-95 folgt: Enterprise → Site → Area → Line → Cell. Aus dem Demo-Topic plant1/energy/mdb1_incomer wird dann etwa acme/werk-augsburg/energie/hauptverteilung-1/einspeisung. Energiemonitoring, MES und Analytics abonnieren genau die Ebene, die sie brauchen, und neue Zähler fügen sich ohne Absprache in die Struktur ein. Wie Sparkplug B diese Struktur ergänzt, beschreibt der Beitrag zu Sparkplug B und Unified Namespace.
Ein verwalteter MQTT-Broker wie ConnectMQ erspart Ihnen den Betrieb eines Servers für diese Gateways. Der kostenlose Serverless-Plan unterstützt bis zu 25 Verbindungen, genug für einen Pilot mit mehreren Gateways, und der kostenpflichtige Serverless-Plan skaliert auf 1.000. Die Regeln für Schwellwert-Alarme im Portal können Werte wie power_total überwachen und einen Alarm protokollieren, wenn ein Grenzwert überschritten wird. Zur Architektur dahinter lesen Sie den Leitfaden zu Industrial IoT mit MQTT.
Starten Sie mit ConnectMQ
Bringen Sie Ihre RS-485-Zähler noch heute online. Registrieren Sie sich unter app.connectmq.com, wählen Sie den kostenlosen Serverless-Plan (ohne Kreditkarte), legen Sie einen Broker an und kopieren Sie den generierten Benutzernamen, das Passwort und die Client ID in das Gateway-Skript. Ihre Zählerwerte erscheinen im Live-Topic-Explorer von ConnectMQ, sobald die erste Abfrage abgeschlossen ist.
Häufig gestellte Fragen
Wie viele Modbus-RTU-Geräte kann ein RS-485-Bus unterstützen?
Modbus-Adressen erlauben bis zu 247 Geräte, die elektrische Grenze hängt aber von der Last der Transceiver ab; Standard-RS-485 unterstützt 32 Unit Loads, und viele moderne Transceiver stellen nur Bruchteile davon dar. In der Praxis wird meist zuerst die Polling-Zeit zur Grenze.
Kann ich Modbus-RTU-Geräte lesen, die bereits eine Gebäudeleittechnik pollt?
Nicht am selben Bus, denn Modbus RTU erlaubt nur einen Master. Nutzen Sie eine zweite Schnittstelle am Gerät, einen separaten Zählerausgang oder bitten Sie den Integrator der Gebäudeleittechnik, die Daten auf anderem Weg bereitzustellen.
Welche Baudrate sollte ich für Modbus RTU verwenden?
Die, die jedes Gerät am Bus unterstützt, typischerweise 9600 oder 19200. Niedrigere Raten vertragen längere Kabel und störungsreichere Umgebungen besser.
Sollte ein Gateway von Modbus RTU zu MQTT bei jeder Abfrage veröffentlichen?
Nicht unbedingt. Die Werte eines Geräts in einer Nachricht pro Zyklus zu bündeln oder nur bei signifikanter Änderung zu veröffentlichen, hält das Nachrichtenvolumen niedrig, ohne Informationen zu verlieren.



