Raspberry Pi

Raspberry Pi Relais per MQTT steuern: Mehrkanal-Relaisplatine von überall schalten

Schließen Sie eine 4-Kanal-Relaisplatine an einen Raspberry Pi an, steuern Sie jeden Kanal mit Python und gpiozero über MQTT-Topics und nutzen Sie Retained Messages, damit jedes Relais nach einem Neustart oder Stromausfall in den richtigen Zustand zurückkehrt.

Raspberry Pi mit Vierkanal-Relaisplatine und Kontroll-LEDs, gesteuert über Cloud-MQTT-Nachrichten in einem Raspberry Pi Relais MQTT Projekt
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

Mit einer Raspberry Pi Relais MQTT Steuerung schalten Sie Lampen, Pumpen, Lüfter oder Schütze vom Smartphone, einem Dashboard oder einem Automatisierungsskript aus, ohne Ports am Router zu öffnen. In diesem Tutorial verdrahten Sie eine Mehrkanal-Relaisplatine, schreiben einen Python-Dienst, der MQTT-Topics auf Relaiskanäle abbildet, und nutzen Retained Messages, damit jedes Relais nach einem Neustart im richtigen Zustand zurückkommt.

Was Sie brauchen

Teil Hinweise
Raspberry Pi (3B+, 4, 5 oder Zero 2 W) Raspberry Pi OS Bookworm, mit dem Netzwerk verbunden
Relaisplatine mit 2, 4 oder 8 Kanälen 5-V-Spule mit Optokopplern, 3,3-V-kompatible Eingänge
Jumperkabel Buchse-Buchse Eines pro Kanal plus Versorgung und Masse
Python 3 mit gpiozero und paho-mqtt 2.x In einer virtuellen Umgebung installiert
Ein MQTT-Broker broker.connectmq.com zum Testen, private Zugangsdaten für die Produktion

Vorab ein Sicherheitshinweis: Relaisplatinen schalten alles, was Sie daran anschließen. Wenn Sie Netzspannung steuern, muss die Verdrahtung in einem geeigneten Gehäuse von einer Fachkraft ausgeführt werden, und das Relais muss für die Last ausgelegt sein. Zum Lernen schalten Sie einen 12-V-LED-Streifen oder einen kleinen Gleichstromlüfter.

Die Relaisplatine verdrahten

Die meisten Hobby-Relaismodule haben eine Stiftleiste mit VCC, GND und IN1 bis IN4. Verbinden Sie sie so:

Relais-Pin Raspberry-Pi-Pin
VCC 5 V (physischer Pin 2)
GND GND (physischer Pin 6)
IN1 GPIO17 (physischer Pin 11)
IN2 GPIO27 (physischer Pin 13)
IN3 GPIO22 (physischer Pin 15)
IN4 GPIO23 (physischer Pin 16)

Viele dieser Platinen sind Low-aktiv: Wird ein Eingang auf Masse gezogen, zieht die Spule an. Deshalb verwendet der Code unten active_high=False. Schaltet Ihre Platine ein, wenn Sie Aus erwarten, kehren Sie dieses Flag um.

Platinen mit einem JD-VCC-Jumper erlauben es, die Spulen für eine vollständige Trennung aus einer separaten 5-V-Versorgung zu speisen. Entfernen Sie den Jumper, versorgen Sie JD-VCC aus der externen Quelle, lassen Sie VCC gemäß Dokumentation der Platine an 3,3 V oder 5 V des Pi und verbinden Sie die Masse nur, wenn das Handbuch es verlangt.

Ein weiteres Hardwaredetail ist für die Zuverlässigkeit wichtig. Bevor Ihr Skript startet, sind die GPIO-Pins Eingänge mit Standard-Pull-Widerständen, sodass eine Low-aktive Platine beim Booten kurz schalten kann. Testen Sie, was Ihre Relais beim Aus- und Einschalten tun. Wäre ein solcher Impuls schädlich, wählen Sie Pins, deren Standard-Pull dem Aus-Pegel entspricht, oder ergänzen Sie externe Pull-Widerstände.

Den Topic-Vertrag entwerfen

Eine saubere Topic-Struktur macht die Relaissteuerung von jedem Client aus leicht nutzbar, ob Node-RED, Home Assistant oder ein Skript:

