IoT-Tutorials

Paho MQTT 2.0 Callback API Version: Migrationsfehler Schritt für Schritt beheben

paho-mqtt 2.0 hat über Nacht viel Python-Code lahmgelegt. Erfahren Sie, was sich geändert hat, wie Sie den callback_api_version-Fehler mit einer Zeile beheben und wie Sie jeden Callback mit einem lauffähigen Beispiel auf die VERSION2-Signaturen migrieren.

Code-Diff einer Migration der Paho MQTT 2.0 Callback API Version von VERSION1- auf VERSION2-Callbacks
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

Die Änderung der Callback API Version in Paho MQTT 2.0 ist der häufigste Grund, warum Python-MQTT-Skripte nach einem pip install --upgrade plötzlich nicht mehr funktionieren. Dieser Leitfaden erklärt genau, was sich in paho-mqtt 2.0 geändert hat, liefert Ihnen die einzeilige Lösung für den Fehler und führt Sie dann durch die Migration jedes Callbacks auf die empfohlenen VERSION2-Signaturen. Am Ende haben Sie ein vollständiges, lauffähiges Beispiel mit Verbindung zu broker.connectmq.com, das Sie als Vorlage nutzen können.

Die Fehler, die Sie wahrscheinlich sehen

Sind Sie über eine Suchmaschine hier gelandet, haben Sie höchstwahrscheinlich einen dieser Fehler:

ValueError: Unsupported callback API version: version 2.0 added a callback_api_version, see docs/migrations.rst for details
TypeError: Client.__init__() missing 1 required positional argument: 'callback_api_version'
DeprecationWarning: Callback API version 1 is deprecated, update to latest version
TypeError: on_connect() takes 4 positional arguments but 5 were given

Die ersten beiden entstehen, wenn der Client auf die 1.x-Art erzeugt wird. Der ValueError tritt auf, wenn Sie eine Client ID als erstes Positionsargument übergeben, wie in mqtt.Client("my-device"), denn diese Position gehört nun der Callback API Version. Der dritte ist eine Warnung, dass Sie die alte API ausdrücklich gewählt haben. Der vierte erscheint, nachdem Sie auf VERSION2 umgestellt, aber einen Callback mit der alten Parameterzahl belassen haben.

Was sich in paho-mqtt 2.0 geändert hat

Version 2.0 des Eclipse-Paho-Python-Clients, Anfang 2024 erschienen, war das erste Major-Release seit Jahren. Die zentrale Änderung: Callbacks sind jetzt versioniert. In 1.x unterschieden sich die an Callbacks übergebenen Parameter zwischen MQTT 3.1.1 und MQTT 5, und manche verwendeten einfache Integer, andere Reason-Code-Objekte. Version 2 vereinheitlicht das: Jeder Callback erhält unabhängig von der Protokollversion dieselben Parameter, und Ergebniscodes sind immer ReasonCode-Objekte.

Damit neue Signaturen bestehenden Code nicht stillschweigend brechen, verlangen die Maintainer eine ausdrückliche Wahl. Das erste Argument von Client() ist jetzt callback_api_version, mit zwei möglichen Werten:

Wert Verhalten Empfohlen?
CallbackAPIVersion.VERSION1 Alte Callback-Signaturen aus 1.x, gibt eine Deprecation-Warnung aus Nur als vorübergehende Brücke
CallbackAPIVersion.VERSION2 Neue einheitliche Signaturen, überall ReasonCode-Objekte Ja, für allen neuen und migrierten Code

Weitere nennenswerte Änderungen in 2.0 sind der Wegfall der Unterstützung für Python 2.7 und sehr alte Python-3-Versionen sowie die Umbenennung der Klasse ReasonCodes in ReasonCode. Die vollständige Liste finden Sie in den offiziellen Migrationshinweisen von paho-mqtt.

Lösung 1: Die einzeilige Brücke (VERSION1)

Ist die Produktion ausgefallen, etwa ein Edge-Gateway, das nach einem Update keine Maschinendaten mehr aus der Halle liefert, und muss sofort wieder laufen, weisen Sie paho an, das alte Verhalten beizubehalten:

import paho.mqtt.client as mqtt

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, client_id="my-device")

Alle bestehenden Callbacks funktionieren unverändert weiter. Sie sehen die Deprecation-Warnung, die daran erinnert, dass VERSION1 in einem künftigen Major-Release entfernt wird. Betrachten Sie das als Pflaster, nicht als Lösung.

Ein alternatives Pflaster ist das Fixieren der alten Bibliothek mit pip install "paho-mqtt<2.0". Das funktioniert, blockiert aber Sicherheits- und Fehlerkorrekturen und kollidiert gern mit anderen Paketen, die bereits 2.x voraussetzen. Ziehen Sie das VERSION1-Flag dem Fixieren vor und planen Sie die echte Migration.

