Le suivi de véhicules avec MQTT fonctionne bien parce que le protocole a été conçu exactement pour ce type de liaison : de petits appareils qui envoient fréquemment de petits messages sur des réseaux peu fiables et facturés au volume. Dans ce guide, vous allez concevoir une structure de topics pour une flotte, choisir des payloads GPS compacts, régler le keep alive et les sessions pour des traceurs cellulaires, détecter les véhicules hors ligne et construire une carte en direct dans le navigateur, mise à jour directement à partir d'abonnements MQTT sur ConnectMQ.
Pourquoi MQTT convient à la télématique de flotte
Un traceur cellulaire dans une camionnette passe sa vie à changer de cellule, à entrer dans des tunnels et à perdre la couverture dans les parkings. Chaque reconnexion coûte du temps, de l'énergie et des données. MQTT aide de plusieurs façons :
- Une seule connexion persistante au lieu d'une nouvelle requête HTTP par position : les en-têtes et les négociations ne sont payés qu'une fois.
- Un faible surcoût fixe par message, ce qui compte quand chaque kilo-octet est facturé.
- Le keep alive et le Last Will donnent au serveur un signal clair quand un véhicule devient silencieux.
- La QoS 1 avec des sessions persistantes permet aux commandes d'atteindre un véhicule qui a brièvement perdu la couverture.
- La diffusion par abonnements : la même position alimente la carte d'un répartiteur, un service de geofencing et un enregistreur d'historique, sans aucun effort supplémentaire du traceur.
Pour revoir les garanties de livraison, consultez les niveaux de QoS MQTT expliqués.
Conception des topics pour le suivi de véhicules
Commencez par une hiérarchie qui correspond à la façon dont les données sont interrogées : par flotte, puis par véhicule, puis par type de données.
fleet/{fleetId}/vehicle/{vehicleId}/position live GPS fixes
fleet/{fleetId}/vehicle/{vehicleId}/status online/offline (retained)
fleet/{fleetId}/vehicle/{vehicleId}/event ignition, harsh braking, door open
fleet/{fleetId}/vehicle/{vehicleId}/diag battery voltage, signal quality
fleet/{fleetId}/vehicle/{vehicleId}/cmd commands to the tracker
Cela permet à une carte de répartition de s'abonner à fleet/north/vehicle/+/position, à un service d'alerte de s'abonner à fleet/+/vehicle/+/event, et à un tableau de bord d'exploitation de s'abonner à fleet/+/vehicle/+/status. Gardez des identifiants courts et stables : un ID de véhicule comme v0142 plutôt qu'une plaque d'immatriculation complète avec des espaces. Évitez de mettre des données personnelles, comme le nom d'un conducteur, dans les noms de topics.
Conception des payloads
Les messages de position représentent l'essentiel de votre trafic : ils méritent qu'on s'y attarde.
| Champ | Clé | Exemple | Remarques |
|---|---|---|---|
| Horodatage | t |
1792137600 |
Secondes Unix issues de l'heure GNSS, pas l'heure de réception du serveur |
| Latitude | la |
41.01224 |
5 décimales correspondent à environ un mètre |
| Longitude | lo |
28.97601 |
Même précision |
| Vitesse | s |
48 |
km/h, entier |
| Cap | h |
270 |
Degrés, entier |
| Qualité du fix | q |
3 |
0 = aucun, 2 = 2D, 3 = 3D |
| Satellites | n |
9 |
Utile pour filtrer les mauvais fix |
Le payload obtenu pèse environ 90 octets :
{"t":1792137600,"la":41.01224,"lo":28.97601,"s":48,"h":270,"q":3,"n":9}
Règles pratiques :
- Incluez toujours l'horodatage de l'appareil. Les messages mis en mémoire tampon pendant une perte de couverture arrivent en retard ; la carte et l'historique doivent les trier selon l'heure du fix.
- Regroupez lors de la mise en tampon. Après un tunnel, publiez un seul message contenant un tableau des fix mis en tampon plutôt que des centaines de messages individuels.
- Adaptez la fréquence d'envoi. Toutes les 5 à 15 secondes en mouvement, toutes les quelques minutes à l'arrêt, et immédiatement lors des changements de cap importants.
- Écartez les mauvais fix sur l'appareil. Si la qualité du fix vaut 0, ne publiez pas de position.
Keep alive, sessions et QoS pour les liaisons cellulaires
- Keep alive : 60 à 120 secondes est un point de départ raisonnable en cellulaire. Des valeurs plus courtes détectent les coupures plus vite mais maintiennent le modem éveillé ; les délais d'expiration NAT des opérateurs peuvent aussi tuer silencieusement les connexions inactives, alors n'allez pas si loin que la correspondance NAT expire en premier.
- QoS : la QoS 0 est acceptable pour des positions à haute fréquence où le fix suivant remplace le précédent ; la QoS 1 pour les événements et les commandes qui ne doivent pas être perdus.
- Sessions persistantes : connectez-vous avec clean start à false et une expiration de session (MQTT 5), par exemple de 10 à 30 minutes, pour que les commandes envoyées pendant une courte coupure soient livrées à la reconnexion.
- Expiration des messages : définissez une expiration sur les commandes comme « déverrouiller les portes », afin qu'un véhicule qui revient une heure plus tard n'exécute pas une ancienne instruction.
- Last Will : enregistrez un will
offlineretained sur le topic de statut et publiez unonlineretained après la connexion.
Simuler un traceur en Python
Avant l'arrivée du matériel, simulez un véhicule. Ce script roule le long d'une trajectoire, utilise un Last Will et publie des positions avec paho-mqtt 2.x. Il cible le serveur MQTT public gratuit pour que vous puissiez l'exécuter tout de suite ; passez à vos propres identifiants et au port 8883 pour un usage réel.
import json
import math
import time
import uuid
import paho.mqtt.client as mqtt
HOST = "broker.connectmq.com"
PORT = 1883
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:6]}"
VEHICLE = "v0142"
BASE = f"{PREFIX}/fleet/north/vehicle/{VEHICLE}"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"sim-{VEHICLE}-{uuid.uuid4().hex[:6]}",
protocol=mqtt.MQTTv5)
client.will_set(f"{BASE}/status", "offline", qos=1, retain=True)
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code, "| topic prefix:", PREFIX)
client.publish(f"{BASE}/status", "online", qos=1, retain=True)
client.on_connect = on_connect
client.connect(HOST, PORT, keepalive=90)
client.loop_start()
lat, lon, heading = 41.0100, 28.9700, 45.0
try:
while True:
lat += 0.0003 * math.cos(math.radians(heading))
lon += 0.0003 * math.sin(math.radians(heading))
heading = (heading + 3) % 360
fix = {"t": int(time.time()), "la": round(lat, 5), "lo": round(lon, 5),
"s": 42, "h": int(heading), "q": 3, "n": 9}
client.publish(f"{BASE}/position", json.dumps(fix), qos=0)
time.sleep(5)
except KeyboardInterrupt:
client.publish(f"{BASE}/status", "offline", qos=1, retain=True).wait_for_publish()
client.loop_stop()
client.disconnect()
Notez le préfixe affiché ; vous en aurez besoin pour la carte. Le serveur public autorise 10 messages par seconde par client et 8 niveaux de topic : le topic complet connectmq/demo/xxxxxx/fleet/north/vehicle/v0142/position (8 niveaux) tient tout juste. Raccourcissez la hiérarchie si vous ajoutez des niveaux. N'oubliez pas que l'espace public est lisible par tout le monde : n'utilisez que des coordonnées simulées.
Une carte de flotte en direct à partir des abonnements
La carte n'est qu'un client MQTT dans le navigateur qui s'abonne aux positions et déplace des marqueurs. Cette page utilise MQTT.js sur Secure WebSocket et Leaflet.
// map.js - chargez Leaflet et MQTT.js dans votre page et ajoutez un conteneur avec l'id "map"
const PREFIX = "connectmq/demo/REPLACE_WITH_PREFIX";
const map = L.map("map").setView([41.01, 28.97], 13);
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "OpenStreetMap contributors",
}).addTo(map);
const markers = new Map();
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
clientId: "fleet-map-" + Math.random().toString(16).slice(2, 10),
protocolVersion: 5,
});
client.on("connect", () => {
client.subscribe(`${PREFIX}/fleet/+/vehicle/+/position`);
client.subscribe(`${PREFIX}/fleet/+/vehicle/+/status`);
});
client.on("message", (topic, payload) => {
const parts = topic.split("/");
const vehicleId = parts[parts.length - 2];
const kind = parts[parts.length - 1];
if (kind === "position") {
const fix = JSON.parse(payload.toString());
let m = markers.get(vehicleId);
if (!m) {
m = L.marker([fix.la, fix.lo]).addTo(map).bindTooltip(vehicleId);
markers.set(vehicleId, m);
}
m.setLatLng([fix.la, fix.lo]);
m.setTooltipContent(`${vehicleId} - ${fix.s} km/h`);
} else if (kind === "status") {
const m = markers.get(vehicleId);
if (m) m.setOpacity(payload.toString() === "online" ? 1 : 0.4);
}
});
En production, authentifiez la carte avec des identifiants émis par votre backend plutôt que d'embarquer un mot de passe partagé dans la page, et si de nombreux utilisateurs consultent la carte simultanément, envisagez un petit backend qui s'abonne une seule fois et sert les positions aux navigateurs.
Stocker l'historique et faire du geofencing
ConnectMQ est le broker, pas une base de données : l'historique et le geofencing tournent donc sous forme de vos propres clients MQTT. Un service Python ou Node.js abonné à fleet/+/vehicle/+/position peut écrire dans PostgreSQL avec PostGIS ou dans une base de séries temporelles, et un second service peut tester chaque fix par rapport à des polygones de geofence et publier sur le topic d'événements. Avec Serverless (Paid) ou supérieur, des shared subscriptions comme $share/geo/fleet/+/vehicle/+/position permettent à plusieurs instances de se répartir la charge. Les règles d'alerte à seuil du portail sont aussi pratiques pour des contrôles simples, comme une tension de batterie de diagnostic qui passe sous une limite.
Gérer les pertes de couverture sur l'appareil
Les traceurs passent beaucoup de temps hors couverture : le firmware doit prévoir ce cas. Conservez un buffer circulaire des fix récents en flash ou en RAM, dimensionné pour la plus longue coupure attendue, par exemple une heure de fix à fréquence réduite. Quand la connexion revient, publiez d'abord la position actuelle pour que la carte en direct se mette à jour immédiatement, puis videz le buffer par lots avec leurs horodatages d'origine. Les consommateurs qui écrivent l'historique doivent faire un upsert par véhicule et horodatage, pour qu'un lot livré deux fois en QoS 1 ne crée pas de points en double.
Checklist de mise en production
- Identifiants et client ID uniques par traceur, TLS sur 8883.
- Horodatage de l'appareil sur chaque fix ; regroupement après les coupures.
- Intervalle d'envoi adaptatif.
- Statut retained avec Last Will.
- Sessions persistantes et expiration des messages pour les commandes.
- Aucune donnée personnelle dans les noms de topics.
- Backoff de reconnexion avec jitter pour toute la flotte.
Le côté ESP32 d'un traceur est traité dans traceur GPS ESP32 avec MQTT, et MQTT pour les applications mobiles couvre les applications pour conducteurs ou répartiteurs. Pour les choix d'hébergement, consultez le guide du broker MQTT cloud.
Suivez votre flotte avec ConnectMQ
Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire, connectez-y vos traceurs ou le simulateur en TLS et regardez les positions arriver dans l'explorateur de topics en direct. ConnectMQ est un broker MQTT managé, avec des plans Serverless (Paid) et Dedicated à mesure que votre flotte grandit.
Questions fréquentes
À quelle fréquence un traceur de véhicule doit-il publier sa position via MQTT ?
Toutes les 5 à 15 secondes en mouvement et toutes les quelques minutes à l'arrêt est un point de départ courant. Ajustez selon votre cas d'usage et votre forfait de données.
Quelle QoS utiliser pour les positions GPS ?
La QoS 0 suffit souvent pour des positions fréquentes, car le fix suivant remplace le précédent. Utilisez la QoS 1 pour les événements et les commandes qui doivent arriver.
Comment savoir quand un véhicule passe hors ligne ?
Enregistrez un Last Will retained offline sur le topic de statut du véhicule et publiez un online retained après la connexion.
ConnectMQ peut-il stocker l'historique des positions ?
Non, le broker achemine les messages. Exécutez votre propre service abonné pour écrire les positions dans une base de données comme PostgreSQL avec PostGIS.



