Pico W MQTT TLS macht aus einer Bastelverbindung eine, der Sie vertrauen können: Der Verkehr ist verschlüsselt, und das Board prüft, dass es wirklich mit Ihrem Broker spricht, bevor es ein Passwort sendet. Dieser Leitfaden nimmt einen funktionierenden MicroPython-MQTT-Sketch und stellt ihn auf Port 8883 mit vollständiger Zertifikatsprüfung um. Er behandelt die nötigen Firmware-Versionen, das zu ladende Root-Zertifikat, warum die Uhrzeit wichtig ist, wie lange der Handshake auf einem RP2040 dauert und wie Sie die wahrscheinlichsten Fehler beheben.
Warum TLS auf einem Mikrocontroller wichtig ist
Unverschlüsseltes MQTT auf Port 1883 überträgt alles im Klartext, einschließlich Benutzername und Passwort im CONNECT-Paket. Jeder im selben WLAN, beim Provider oder auf dem Weg zum Broker kann Ihre Messwerte lesen und Ihre Zugangsdaten wiederverwenden. TLS löst zwei Probleme auf einmal:
- Verschlüsselung. Payloads und Zugangsdaten sind während der Übertragung unlesbar.
- Serverauthentifizierung. Das Gerät prüft die Zertifikatskette des Brokers, sodass ein gefälschter Access Point oder ein DNS-Hijack den Broker nicht imitieren und Zugangsdaten abgreifen kann.
Den zweiten Punkt überspringen die meisten Tutorials. TLS ohne Zertifikatsprüfung einzuschalten, schützt vor passiven Lauschern, aber nicht vor einem aktiven Angreifer. Dieser Leitfaden macht es richtig. Das Gesamtbild finden Sie unter Best Practices für MQTT-Sicherheit; im industriellen Umfeld knüpfen diese Maßnahmen an Anforderungen aus IEC 62443 und NIS2 an.
Wenn Sie einen Pico W noch nie mit MQTT verbunden haben, beginnen Sie mit dem einfachen Tutorial Raspberry Pi Pico W und MQTT und kehren Sie zurück, sobald das funktioniert.
Firmware- und Bibliotheksversionen
Die TLS-Unterstützung in MicroPython hat sich in den letzten Releases verändert, und viele ältere Beispiele laufen nicht mehr wie geschrieben.
| Komponente | Was Sie verwenden sollten | Warum |
|---|---|---|
| MicroPython-Firmware | Ein aktuelles Release für RPI_PICO_W (1.23 oder neuer) |
Bietet ssl.SSLContext mit load_verify_locations und korrekter Hostnamen-Behandlung |
umqtt.simple |
Die aktuelle Version aus micropython-lib per mip |
Neuere Versionen akzeptieren einen SSLContext im Argument ssl |
| Root-Zertifikat | ISRG Root X1 im DER-Format | Der Vertrauensanker für Let's-Encrypt-Zertifikate |
Ältere Beispiele übergeben ssl=True zusammen mit einem ssl_params-Dictionary. Sehen Sie einen TypeError wegen unerwarteter Keyword-Argumente oder AttributeError: 'bool' object has no attribute 'wrap_socket', kombinieren Sie ein altes Beispiel mit einer neuen Bibliothek oder umgekehrt. Aktualisieren Sie Firmware und Bibliothek und verwenden Sie den kontextbasierten Code unten.
Prüfen Sie in der REPL, was Sie einsetzen:
import sys, os
print(sys.version)
print(os.uname().machine)
Schritt 1: Das richtige Root-Zertifikat besorgen
ConnectMQ-Broker, einschließlich des Öffentlichen MQTT-Brokers unter broker.connectmq.com, verwenden Zertifikate von Let's Encrypt. Sie können die Kette selbst prüfen:
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -showcerts </dev/null \
| grep -E "s:|i:"
Die Ausgabe listet das Serverzertifikat, das Let's-Encrypt-Zwischenzertifikat und am Ende einen Aussteller ISRG Root X1. Diesem Root sollte der Pico W vertrauen. Dem Root statt dem Serverzertifikat zu vertrauen ist wichtig: Let's-Encrypt-Zertifikate werden alle paar Monate erneuert, und Zwischenzertifikate ändern sich gelegentlich, aber das Root bleibt jahrelang gültig.
Laden Sie das Root im DER-Format herunter, das MicroPython direkt einlesen kann:
curl -o isrgrootx1.der https://letsencrypt.org/certs/isrgrootx1.der
# or convert a PEM copy you already have
openssl x509 -in isrgrootx1.pem -outform DER -out isrgrootx1.der
Kopieren Sie es über die Dateiansicht von Thonny oder so auf das Board:
mpremote cp isrgrootx1.der :isrgrootx1.der
Schritt 2: Die Uhr stellen
Der Pico W hat keine batteriegepufferte Uhr. Nach jedem Einschalten startet seine Echtzeituhr mit einem Standarddatum in der Vergangenheit. Je nach Firmware-Build wird der Gültigkeitszeitraum von Zertifikaten gegen diese Uhr geprüft, und ein Gerät, das sich Jahre in der Vergangenheit wähnt, lehnt ein im letzten Monat ausgestelltes Zertifikat als noch nicht gültig ab. Selbst wenn die Prüfung nicht erzwungen wird, ist die korrekte Zeit für Logs und Zeitstempel nützlich; stellen Sie sie also direkt nach dem WLAN-Verbindungsaufbau per NTP:
import ntptime
ntptime.host = "pool.ntp.org"
ntptime.settime() # sets the RTC to UTC
ntptime.settime() kann bei einem NTP-Timeout OSError auslösen; wiederholen Sie den Aufruf daher einige Male, statt das Programm abstürzen zu lassen.
Schritt 3: Das vollständige Pico-W-MQTT-TLS-Programm
Speichern Sie dies als main.py. Für den öffentlichen MQTT-Broker können die Zugangsdaten leer bleiben, und jede eindeutige Client ID funktioniert. Für die Produktion tragen Sie die im Portal generierten Werte ein.
# main.py - Pico W MQTT over TLS with certificate verification
import time
import gc
import ssl
import network
import machine
import ntptime
import ubinascii
from umqtt.simple import MQTTClient
WIFI_SSID = "YOUR_WIFI_SSID"
WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"
BROKER = "broker.connectmq.com"
PORT = 8883
# Public test broker: anonymous, any unique client ID.
# Production: use the values from the broker portal.
MQTT_USER = None # "YOUR_USERNAME"
MQTT_PASSWORD = None # "YOUR_PASSWORD"
CLIENT_ID = "pico-tls-" + ubinascii.hexlify(machine.unique_id()).decode() # or "YOUR_CLIENT_ID"
TOPIC = "connectmq/demo/tl5v8n/pico1/temperature"
CA_FILE = "isrgrootx1.der"
sensor = machine.ADC(4)
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
for _ in range(40):
if wlan.isconnected():
break
time.sleep(0.5)
if not wlan.isconnected():
raise OSError("Wi-Fi failed, status %d" % wlan.status())
print("Wi-Fi:", wlan.ifconfig()[0])
def sync_time():
for attempt in range(5):
try:
ntptime.settime()
print("Time set:", time.gmtime())
return
except OSError:
time.sleep(2)
print("Warning: NTP failed, clock may be wrong")
def make_ssl_context():
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.verify_mode = ssl.CERT_REQUIRED
with open(CA_FILE, "rb") as f:
ctx.load_verify_locations(cadata=f.read())
return ctx
def connect_mqtt(ctx):
gc.collect()
print("Free RAM before TLS:", gc.mem_free())
client = MQTTClient(
CLIENT_ID, BROKER, port=PORT,
user=MQTT_USER, password=MQTT_PASSWORD,
keepalive=60, ssl=ctx,
)
start = time.ticks_ms()
client.connect()
print("TLS + MQTT connect took", time.ticks_diff(time.ticks_ms(), start), "ms")
print("Free RAM after TLS:", gc.mem_free())
return client
def read_temperature():
v = sensor.read_u16() * 3.3 / 65535
return round(27 - (v - 0.706) / 0.001721, 2)
def main():
connect_wifi()
sync_time()
ctx = make_ssl_context()
client = connect_mqtt(ctx)
while True:
payload = '{"value": %s, "unit": "C"}' % read_temperature()
client.publish(TOPIC, payload, qos=1)
print("Published", payload)
time.sleep(30) # publishing every 30 s keeps the 60 s keepalive satisfied
while True:
try:
main()
except OSError as e:
print("Error:", e, "- reconnecting in 10 s")
time.sleep(10)
umqtt.simple umhüllt den Socket mit dem Kontext und übergibt den Broker-Namen als Server-Hostnamen. Dadurch kann mbedTLS prüfen, dass das Zertifikat für broker.connectmq.com ausgestellt wurde, und es sendet außerdem SNI, das viele TLS-Server benötigen, um das richtige Zertifikat auszuwählen.
Beobachten Sie die Ausgabe von Ihrem Computer aus, ebenfalls über TLS:
mosquitto_sub -h broker.connectmq.com -p 8883 --cafile isrgrootx1.pem \
-i laptop-tl5v8n -v -t "connectmq/demo/tl5v8n/#"
Handshake-Zeit und Speicher auf dem RP2040
Der RP2040 hat keine Hardware-Kryptobeschleunigung, daher erledigt mbedTLS die gesamte Arbeit in Software auf Cortex-M0+-Kernen. Rechnen Sie mit einem deutlich spürbaren TLS-Handshake, oft in der Größenordnung von einer Sekunde oder mehr, verglichen mit einem nahezu sofortigen TCP-Verbindungsaufbau ohne Verschlüsselung. Das Programm gibt den genauen Wert in Ihrem Netzwerk aus; es lohnt sich, ihn festzuhalten, weil er vom ausgehandelten Schlüsselaustausch, der Länge der Zertifikatskette und der WLAN-Latenz abhängt.
Was das in der Praxis bedeutet:
- Einmal verbinden, verbunden bleiben. Bei Netzbetrieb halten Sie eine langlebige TLS-Session und senden viele Nachrichten darüber. Die Handshake-Kosten fallen nur beim Reconnect an.
- Vorsicht bei Deep-Sleep-Designs. Ein Batteriegerät, das aufwacht, verbindet, publiziert und schläft, zahlt in jedem Zyklus den vollen Handshake, was Zeit und Energie kostet. Unser Leitfaden Pico W im Batteriebetrieb mit MQTT behandelt längere Intervalle und Bündelung für diesen Fall.
- Zuerst Speicher freigeben. Eine TLS-Session braucht Dutzende Kilobyte RAM für Puffer. Rufen Sie vor dem Verbinden
gc.collect()auf, vermeiden Sie große Objekte vor dem Handshake und vergleichen Sie die vorher und nachher ausgegebenen Werte für freien Speicher. - Den Pico 2 W in Betracht ziehen. Sein RP2350 nutzt schnellere Cortex-M33-Kerne, was den Handshake verkürzt und mehr Reserven lässt. Siehe Pico W vs. Pico 2 W.
TLS-Fehler auf dem Pico W beheben
| Fehler oder Symptom | Wahrscheinliche Ursache | Lösung |
|---|---|---|
OSError: (-9984, 'MBEDTLS_ERR_X509_CERT_VERIFY_FAILED') |
Falsches oder fehlendes Root-Zertifikat oder falscher Hostname | ISRG Root X1 laden, per Hostname statt IP verbinden |
| Prüfung schlägt nur nach dem Einschalten fehl | Uhr nicht gestellt | ntptime.settime() vor dem Verbinden ausführen |
OSError: [Errno 12] ENOMEM |
Nicht genug zusammenhängender RAM für TLS-Puffer | gc.collect() vor dem Verbinden, Puffer und globale Variablen reduzieren |
TypeError bei MQTTClient(... ssl_params=...) |
Altes Beispiel mit neuem umqtt.simple |
Einen SSLContext als ssl= übergeben |
| Verbindung klappt auf 1883, aber Timeout auf 8883 | Netzwerk blockiert 8883 | Von einem Laptop im selben Netz testen; anderes Netz nutzen oder die IT bitten, ausgehend 8883 freizugeben |
MQTTException: 5 |
Nicht autorisiert | Benutzername, Passwort und exakte Client ID aus dem Portal prüfen |
| Handshake dauert sehr lange | Schwaches WLAN-Signal oder Speicherdruck | RSSI mit wlan.status("rssi") und freien Speicher prüfen |
Ein Hinweis zu CERT_NONE: ctx.verify_mode = ssl.CERT_NONE lässt die Fehler verschwinden, weshalb es in vielen Forenantworten auftaucht. Es entfernt aber auch die Serverauthentifizierung. Nutzen Sie es nur für eine einmalige Diagnose, niemals in ausgeliefertem Code.
Auf Ihren eigenen privaten Broker umziehen
Der öffentliche MQTT-Broker akzeptiert anonyme TLS-Verbindungen auf 8883, was ideal zum Testen dieses Codes ist. Für echte Geräte legen Sie einen privaten Broker bei ConnectMQ an und kopieren die generierten Zugangsdaten in die drei Einstellungen am Anfang des Programms. Der Broker bindet Client IDs an die ausgegebenen Zugangsdaten; verwenden Sie die Client ID aus dem Portal also exakt. Weil das Zertifikat von Let's Encrypt stammt, funktioniert dieselbe Datei isrgrootx1.der für den öffentlichen und Ihren privaten Broker, und Zertifikatserneuerungen auf der Broker-Seite erfordern keine Änderung am Gerät.
Ein verwalteter MQTT-Broker sperrt außerdem IP-Adressen nach wiederholten fehlgeschlagenen Anmeldungen und setzt Kontingente pro Plan durch, was Ihren Broker ohne eigenen Aufwand vor fehlerhaften oder kompromittierten Clients schützt. Mehr zum Betrieb von Brokern in der Cloud finden Sie in unserem Leitfaden zum Cloud-MQTT-Broker, und weitere Raspberry-Pi-Projekte im Raspberry-Pi-MQTT-Tutorial.
Ihren Pico W mit ConnectMQ absichern
Legen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker an, ohne Kreditkarte, kopieren Sie Benutzername, Passwort und Client ID in main.py, und Ihr Pico W publiziert über geprüftes TLS auf Port 8883. Der Live-Topic-Explorer im Portal zeigt die eintreffenden Nachrichten, sodass Sie den sicheren Pfad durchgängig bestätigen können.
Häufig gestellte Fragen
Welches Zertifikat braucht der Pico W für ConnectMQ?
ISRG Root X1, das Root von Let's Encrypt, im DER-Format. Wenn Sie dem Root vertrauen, erfordern routinemäßige Zertifikatserneuerungen am Broker kein Update des Geräts.
Warum lehnt mein Pico W ein gültiges Zertifikat ab?
Die häufigsten Ursachen sind eine nie gestellte Uhr, sodass das Zertifikat als noch nicht gültig erscheint, eine Verbindung per IP-Adresse statt Hostname oder ein falsches Root-Zertifikat.
Wie lange dauert ein TLS-Handshake auf dem Pico W?
Er ist spürbar langsamer als auf Chips mit Krypto-Hardware, weil der RP2040 die gesamte Kryptografie in Software ausführt. Messen Sie ihn wie oben gezeigt mit time.ticks_ms() um connect() herum und halten Sie Verbindungen offen, statt für jede Nachricht neu zu verbinden.
Kann ich auf dem Pico W Client-Zertifikate verwenden?
Der SSLContext von MicroPython unterstützt load_cert_chain für Client-Zertifikate. Der Broker authentifiziert Geräte mit Benutzername, Passwort und Client ID aus dem Portal; eine serverseitig geprüfte TLS-Verbindung mit diesen Zugangsdaten ist daher die Standardkonfiguration.