Topic Richtung Payload Retained
connectmq/demo/a91c4e/relays/<n>/set Controller zum Pi ON, OFF (oder TOGGLE, nicht retained) Ja für ON/OFF
connectmq/demo/a91c4e/relays/<n>/state Pi an alle ON oder OFF Ja
connectmq/demo/a91c4e/relays/status Pi (und Last Will) online oder offline Ja

Ersetzen Sie a91c4e durch Ihre eigene Zufallszeichenfolge. Auf einem geteilten öffentlichen MQTT-Broker ist jedes Topic für alle lesbar, ein eindeutiges Präfix hält Ihren Testverkehr also getrennt. Wenn Sie auffrischen möchten, warum getrennte set- und state-Topics gute Praxis sind, erklärt die Anleitung Raspberry Pi GPIO über MQTT das Befehls-/Zustandsmuster im Detail.

Wie Retained States einen Neustart überstehen

Retained Messages sind der Schlüssel zu einer Relaissteuerung, die sich nach einem Stromausfall korrekt verhält. Der Broker speichert die letzte retained Nachricht jedes Topics und liefert sie jedem neuen Abonnenten sofort aus. Daraus ergeben sich zwei nützliche Verhaltensweisen:

  1. Veröffentlicht Ihr Dashboard ON mit Retain-Flag an relays/1/set, behält der Broker die Nachricht. Nachdem der Pi neu gestartet ist und relays/+/set abonniert, erhält er den Sollzustand jedes Kanals und stellt ihn wieder her.
  2. Veröffentlicht der Pi relays/1/state mit Retain, sieht jedes später geöffnete Dashboard sofort den echten Zustand, statt auf die nächste Änderung zu warten.

Es gibt eine Falle: Setzen Sie TOGGLE niemals retained. Ein retained Toggle würde bei jeder Wiederverbindung erneut ausgeführt und das Relais jedes Mal umschalten. Das Skript unten ignoriert retained Toggles aus diesem Grund. Mehr zum Mechanismus lesen Sie in unserer Erklärung zu MQTT Retained Messages.

Raspberry Pi Relais MQTT-Skript in Python

Legen Sie einen Projektordner und eine virtuelle Umgebung an:

sudo apt update
sudo apt install -y python3-venv python3-lgpio
mkdir -p ~/relay-mqtt && cd ~/relay-mqtt
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install "paho-mqtt>=2.0" gpiozero

Das Flag --system-site-packages erlaubt der virtuellen Umgebung, das lgpio-Backend zu nutzen, das gpiozero auf dem Raspberry Pi 5 braucht und das auch auf älteren Modellen funktioniert. Speichern Sie Folgendes als relay_mqtt.py:

#!/usr/bin/env python3
"""Control a multi-channel relay board from MQTT topics."""
import os
import signal
import sys
import uuid

import paho.mqtt.client as mqtt
from gpiozero import OutputDevice

BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"rpi-relay-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/a91c4e/relays")

RELAY_PINS = {1: 17, 2: 27, 3: 22, 4: 23}
ACTIVE_HIGH = False  # die meisten optoisolierten Hobby-Platinen sind Low-aktiv

relays = {
    n: OutputDevice(pin, active_high=ACTIVE_HIGH, initial_value=False)
    for n, pin in RELAY_PINS.items()
}


def publish_state(client, n):
    state = "ON" if relays[n].value else "OFF"
    client.publish(f"{PREFIX}/{n}/state", state, qos=1, retain=True)


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connection refused: {reason_code}")
        return
    print(f"Connected as {CLIENT_ID}")
    client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)
    client.subscribe(f"{PREFIX}/+/set", qos=1)
    for n in relays:
        publish_state(client, n)


def on_message(client, userdata, msg):
    try:
        n = int(msg.topic.split("/")[-2])
    except ValueError:
        return
    if n not in relays:
        print(f"Ignoring unknown channel {n}")
        return

    command = msg.payload.decode(errors="ignore").strip().upper()
    if command in ("ON", "1", "TRUE"):
        relays[n].on()
    elif command in ("OFF", "0", "FALSE"):
        relays[n].off()
    elif command == "TOGGLE":
        if msg.retain:
            print(f"Ignoring retained TOGGLE on channel {n}")
            return
        relays[n].toggle()
    else:
        print(f"Unknown command {command!r} for channel {n}")
        return
    print(f"Relay {n} -> {'ON' if relays[n].value else 'OFF'}")
    publish_state(client, n)


