Tutoriels IoT

Callback API version de Paho MQTT 2.0 : corriger les erreurs de migration pas à pas

Paho-mqtt 2.0 a cassé beaucoup de code Python du jour au lendemain. Découvrez ce qui a changé, comment corriger l'erreur callback_api_version en une ligne et comment migrer chaque callback vers les signatures VERSION2 avec un exemple fonctionnel.

Diff de code montrant une migration de la callback API version de Paho MQTT 2.0, des callbacks VERSION1 vers VERSION2
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Le changement de callback API version de paho-mqtt 2.0 est de loin la raison la plus fréquente pour laquelle des scripts MQTT Python cessent soudainement de fonctionner après un pip install --upgrade. Ce guide explique précisément ce qui a changé dans paho-mqtt 2.0, vous donne la correction en une ligne pour l'erreur, puis détaille la migration de chaque callback vers les signatures VERSION2 recommandées. Vous terminerez avec un exemple complet et fonctionnel connecté à broker.connectmq.com que vous pourrez utiliser comme modèle.

Les erreurs que vous voyez probablement

Si vous arrivez ici depuis un moteur de recherche, vous avez très probablement l'une de ces erreurs :

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

Les deux premières viennent d'une création du client à la manière 1.x. La ValueError apparaît quand vous passez un client ID comme premier argument positionnel, comme dans mqtt.Client("my-device"), car cette position appartient désormais à la callback API version. La troisième est un avertissement indiquant que vous avez explicitement choisi l'ancienne API. La quatrième apparaît après le passage à VERSION2 si un callback a conservé l'ancien nombre de paramètres.

Ce qui a changé dans paho-mqtt 2.0

La version 2.0 du client Python Eclipse Paho, publiée début 2024, a été la première version majeure depuis des années. Son changement phare est que les callbacks sont désormais versionnés. En 1.x, les paramètres transmis aux callbacks différaient entre MQTT 3.1.1 et MQTT 5, et certains utilisaient de simples entiers tandis que d'autres utilisaient des objets reason code. La version 2 les unifie : chaque callback reçoit les mêmes paramètres quelle que soit la version du protocole, et les codes de résultat sont toujours des objets ReasonCode.

Pour éviter de casser silencieusement du code avec de nouvelles signatures, les mainteneurs vous obligent à choisir explicitement. Le premier argument de Client() est maintenant callback_api_version, avec deux valeurs possibles :

Valeur Comportement Recommandée ?
CallbackAPIVersion.VERSION1 Anciennes signatures de callbacks 1.x, émet un avertissement de dépréciation Uniquement comme solution de transition temporaire
CallbackAPIVersion.VERSION2 Nouvelles signatures unifiées, objets ReasonCode partout Oui, pour tout code nouveau ou migré

Parmi les autres changements notables de la 2.0 figurent l'abandon de la prise en charge de Python 2.7 et des très anciennes versions de Python 3, ainsi que le renommage de la classe ReasonCodes en ReasonCode. La liste complète se trouve dans les notes de migration officielles de paho-mqtt.

Correction 1 : la solution de transition en une ligne (VERSION1)

Si la production est en panne et que vous devez la rétablir immédiatement, demandez à paho de conserver l'ancien comportement :

import paho.mqtt.client as mqtt

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

Tous vos callbacks existants continuent de fonctionner sans modification. Vous verrez l'avertissement de dépréciation, qui vous rappelle que VERSION1 sera supprimée dans une future version majeure. Considérez cela comme un pansement, pas comme une correction.

Un autre pansement consiste à figer l'ancienne bibliothèque avec pip install "paho-mqtt<2.0". Cela fonctionne, mais bloque les correctifs de sécurité et de bugs, et entre souvent en conflit avec d'autres paquets qui exigent déjà la 2.x. Préférez le flag VERSION1 au gel de version, et planifiez la vraie migration.

Correction 2 : migrer vers la callback API version 2 de Paho MQTT 2.0

La vraie correction consiste à passer VERSION2 et à mettre à jour les signatures des callbacks. Voici tous les callbacks côte à côte :

Callback Signature 1.x / VERSION1 Signature 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) inchangée
on_log (client, userdata, level, buf) inchangée

Avec VERSION1 et MQTT 5, certains de ces callbacks avaient déjà des paramètres supplémentaires ; VERSION2 supprime cette différence, ce qui est tout l'objet du changement.

Liste de vérification de la migration