Lösung 2: Auf Version 2 der Paho MQTT 2.0 Callback API migrieren

Die echte Lösung besteht darin, VERSION2 zu übergeben und die Callback-Signaturen anzupassen. Hier alle Callbacks im direkten Vergleich:

Callback Signatur 1.x / VERSION1 Signatur VERSION2
on_connect (client, userdata, flags, rc) (client, userdata, flags, reason_code, properties)
on_disconnect (client, userdata, rc) (client, userdata, disconnect_flags, reason_code, properties)
on_subscribe (client, userdata, mid, granted_qos) (client, userdata, mid, reason_code_list, properties)
on_unsubscribe (client, userdata, mid) (client, userdata, mid, reason_code_list, properties)
on_publish (client, userdata, mid) (client, userdata, mid, reason_code, properties)
on_message (client, userdata, message) unverändert
on_log (client, userdata, level, buf) unverändert

Unter VERSION1 mit MQTT 5 hatten einige davon bereits zusätzliche Parameter; VERSION2 beseitigt diesen Unterschied – genau darum geht es bei der Änderung.

Migrations-Checkliste

Arbeiten Sie Ihren Code in dieser Reihenfolge durch:

  1. Ändern Sie jeden Aufruf mqtt.Client(...) in mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=..., ...) und übergeben Sie alle anderen Argumente als Schlüsselwortargumente.
  2. Ergänzen Sie properties in on_connect und benennen Sie rc in reason_code um. Ersetzen Sie rc == 0 durch not reason_code.is_failure (der Vergleich mit Integern funktioniert weiterhin, das Attribut liest sich aber besser).
  3. Ersetzen Sie flags["session present"] durch flags.session_present.
  4. Geben Sie on_disconnect den neuen Parameter disconnect_flags sowie properties.
  5. Ersetzen Sie in on_subscribe granted_qos durch reason_code_list und prüfen Sie jeden Eintrag: Erfolgscodes haben Werte von 0 bis 2 (die gewährte QoS), bei Fehlern ist is_failure gesetzt.
  6. Ergänzen Sie reason_code und properties in on_publish und on_unsubscribe.
  7. Durchsuchen Sie die Codebasis nach ReasonCodes und ändern Sie es in ReasonCode.
  8. Führen Sie Ihre Tests mit Warnungen als Fehler aus (python -W error::DeprecationWarning), um zu belegen, dass kein VERSION1-Client übrig ist.

Ein vollständiges VERSION2-Beispiel

Dieses Skript nutzt alle gängigen Callbacks mit den neuen Signaturen. Ersetzen Sie k7f3q2 durch eine eigene Zufallszeichenfolge, damit Sie keine Topics mit anderen Nutzern des öffentlichen MQTT-Brokers teilen (er ist für Tests gedacht, nicht für Produktionsdaten):

import time
import uuid

import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/k7f3q2"


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connect failed: {reason_code}")
        return
    print(f"Connected (session present: {flags.session_present})")
    client.subscribe(f"{PREFIX}/#", qos=1)


def on_subscribe(client, userdata, mid, reason_code_list, properties):
    for rc in reason_code_list:
        print("Subscribe rejected:" if rc.is_failure else "Granted QoS:", rc)


def on_publish(client, userdata, mid, reason_code, properties):
    print(f"Publish {mid} acknowledged: {reason_code}")


def on_message(client, userdata, msg):
    print(f"{msg.topic}: {msg.payload.decode()}")


def on_disconnect(client, userdata, disconnect_flags, reason_code, properties):
    print(f"Disconnected: {reason_code}")


client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=f"migrate-{uuid.uuid4().hex[:8]}",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_publish = on_publish
client.on_message = on_message
client.on_disconnect = on_disconnect

client.connect(BROKER, 1883, keepalive=60)
client.loop_start()
time.sleep(1)

for i in range(3):
    client.publish(f"{PREFIX}/test", f"hello {i}", qos=1)
    time.sleep(1)

client.disconnect()
client.loop_stop()

Führen Sie es aus, und Sie sollten den Connect, die gewährte QoS, drei Publish-Bestätigungen und die drei Nachrichten sehen, die der öffentliche MQTT-Broker von ConnectMQ zurückliefert. Stellen Sie protocol auf mqtt.MQTTv311 um, und dieselben Callbacks funktionieren ohne Änderungen weiter – genau das verspricht VERSION2. Sind Sie neu bei der Bibliothek selbst, beginnen Sie zuerst mit dem Paho-MQTT-Python-Tutorial.

Fallstricke nach der Migration