def on_disconnect(client, userdata, flags, reason_code, properties):
    print(f"Disconnected: {reason_code}; paho will reconnect")


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=60)

if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set()


def shutdown(signum, frame):
    for relay in relays.values():
        relay.off()
    client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True)
    client.disconnect()
    sys.exit(0)


signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)

client.connect(BROKER, PORT, keepalive=30)
client.loop_forever(retry_first_connection=True)

Starten Sie es mit python relay_mqtt.py. Das Skript schaltet bei einem sauberen Herunterfahren alle Relais aus; sollen die Lasten weiterlaufen, wenn der Dienst stoppt, entfernen Sie die Schleife in shutdown.

Vom Laptop aus testen

Öffnen Sie auf einem beliebigen Rechner mit installierten Mosquitto-Clients ein zweites Terminal und beobachten Sie die Zustands-Topics:

mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-a91c4e \
  -t 'connectmq/demo/a91c4e/relays/#' -v

Schalten Sie dann Kanal 1 mit einem retained Befehl ein und Kanal 2 per Toggle um:

mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-a91c4e \
  -t 'connectmq/demo/a91c4e/relays/1/set' -m 'ON' -q 1 -r

mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-a91c4e \
  -t 'connectmq/demo/a91c4e/relays/2/set' -m 'TOGGLE' -q 1

Sie sollten das Klicken hören und relays/1/state ON sehen. Starten Sie nun den Pi neu. Wenn sich das Skript wieder verbindet, kehrt Kanal 1 auf ON zurück, weil der retained Befehl noch auf dem Broker liegt, während Kanal 2 mit OFF startet, weil Toggles nie retained werden. Um einen retained Befehl zu löschen, veröffentlichen Sie eine leere retained Nachricht: mosquitto_pub ... -t '.../relays/1/set' -r -n.

Als Dienst ausführen

Eine Relaissteuerung muss beim Booten starten und nach einem Absturz neu starten. Legen Sie /etc/systemd/system/relay-mqtt.service an:

[Unit]
Description=Relay MQTT controller
After=network-online.target
Wants=network-online.target

[Service]
User=pi
WorkingDirectory=/home/pi/relay-mqtt
Environment=MQTT_HOST=broker.connectmq.com
Environment=MQTT_PORT=8883
Environment=MQTT_USERNAME=YOUR_USERNAME
Environment=MQTT_PASSWORD=YOUR_PASSWORD
Environment=MQTT_CLIENT_ID=YOUR_CLIENT_ID
Environment=MQTT_PREFIX=home/garage/relays
ExecStart=/home/pi/relay-mqtt/.venv/bin/python relay_mqtt.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Aktivieren Sie ihn mit sudo systemctl daemon-reload && sudo systemctl enable --now relay-mqtt. Die vollständige Erklärung zu Service-Dateien, Logging und Umgebungsdateien finden Sie unter Python-MQTT-Skript beim Booten starten. Passen Sie den Benutzernamen an, falls Ihrer nicht pi lautet.

Vom öffentlichen MQTT-Broker in die Produktion

Der öffentliche MQTT-Broker ist für die erste Stunde perfekt, aber wer Ihr Topic errät, könnte Ihre Relais schalten. Für alles, was an echte Anlagen angeschlossen ist, verwenden Sie einen privaten Broker mit Authentifizierung und TLS. Mit einem verwalteten MQTT-Broker wie ConnectMQ legen Sie im Portal einen Broker an, kopieren den generierten Benutzernamen, das Passwort und die Client ID in die Service-Datei oben und setzen den Port auf 8883. Die Client ID ist an die ausgegebenen Zugangsdaten gebunden, sodass kein anderes Gerät Ihre Steuerung imitieren kann. Am Skript ändert sich überhaupt nichts.