Parcourez votre code dans cet ordre :

  1. Remplacez chaque appel mqtt.Client(...) par mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=..., ...), en passant tous les autres arguments par mot-clé.
  2. Ajoutez properties à on_connect et renommez rc en reason_code. Remplacez rc == 0 par not reason_code.is_failure (la comparaison avec des entiers fonctionne toujours, mais l'attribut est plus lisible).
  3. Remplacez flags["session present"] par flags.session_present.
  4. Donnez à on_disconnect son nouveau paramètre disconnect_flags ainsi que properties.
  5. Dans on_subscribe, remplacez granted_qos par reason_code_list et vérifiez chaque entrée : les codes de succès ont des valeurs de 0 à 2 (la QoS accordée), les échecs ont is_failure positionné.
  6. Ajoutez reason_code et properties à on_publish et à on_unsubscribe.
  7. Recherchez ReasonCodes dans le code et remplacez-le par ReasonCode.
  8. Exécutez vos tests en transformant les avertissements en erreurs (python -W error::DeprecationWarning) pour prouver qu'il ne reste aucun client VERSION1.

Un exemple VERSION2 complet

Ce script utilise tous les callbacks courants avec les nouvelles signatures. Remplacez k7f3q2 par votre propre chaîne aléatoire pour ne pas partager vos topics avec d'autres utilisateurs du serveur MQTT public gratuit :

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()

Exécutez-le et vous devriez voir la connexion, la QoS accordée, trois accusés de publication et les trois messages renvoyés par le serveur public ConnectMQ. Passez protocol à mqtt.MQTTv311 et les mêmes callbacks fonctionnent toujours sans modification, ce qui est exactement la promesse de VERSION2. Si vous découvrez la bibliothèque elle-même, commencez plutôt par le tutoriel Paho MQTT Python.

Pièges après la migration

Bibliothèques tierces figées en 1.x. Certains paquets qui enveloppent paho ont déclaré paho-mqtt<2.0 dans leurs dépendances. Vérifiez avec pip show et pip check. Les versions récentes de la plupart des wrappers maintenus prennent en charge la 2.x ; mettez-les à jour, ou isolez les outils anciens dans leur propre environnement virtuel.

Arguments positionnels. Tout appel du type mqtt.Client("id", False, None, mqtt.MQTTv311) est désormais décalé d'une position. Convertissez-les tous en arguments nommés ; cela rendra les futures mises à niveau indolores.

Callbacks enregistrés avec des décorateurs. Le code qui utilise @client.connect_callback() et des décorateurs similaires doit lui aussi mettre à jour les signatures des fonctions décorées.

Exceptions avalées. Par défaut, paho journalise les exceptions levées dans les callbacks au lieu de faire planter votre programme. Une mauvaise signature peut donc ressembler à « il ne se passe rien ». Attachez un logger avec client.enable_logger() pendant la migration pour que le TypeError soit visible.

Logique de reconnexion. Si vous compariez des entiers rc dans on_disconnect pour décider de vous reconnecter, réécrivez cette logique autour de reason_code. Le guide de reconnexion paho-mqtt présente des patterns robustes, et le guide Python MQTT TLS couvre la connexion chiffrée à utiliser en production.

Faut-il envisager aiomqtt à la place ?

Si votre application repose sur asyncio, la migration des callbacks peut être le bon moment pour passer complètement à une API asynchrone. aiomqtt enveloppe paho et remplace les callbacks par async for message in client.messages. Notre tutoriel aiomqtt et asyncio montre le même flux publish/subscribe écrit de cette manière. Pour une comparaison plus large des clients Python et des autres langages, consultez la vue d'ensemble des bibliothèques clientes MQTT.

Testez votre code migré sur ConnectMQ

ConnectMQ exploite le serveur MQTT public gratuit broker.connectmq.com, idéal pour vérifier une migration mais pas pour des données de production, ainsi qu'un broker MQTT managé pour la production avec MQTT 3.1.1 et 5.0, TLS sur le port 8883 et des identifiants générés. Son portail inclut un explorateur de topics en direct pour confirmer que les clients migrés publient toujours ce que vous attendez. Quand vous êtes prêt à quitter le serveur public, faites tourner vos clients sur un broker MQTT cloud privé : inscrivez-vous à l'offre Serverless gratuite, sans carte bancaire.

Questions fréquentes

Qu'est-ce que callback_api_version dans paho-mqtt ?

C'est le premier argument de mqtt.Client() depuis paho-mqtt 2.0. Il sélectionne les signatures de callbacks utilisées par le client : VERSION1 pour l'ancien style 1.x ou VERSION2 pour le nouveau style unifié.

Faut-il utiliser VERSION1 ou VERSION2 ?

Utilisez VERSION2. VERSION1 n'existe que pour faire tourner l'ancien code et affiche un avertissement de dépréciation : elle finira donc par être supprimée.

Pourquoi est-ce que j'obtiens « Unsupported callback API version » en passant un client ID ?

Vous avez passé le client ID comme premier argument positionnel, désormais réservé à la callback API version. Passez d'abord mqtt.CallbackAPIVersion.VERSION2, puis l'ID sous la forme client_id=....

Faut-il modifier on_message lors de la migration ?

Non. on_message(client, userdata, message) conserve la même signature dans les deux versions. Les changements concernent les callbacks de connexion, de déconnexion, d'abonnement, de désabonnement et de publication.

Articles liés

Les meilleurs outils CLI MQTT pour tester, scripter et déboguer

Un comparatif pratique de mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, la CLI MQTT.js, curl et mqttui, avec le même test exécuté sur le serveur MQTT public gratuit broker.connectmq.com pour choisir le bon outil pour le scripting et le débogage.

9 min de lecture

Comment stocker des données MQTT dans InfluxDB avec Python

Construisez une passerelle Python avec paho-mqtt et influxdb-client qui s'abonne à un broker, transforme les niveaux de topic en tags InfluxDB, écrit les valeurs JSON numériques comme fields par lots et gère les payloads invalides et les conflits de type.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.