Le choix d'un format de payload MQTT est l'une des premières décisions de conception de tout projet IoT, et l'une des plus difficiles à changer ensuite. MQTT traite le payload comme des octets opaques : JSON, Protobuf, CBOR ou une structure binaire maison fonctionnent tous sur le réseau. Cette comparaison montre en quoi les trois encodages les plus courants diffèrent en taille, en gestion des schémas et en outillage, avec le nombre d'octets d'un même message de capteur, pour que vous puissiez choisir celui qui convient à vos appareils.
MQTT est agnostique vis-à-vis du payload
Un paquet PUBLISH MQTT contient un topic, quelques flags, des propriétés MQTT 5 optionnelles et un payload pouvant atteindre 256 Mo selon la limite du protocole (les brokers imposent en pratique des limites bien plus basses). Le broker MQTT ne regarde jamais à l'intérieur du payload. Cela vous laisse une grande liberté, mais signifie aussi que rien n'empêche deux équipes de publier des formats incompatibles sur le même topic.
MQTT 5 ajoute deux propriétés utiles :
- Payload Format Indicator : 0 signifie des octets non spécifiés, 1 du texte UTF-8.
- Content Type : une chaîne libre, généralement un type MIME comme
application/jsonouapplication/x-protobuf.
Les définir ne coûte que quelques octets et permet aux outils génériques, journaux et consommateurs de traiter correctement vos messages.
Le message d'exemple
Pour une comparaison équitable, nous encodons la même mesure de pompe dans chaque format :
{"deviceId":"pump-07","ts":1760600000,"temp":21.5,"pressure":2.31,"rpm":1480,"running":true}
Six champs : un identifiant texte, un horodatage Unix, deux mesures décimales, un entier et un booléen. C'est une structure réaliste pour la télémétrie industrielle et du bâtiment.
Comparaison des tailles
Les nombres d'octets ci-dessous sont calculés à partir des règles d'encodage de chaque format pour ce message précis :
| Encodage | Octets | Remarques |
|---|---|---|
| JSON indenté (2 espaces) | 117 | Agréable à lire, gaspilleur sur le réseau |
| JSON compact | 92 | Le choix par défaut courant |
| JSON compact avec clés courtes | 65 | {"d":"pump-07","t":1760600000,"tp":21.5,"p":2.31,"r":1480,"on":1} |
| CBOR, flottants sur 64 bits | 74 | Mêmes clés que JSON, valeurs binaires |
| CBOR, flottants sur 32 bits | 64 | Compromis de précision sur pressure |
Protobuf, flottants en float |
30 | Numéros de champ au lieu des noms |
Quelques observations :
- L'essentiel de la taille du JSON tient aux noms de clés et aux nombres écrits en texte. Raccourcir les clés mène déjà loin, avant même de changer de format.
- CBOR conserve la structure de map autodescriptive : les noms de clés voyagent donc toujours avec chaque message. Ses économies viennent des nombres et booléens binaires.
- Protobuf est compact parce que les noms de champs résident dans un fichier de schéma, pas dans le message. Le destinataire doit disposer de ce schéma.
N'oubliez pas l'en-tête MQTT et le topic qui s'ajoutent au payload. Un topic comme site/plant1/line1/pump-07/telemetry fait 35 octets, soit plus que l'intégralité du payload Protobuf. Si la bande passante compte vraiment, examinez aussi la longueur des topics et les topic aliases de MQTT 5, pas seulement l'encodage. Pour une vision plus large de la consommation d'octets, consultez la consommation de bande passante MQTT.
JSON : le choix par défaut, pour de bonnes raisons
JSON l'emporte sur tout, sauf la taille :
- Lisible dans n'importe quel client MQTT, fichier de log ou terminal.
- Chaque langage et chaque plateforme dispose d'un parseur, y compris ArduinoJson sur microcontrôleurs.
- Node-RED, Telegraf, Home Assistant et la plupart des tableaux de bord l'acceptent sans configuration.
- L'ajout d'un champ casse rarement les anciens consommateurs.
Ses faiblesses : aucune validation de schéma, des types numériques ambigus (1 est-il un booléen, un entier ou un flottant ?) et un coût d'analyse sur les très petits microcontrôleurs. Pour la plupart des projets avec des appareils alimentés sur secteur et en Wi-Fi ou Ethernet, ces compromis sont acceptables.
Protobuf : le plus compact, avec un schéma
Protocol Buffers encode chaque champ sous la forme d'un numéro de champ suivi d'une valeur compacte. Le schéma de notre message :
syntax = "proto3";
message PumpReading {
string device_id = 1;
uint64 ts = 2;
float temp = 3;
float pressure = 4;
uint32 rpm = 5;
bool running = 6;
}
Points forts : les payloads les plus petits, un typage fort, du code généré dans de nombreux langages et des règles claires pour faire évoluer les schémas (ajouter des champs avec de nouveaux numéros, ne jamais réutiliser les anciens). Sparkplug B, très utilisé dans le MQTT industriel, repose sur Protobuf précisément pour ces raisons ; consultez MQTT Sparkplug B et l'Unified Namespace.
Points faibles : illisible sans le schéma, donc le débogage nécessite des outils de décodage ; les fichiers de schéma doivent être distribués et versionnés auprès de chaque producteur et consommateur ; et les intégrations génériques ne peuvent pas exploiter les données sans étape de décodage.
CBOR : du JSON binaire
CBOR (RFC 8949) conserve le modèle de données de JSON (maps, tableaux, chaînes et nombres) mais l'encode en binaire. Il ne nécessite aucun schéma : n'importe quel décodeur CBOR peut retransformer un message en structure de type JSON.
Points forts : plus compact que JSON, autodescriptif, chaînes d'octets binaires natives (pas de base64) et populaire dans les protocoles contraints comme CoAP. Points faibles : les économies restent modérées si vous ne raccourcissez pas aussi les clés, l'outillage est moins fourni que pour JSON, et l'encodage des flottants diffère selon les bibliothèques, ce qui peut surprendre quand on compare les octets.
Check-list de décision
- Des humains vont-ils lire souvent ces messages ? Préférez JSON.
- Les appareils sont-ils sur du cellulaire facturé au volume, un backhaul LoRa ou du satellite ? Envisagez Protobuf, ou du JSON compact à clés courtes comme première étape.
- De nombreuses équipes et de nombreux langages consomment-ils les mêmes données ? Les schémas de Protobuf sont alors rentables ; sinon, JSON avec un schéma documenté.
- Besoin de blobs binaires au sein de données structurées ? CBOR les gère nativement.
- Intégration avec des outils du marché ? JSON, ou prévoyez une étape de décodage qui republie en JSON.
- Interopérabilité industrielle ? Regardez Sparkplug B avant d'inventer votre propre schéma Protobuf.
Quel que soit votre choix, versionnez-le. Un champ schema dans le payload, une version dans le topic ou une user property MQTT 5 conviennent tous ; l'essentiel est que les consommateurs puissent distinguer les formats.
Publier avec un content type en Python
Cet exemple paho-mqtt 2.x publie la mesure en JSON compact avec le payload format indicator et le content type MQTT 5 définis, sur le serveur MQTT public gratuit :
import json
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
reading = {"deviceId": "pump-07", "ts": 1760600000, "temp": 21.5,
"pressure": 2.31, "rpm": 1480, "running": True}
payload = json.dumps(reading, separators=(",", ":")).encode()
print("payload bytes:", len(payload)) # 92
props = Properties(PacketTypes.PUBLISH)
props.PayloadFormatIndicator = 1
props.ContentType = "application/json"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"fmt-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5)
client.connect("broker.connectmq.com", 1883, keepalive=30)
client.loop_start()
client.publish("connectmq/demo/f6n1/pump-07/telemetry", payload,
qos=1, properties=props).wait_for_publish()
client.loop_stop()
client.disconnect()
Notez separators=(",", ":") : par défaut, json.dumps en Python ajoute une espace après chaque virgule et chaque deux-points, ce qui rendrait le payload plus volumineux que le chiffre compact du tableau.
Pièges liés au payload
- Mélanger les formats sur un même topic. Les consommateurs cassent de façon déroutante. Un topic, un format.
- Surprises des nombres flottants. Un flottant 32 bits ne peut pas représenter 2.31 exactement. Choisissez délibérément la précision ou envoyez des entiers mis à l'échelle.
- Horodatages en heure locale. Utilisez l'heure Unix UTC ou l'ISO 8601 avec décalage.
- Dépassement des limites de taille. Regrouper de nombreuses mesures dans un seul message peut atteindre la taille maximale de message du broker ; consultez la limite de taille des messages MQTT.
Les formats de payload sur ConnectMQ
ConnectMQ transporte n'importe quel format de payload, puisque les payloads MQTT sont des octets opaques. En plus, ConnectMQ peut décoder les payloads Sparkplug B (Protobuf ou JSON) et les republier dans des topics ISA-95 lisibles. Les limites de message sont de 256 Ko sur le plan Serverless gratuit et de 1 Mo sur le plan Serverless payant, ce qui est largement suffisant pour chacun des encodages de mesure unique ci-dessus. Si vous préférez ne pas exploiter l'infrastructure, un broker MQTT managé vous permet de vous concentrer sur le contrat de payload. Le tutoriel MQTT couvre le reste du protocole.
Démarrer avec ConnectMQ
Créez un broker gratuit sur app.connectmq.com avec le plan Serverless, sans carte bancaire. Publiez la même mesure en JSON et dans le format binaire de votre choix, et comparez-les côte à côte dans le client intégré au navigateur du portail ConnectMQ.
Questions fréquentes
Quel est le meilleur format de payload MQTT ?
Il n'y en a pas un seul. JSON est le choix par défaut le plus sûr pour l'interopérabilité et le débogage ; Protobuf est le meilleur lorsque la bande passante est limitée et que les schémas sont bien gérés.
Le broker valide-t-il le format du payload ?
Non. Les brokers MQTT traitent les payloads comme des octets opaques. La validation se fait dans vos consommateurs.
Faut-il compresser les payloads JSON ?
Pour de petites mesures uniques, la compression fait souvent gagner peu et coûte du CPU. Elle est plus utile pour les gros messages regroupés.
Comment indiquer aux consommateurs le format d'un message ?
En MQTT 5, définissez la propriété Content Type. En MQTT 3.1.1, utilisez une convention de topic ou un champ de version dans le payload.