Das ConnectMQ-Portal hilft auch bei der Inbetriebnahme: Sein MQTT-Client im Browser kann ON und OFF an jeden Kanal senden, und der Live-Topic-Explorer zeigt retained Zustände und Statuswerte auf einen Blick. Wenn Sie eine Hardware-Alternative zum Pi für dieselbe Aufgabe suchen, vergleichen Sie mit dem Aufbau ESP32-Relais über MQTT.

Fehlerbehebung

  1. Relais schalten beim Start ein und bei Ein-Befehl aus: Ihre Platine ist High-aktiv; setzen Sie ACTIVE_HIGH = True.
  2. LEDs auf der Platine leuchten, aber das Relais klickt nicht: Die Spulenversorgung ist zu schwach; versorgen Sie JD-VCC aus einer separaten 5-V-Quelle.
  3. Connection refused: Not authorized: Benutzername, Passwort und Client ID prüfen oder sie beim anonymen öffentlichen MQTT-Broker weglassen.
  4. Relais stellt nach dem Neustart einen alten Zustand wieder her: Ein veralteter retained Befehl liegt auf dem Broker; löschen Sie ihn mit einem leeren retained Publish.
  5. Fehler GPIO busy: Ein anderes Skript oder ein anderer Dienst nutzt dieselben Pins; beenden Sie es, bevor Sie dieses starten.

Starten Sie mit ConnectMQ

Bereit, echte Geräte zu steuern? Registrieren Sie sich für den kostenlosen Serverless-Plan, ohne Kreditkarte, legen Sie einen Broker an und verbinden Sie Ihren Relaisdienst per TLS. Sie erhalten MQTT 3.1.1 und 5.0, Retained Messages und ein Portal, in dem Sie jedes Schaltereignis verfolgen. Neu in den Konzepten? Das Raspberry Pi MQTT Tutorial behandelt die Grundlagen, und unser Überblick über einen Cloud-MQTT-Broker erklärt, wann ein gehosteter Broker besser ist als Mosquitto auf dem Pi.

Häufig gestellte Fragen

Warum ändert mein Relais nach dem Neustart des Raspberry Pi seinen Zustand?

Es führt einen retained Befehl vom Broker erneut aus, was meist gewünscht ist. Ist der Zustand falsch, veröffentlichen Sie den korrekten Wert mit Retain oder löschen Sie das Topic mit einer leeren retained Nachricht.

Kann ich QoS 1 für Relaisbefehle verwenden?

Ja, und das sollten Sie. QoS 1 garantiert, dass der Befehl mindestens einmal ankommt, und da ON und OFF idempotent sind, schadet eine doppelte Zustellung nicht.

Wie viele Relais kann ein Raspberry Pi steuern?

So viele, wie Sie freie GPIO-Pins haben, typischerweise bis zu acht auf einer Hobby-Platine. Für mehr Kanäle nutzen Sie einen I2C-GPIO-Expander wie den MCP23017 und behalten dieselbe Topic-Struktur bei.

Ist es sicher, Netzgeräte auf diese Weise zu steuern?

Nur mit Relais, die für die Last ausgelegt sind, einem geeigneten Gehäuse und einer Verdrahtung nach den örtlichen Elektrovorschriften. Verwenden Sie für alles, was echte Anlagen schaltet, immer authentifizierte TLS-Verbindungen.

Verwandte Artikel

Raspberry Pi RFID MQTT: Zutrittsprotokollierung mit dem RC522-Leser

Schließen Sie einen RC522-RFID-Leser an einen Raspberry Pi an, lesen Sie Tags mit Python, prüfen Sie sie gegen eine lokale Allowlist und veröffentlichen Sie jeden Zutrittsversuch als MQTT-Ereignis, das Logger, Dashboards und Alarmwerkzeuge verarbeiten können.

7 Min. Lesezeit

Pico W vs. Pico 2 W für MQTT: RP2040 vs. RP2350 bei Leistung, Speicher und TLS

Der Pico 2 W behält Formfaktor und WLAN-Chip des Pico W, ersetzt aber den RP2040 durch den schnelleren RP2350. Dieser Vergleich zeigt, was das für MQTT-Geräte bedeutet: CPU, Speicher, TLS, Sicherheitsfunktionen, Softwareunterstützung und welches Board für welches Projekt.

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.