Drittanbieter-Bibliotheken, die auf 1.x fixiert sind. Einige Pakete, die paho kapseln, haben paho-mqtt<2.0 in ihren Abhängigkeiten deklariert. Prüfen Sie das mit pip show und pip check. Aktuelle Releases der meisten gepflegten Wrapper unterstützen 2.x; aktualisieren Sie diese oder isolieren Sie Altwerkzeuge in einer eigenen virtuellen Umgebung.

Positionsargumente. Jeder Aufruf wie mqtt.Client("id", False, None, mqtt.MQTTv311) ist jetzt um eine Position verschoben. Wandeln Sie alle in Schlüsselwortargumente um; das macht künftige Upgrades schmerzlos.

Per Decorator registrierte Callbacks. Code, der @client.connect_callback() und ähnliche Decorators verwendet, muss die Signaturen der dekorierten Funktionen ebenfalls anpassen.

Verschluckte Exceptions. Standardmäßig protokolliert paho Exceptions, die in Callbacks ausgelöst werden, statt Ihr Programm abstürzen zu lassen. Eine falsche Signatur kann daher wie „nichts passiert" aussehen. Hängen Sie während der Migration mit client.enable_logger() einen Logger an, damit der TypeError sichtbar wird.

Reconnect-Logik. Haben Sie in on_disconnect Integer-Werte von rc verglichen, um über einen Reconnect zu entscheiden, schreiben Sie das auf reason_code um. Der Leitfaden zu Reconnects mit paho-mqtt zeigt robuste Muster, und der Leitfaden zu Python, MQTT und TLS behandelt die verschlüsselte Verbindung, die Sie in der Produktion verwenden sollten.

Sollten Sie stattdessen aiomqtt in Betracht ziehen?

Basiert Ihre Anwendung auf asyncio, kann die Migration der Callbacks ein guter Moment sein, ganz auf eine asynchrone API umzusteigen. aiomqtt kapselt paho und ersetzt Callbacks durch async for message in client.messages. Unser Tutorial zu aiomqtt und asyncio zeigt denselben Publish/Subscribe-Ablauf in dieser Form. Einen breiteren Vergleich von Python-Clients und Clients anderer Sprachen bietet die Übersicht über MQTT-Client-Bibliotheken.

Testen Sie Ihren migrierten Code auf ConnectMQ

ConnectMQ betreibt unter broker.connectmq.com einen kostenlosen öffentlichen MQTT-Broker, der sich ideal zur Überprüfung einer Migration eignet, sowie einen verwalteten MQTT-Broker für die Produktion mit MQTT 3.1.1 und 5.0, TLS auf 8883 und generierten Zugangsdaten. Das Portal enthält einen Live-Topic-Explorer, mit dem Sie bestätigen können, dass migrierte Clients weiterhin publizieren, was Sie erwarten. Sind Sie bereit, den öffentlichen Broker zu verlassen, betreiben Sie Ihre Clients auf einem privaten Cloud-MQTT-Broker: Registrieren Sie sich für den kostenlosen Serverless-Plan, ohne Kreditkarte.

Häufig gestellte Fragen

Was ist callback_api_version in paho-mqtt?

Es ist seit paho-mqtt 2.0 das erste Argument von mqtt.Client(). Es legt fest, welche Callback-Signaturen der Client verwendet: VERSION1 für den alten 1.x-Stil oder VERSION2 für den neuen, einheitlichen Stil.

Sollte ich VERSION1 oder VERSION2 verwenden?

Verwenden Sie VERSION2. VERSION1 existiert nur, damit alter Code weiterläuft, gibt eine Deprecation-Warnung aus und wird daher irgendwann entfernt.

Warum erhalte ich „Unsupported callback API version", wenn ich eine Client ID übergebe?

Sie haben die Client ID als erstes Positionsargument übergeben, das nun der Callback API Version vorbehalten ist. Übergeben Sie zuerst mqtt.CallbackAPIVersion.VERSION2 und die ID als client_id=....

Muss ich on_message bei der Migration ändern?

Nein. on_message(client, userdata, message) behält in beiden Versionen dieselbe Signatur. Die Änderungen betreffen die Callbacks für Connect, Disconnect, Subscribe, Unsubscribe und Publish.

Verwandte Artikel

Die besten MQTT-CLI-Tools zum Testen, Skripten und Debuggen

Ein praxisnaher Vergleich von mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, der MQTT.js-CLI, curl und mqttui – mit demselben Test gegen broker.connectmq.com, damit Sie das richtige Tool zum Skripten und Debuggen wählen.

8 Min. Lesezeit

MQTT-Daten mit Python in InfluxDB speichern

Bauen Sie mit paho-mqtt und influxdb-client eine Python-Bridge, die einen Broker abonniert, Topic-Ebenen in InfluxDB-Tags verwandelt, numerische JSON-Werte als Fields in Batches schreibt und fehlerhafte Payloads sowie Typkonflikte behandelt.

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.