MQTT sur réseau cellulaire est la façon dont la plupart des équipements isolés (stations de pompage, cuves, centrales solaires, véhicules, stations de mesure environnementale) rejoignent le cloud, mais les règles de conception diffèrent de celles du Wi-Fi ou de l'Ethernet. Les octets sont facturés, les liaisons décrochent plus souvent et les réseaux des opérateurs ferment silencieusement les connexions inactives. Ce guide vous montre comment estimer un budget data, choisir les valeurs de keep alive, réduire le surcoût TLS et choisir entre LTE-M et NB-IoT pour que vos appareils restent connectés sans factures surprises.
Pourquoi le cellulaire change la conception MQTT
MQTT a été conçu à l'origine pour des liaisons peu fiables et à faible débit : il est donc déjà bien adapté, avec un en-tête fixe de 2 octets, des connexions TCP persistantes et un modèle publish-subscribe qui évite l'interrogation. Mais trois réalités du cellulaire façonnent les détails :
- Chaque octet est facturé, y compris les en-têtes TCP/IP, les enregistrements TLS, les acquittements et les pings de keep alive, pas seulement votre payload.
- Le NAT d'opérateur (carrier-grade NAT) se trouve entre la plupart des appareils et internet et supprime les correspondances TCP inactives après un délai propre à chaque opérateur. Si MQTT reste silencieux plus longtemps, la connexion meurt sans qu'aucune des deux extrémités ne s'en aperçoive immédiatement.
- L'état radio coûte de l'énergie. Chaque transmission réveille le modem, qui reste ensuite un moment dans un état de forte consommation. De nombreux petits envois vident les batteries plus vite que quelques envois regroupés.
LTE-M vs NB-IoT pour MQTT
| LTE-M (Cat-M1) | NB-IoT (Cat-NB1/NB2) | |
|---|---|---|
| Débit | Plus élevé, confortable pour MQTT sur TLS | Très faible ; les négociations volumineuses prennent longtemps |
| Latence | Comparable à la LTE classique, assez basse pour des commandes interactives | Élevée et variable, parfois plusieurs secondes |
| Mobilité | Prend en charge le transfert entre cellules | Conçu pour des appareils fixes |
| Adéquation TCP/TLS | Bonne | Possible, mais souvent associé à des protocoles basés sur UDP |
| Économie d'énergie | PSM et eDRX pris en charge | PSM et eDRX pris en charge, très faible consommation au repos |
| Couverture | Bonne, améliorée par rapport à la LTE classique | Excellente en intérieur profond et en souterrain |
Pour MQTT sur TCP et TLS, LTE-M est généralement le choix pragmatique : les négociations TLS aboutissent de façon fiable et les commandes atteignent rapidement l'appareil. NB-IoT excelle pour les appareils fixes qui envoient de petits rapports peu fréquents depuis des endroits difficiles d'accès ; dans ce cas, de nombreuses équipes utilisent MQTT-SN ou un autre protocole basé sur UDP, ou acceptent un établissement de connexion lent avec MQTT sur TCP. Vérifiez les technologies prises en charge par votre opérateur dans votre région de déploiement avant de choisir le matériel ; certains modems gèrent les deux et basculent automatiquement.
Estimer un budget data pour MQTT sur réseau cellulaire
La taille du payload est souvent la plus petite partie de la facture. Prenez en compte :
- Les en-têtes TCP/IP de chaque paquet (environ 40 octets en IPv4 sans options, davantage avec options ou en IPv6), plus les acquittements TCP.
- Le surcoût des enregistrements TLS par message, quelques dizaines d'octets pour l'en-tête, le nonce et l'étiquette d'authentification.
- Le surcoût MQTT : en-tête fixe, nom du topic (souvent la plus grande partie d'un petit message) et un PUBACK en QoS 1.
- Les pings de keep alive : un PINGREQ et un PINGRESP ne font que 2 octets chacun, mais avec TLS, les en-têtes TCP/IP et les ACK, chaque aller-retour coûte bien plus sur le réseau.
- L'établissement de la connexion : une négociation TLS complète, chaîne de certificats du serveur comprise, pèse généralement plusieurs kilo-octets. Des reconnexions fréquentes peuvent dominer le budget.
Le script ci-dessous donne une estimation approximative. Les chiffres par paquet sont des hypothèses volontairement prudentes ; remplacez-les par des valeurs mesurées sur votre modem (la plupart des modems indiquent les octets envoyés et reçus).
# Estimation approximative de la consommation mensuelle d'un appareil cellulaire MQTT sur TLS.
# Les surcoûts sont des hypothèses - mesurez votre propre liaison et ajustez.
PAYLOAD_BYTES = 60 # par ex. JSON compact
TOPIC_BYTES = 40 # longueur de la chaîne du topic
MSGS_PER_HOUR = 12 # une mesure toutes les 5 minutes
QOS = 1 # le QoS 1 ajoute un PUBACK
KEEPALIVE_S = 240 # les pings ne comptent que lorsque la liaison est inactive
RECONNECTS_PER_DAY = 2 # chacune paie une négociation TLS complète
TLS_HANDSHAKE_BYTES = 6000 # hypothèse : la chaîne de certificats domine
TCP_IP_PER_PACKET = 52 # IPv4 + TCP avec l'option timestamps
TLS_PER_RECORD = 29 # surcoût d'un enregistrement TLS 1.2 AES-GCM
TCP_ACK = 52 # paquet ACK pur
def bytes_per_publish():
mqtt = 2 + 2 + TOPIC_BYTES + (2 if QOS > 0 else 0) + PAYLOAD_BYTES
out = mqtt + TLS_PER_RECORD + TCP_IP_PER_PACKET
back = TCP_ACK
if QOS > 0:
back = 4 + TLS_PER_RECORD + TCP_IP_PER_PACKET + TCP_ACK # PUBACK + notre ACK
return out + back
def bytes_per_ping():
one_way = 2 + TLS_PER_RECORD + TCP_IP_PER_PACKET
return 2 * one_way + 2 * TCP_ACK
msgs = MSGS_PER_HOUR * 24 * 30
gap = 3600 / MSGS_PER_HOUR
pings_per_gap = int(gap // KEEPALIVE_S) # pings nécessaires entre deux messages
pings = pings_per_gap * msgs
total = (msgs * bytes_per_publish()
+ pings * bytes_per_ping()
+ RECONNECTS_PER_DAY * 30 * TLS_HANDSHAKE_BYTES)
print(f"messages/month: {msgs}")
print(f"payload only: {msgs * PAYLOAD_BYTES / 1e6:.2f} MB")
print(f"estimated total: {total / 1e6:.2f} MB")
Son exécution montre ce que vous constaterez sur le terrain : le total réellement transmis représente plusieurs fois le payload brut, et la longueur des topics, les acquittements et les reconnexions pèsent autant que les données elles-mêmes. C'est pourquoi les optimisations ci-dessous se concentrent sur le surcoût.
Keep alive vs timeouts NAT des opérateurs
L'intervalle de keep alive MQTT indique au broker combien de temps le client peut rester silencieux. Si rien d'autre n'est envoyé, le client émet un PINGREQ avant l'expiration de l'intervalle. En cellulaire, le keep alive a une seconde mission : maintenir la correspondance NAT de l'opérateur.
- Si le keep alive est plus long que le timeout d'inactivité NAT, la correspondance est supprimée silencieusement. L'appareil se croit toujours connecté ; la publication suivante disparaît, et la connexion n'est détectée comme morte qu'après un timeout TCP. Entre-temps, les commandes envoyées depuis le cloud n'arrivent jamais.
- Si le keep alive est bien plus court que nécessaire, vous payez des pings inutiles et gardez la radio éveillée.
Les timeouts NAT varient selon les opérateurs et peuvent ne durer que quelques minutes. Mesurez le vôtre : connectez-vous avec un keep alive long, espacez progressivement les publications et notez le moment où les messages venant du cloud cessent d'arriver. Réglez ensuite le keep alive nettement en dessous de cette valeur. Si l'appareil se contente d'envoyer des données et n'a pas besoin de recevoir de commandes, une alternative consiste à se connecter, publier puis se déconnecter, en acceptant le coût de la négociation à chaque fois, ce qui peut revenir moins cher quand les rapports sont espacés de plusieurs heures.
Réduire le coût de TLS sans renoncer à TLS
N'envoyez jamais de MQTT en clair sur un réseau cellulaire public. Rendez plutôt TLS moins coûteux :
- Gardez les connexions ouvertes lorsque les rapports sont fréquents, afin que la négociation soit rare.
- Utilisez la reprise de session TLS si votre modem ou votre bibliothèque TLS prend en charge les identifiants ou tickets de session. Une négociation reprise saute l'échange de certificats et économise à la fois des octets et du temps.
- Préférez ECDHE avec ECDSA lorsque les deux côtés le prennent en charge ; les clés et signatures à courbes elliptiques sont plus petites que leurs équivalents RSA.
- Ne faites confiance qu'au certificat racine nécessaire (par exemple ISRG Root X1 pour les certificats Let's Encrypt), afin que l'appareil stocke et valide une chaîne minimale.
- Évitez les tempêtes de reconnexion. Utilisez un backoff exponentiel avec jitter, pour qu'une panne de cellule ne déclenche pas des centaines de négociations à la suite.
Alléger chaque message
- Topics courts. Un topic comme
t/pump7/pcoûte bien moins cher qu'une longue hiérarchie descriptive à chaque publication. Avec MQTT 5, les topic aliases permettent au client d'envoyer le topic complet une seule fois puis d'y faire référence par un petit entier : vous gardez des topics lisibles sans payer le coût à chaque message. - Payloads compacts. Clés JSON courtes, entiers avec facteur d'échelle implicite, ou format binaire comme Protobuf (utilisé par Sparkplug B).
- Regroupement des mesures. Envoyez dix mesures dans un message toutes les dix minutes au lieu d'une par minute ; les en-têtes ne sont payés qu'une fois.
- Report by exception. N'envoyez que les changements significatifs plus un heartbeat ; voir report by exception.
- Choix du QoS. Le QoS 1 ajoute un PUBACK par message. Utilisez-le là où la livraison compte, et le QoS 0 pour les valeurs à haute fréquence où la mesure suivante remplace la précédente.
Paramètres de session MQTT 5 pour les liaisons intermittentes
Une session persistante permet au broker de conserver les abonnements et de mettre en file les messages QoS 1 destinés à l'appareil pendant une brève déconnexion, si bien que les commandes envoyées pendant une coupure ne sont pas perdues. Avec paho-mqtt 2.x :
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="YOUR_CLIENT_ID", protocol=mqtt.MQTTv5)
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set() # magasin de certificats du système
client.reconnect_delay_set(min_delay=2, max_delay=300)
props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 3600 # conserver la session 1 h après une coupure
client.connect("YOUR_BROKER_HOST", 8883, keepalive=240,
clean_start=False, properties=props)
client.loop_forever()
Associez cela à une mise en tampon locale des données sortantes, car une session ne protège que les messages reçus par le broker. Le guide store-and-forward MQTT présente une file sur disque conçue exactement pour cela.
Check-list de conception cellulaire
- Choisissez LTE-M pour MQTT sur TCP/TLS et les commandes interactives ; envisagez NB-IoT pour les appareils fixes qui rapportent rarement.
- Mesurez le timeout d'inactivité NAT de l'opérateur et réglez le keep alive en dessous.
- Gardez TLS, mais réduisez au minimum les négociations et utilisez la reprise de session lorsqu'elle est disponible.
- Raccourcissez les topics ou utilisez les topic aliases de MQTT 5 ; compactez et regroupez les payloads.
- Appliquez le report by exception en périphérie.
- Mettez en tampon les données sortantes sur l'appareil pendant les coupures.
- Utilisez un backoff exponentiel avec jitter pour les reconnexions.
- Surveillez les octets par appareil et par jour pour que les anomalies apparaissent avant la facture.
Pour un exemple pratique avec un modem, consultez SIM7600 MQTT. Pour l'architecture au niveau passerelle, lisez l'article sur la passerelle edge IIoT et le guide de l'IoT industriel avec MQTT.
Tester avant de payer les données
Validez d'abord la structure des topics et le format des payloads en Wi-Fi ou en Ethernet, sur le serveur MQTT public gratuit, réservé aux tests, avec un préfixe unique comme connectmq/demo/cell-4f8a/.... Passez ensuite l'appareil en cellulaire avec des identifiants de production sur un broker MQTT managé comme ConnectMQ, qui fournit des points de connexion TLS et les fonctionnalités de MQTT 5 sans que vous ayez à exploiter de serveurs. Vous comparez les options d'hébergement ? Le guide du broker MQTT cloud indique les points à examiner.
Connectez votre flotte cellulaire à ConnectMQ
ConnectMQ prend en charge MQTT 3.1.1 et 5.0 sur TLS sur le port 8883, avec expiration de session, topic aliases et expiration des messages pour les liaisons intermittentes. Son topic $SYS/broker/connection/{clientId}/state et les vues des appareils du portail vous aident à voir quels appareils distants sont en ligne. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire.
Questions fréquentes
Quelle quantité de données MQTT consomme-t-il en cellulaire ?
Cela dépend bien plus du surcoût que du payload : en-têtes TCP/IP et TLS, acquittements, pings de keep alive et négociations de reconnexion. Faites une estimation avec un modèle comme le script ci-dessus, puis vérifiez avec les compteurs d'octets de votre modem.
Quel keep alive utiliser en LTE-M ?
Une valeur inférieure au timeout d'inactivité NAT de votre opérateur, que vous devez mesurer. Quelques minutes constituent un point de départ courant ; ajustez après les tests.
NB-IoT convient-il à MQTT ?
Il peut fonctionner pour de petits messages peu fréquents envoyés par des appareils fixes, mais sa latence élevée et son faible débit ralentissent les négociations TCP et TLS. LTE-M est le choix le plus simple pour du MQTT standard sur TLS.
Les appareils cellulaires doivent-ils se déconnecter entre deux rapports ?
Si les rapports sont espacés de plusieurs heures et qu'aucune commande ne doit atteindre l'appareil, le cycle connexion-publication-déconnexion peut revenir moins cher. Pour des rapports fréquents ou un pilotage à distance, gardez la connexion ouverte avec un keep alive ajusté.



