IoT industriel

MTConnect vers MQTT : diffuser les données des machines CNC vers les tableaux de bord

Les agents MTConnect exposent les données CNC en HTTP et XML. Construisez un pont qui suit les numéros de séquence de l'agent, sélectionne les data items utiles et publie l'état des machines en MQTT pour les tableaux de bord et l'analytique.

Machines CNC alimentant un agent MTConnect dont le flux XML est converti par un pont MTConnect vers MQTT en topics de tableau de bord en temps réel
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

MTConnect vers MQTT est le chemin le plus court entre les données standardisées d'une machine CNC et des tableaux de bord en temps réel, des alertes et des rapports d'utilisation. Dans ce tutoriel, vous verrez comment un agent MTConnect expose les données, puis vous construirez un pont Python qui suit les numéros de séquence de l'agent sans manquer d'observations, associe des data items comme l'état d'exécution, la vitesse de broche et le compteur de pièces à des topics lisibles, et les publie en MQTT. Le même pont fonctionne pour une machine ou pour une cellule entière.

Comment MTConnect expose les données machines

MTConnect est un standard ouvert pour les équipements de production, en particulier les machines-outils. Il définit un vocabulaire (ce que signifient « Execution », « SpindleSpeed » ou « PartCount ») et une interface HTTP en lecture seule servie par un agent. Les machines communiquent avec l'agent via un adaptateur, souvent fourni par le fabricant de la commande numérique ou intégré à celle-ci, et les clients lisent les données depuis l'agent.

L'agent propose trois requêtes principales :

Requête Renvoie À utiliser pour
/probe Le modèle de l'appareil : composants et data items avec ID, types, unités Construire une fois au démarrage le catalogue des data items
/current La dernière valeur de chaque data item, plus les informations de séquence de l'en-tête L'état initial, et la resynchronisation après erreur
/sample?from=N&count=M Toutes les observations à partir de la séquence N, jusqu'à M éléments Suivre les changements sans en manquer aucun

Chaque observation porte un numéro sequence attribué par l'agent, un timestamp et un dataItemId. L'en-tête de la réponse contient firstSequence, lastSequence, nextSequence et un instanceId. Ces quatre valeurs sont la clé d'un pont fiable : vous partez de /current, mémorisez nextSequence et demandez les échantillons à partir de là.

Les observations MTConnect se répartissent en trois catégories, qui correspondent bien à la manière de les traiter en MQTT :

  • Samples : des mesures numériques comme la vitesse de broche, la charge ou la position.
  • Events : des états ou valeurs discrets comme l'état d'exécution, le mode de la commande, le nom du programme ou le compteur de pièces.
  • Conditions : l'état de santé, Normal, Warning, Fault ou Unavailable, souvent avec un code d'alarme natif.

Un data item dont la valeur est inconnue renvoie UNAVAILABLE. Votre pont doit le transmettre tel quel, sans le masquer, car « la machine est éteinte ou déconnectée » est une information importante.

Pourquoi relier MTConnect à MQTT

MTConnect fonctionne en mode pull et repose lourdement sur XML. Cela convient pour un tableau de bord, mais chaque nouveau consommateur interroge l'agent séparément et doit analyser du XML. Le pont vers MQTT vous apporte la livraison en push, un format JSON unique et facile à consommer, un état actuel retenu pour les consommateurs qui arrivent en cours de route, et la possibilité de combiner les données machines avec celles des automates, de l'énergie et de la qualité dans une même hiérarchie de topics. Si vous construisez un Unified Namespace, les machines MTConnect deviennent une source de plus qui l'alimente ; notre guide sur les topics MQTT ISA-95 montre comment les y placer.

Les versions récentes de l'agent de référence MTConnect peuvent aussi publier directement vers un broker MQTT grâce à un sink MQTT intégré. Si votre version d'agent le prend en charge, cela vaut la peine de l'évaluer ; les clés de configuration varient selon les versions, suivez donc la documentation de l'agent. Le pont de ce tutoriel fonctionne avec toutes les versions d'agent et vous laisse un contrôle total sur les noms de topics et la forme des payloads.

Prérequis

  • Python 3.10 ou plus récent avec requests et paho-mqtt 2.x.
  • L'URL d'un agent MTConnect, par exemple http://192.168.10.50:5000. Si aucune machine n'est connectée, le projet de l'agent de référence inclut des configurations d'exemple et un simulateur exécutable en local.
  • Un broker. Pour les tests, utilisez le serveur MQTT public gratuit avec un préfixe de topic unique.
pip install requests "paho-mqtt>=2.0"
curl -s http://localhost:5000/probe | head -40     # vérifier que l'agent répond et lister les data items

Étape 1 : choisir les data items

Une CNC moderne peut exposer des centaines de data items. Publiez ce dont les consommateurs ont besoin, pas tout. Un ensemble de départ pratique pour les tableaux de bord d'utilisation et d'état :

Type MTConnect Catégorie Exemples de valeurs Pourquoi c'est important
AVAILABILITY Event AVAILABLE, UNAVAILABLE La machine est-elle seulement connectée
EXECUTION Event ACTIVE, READY, INTERRUPTED, FEED_HOLD, STOPPED Le cœur du suivi d'utilisation
CONTROLLER_MODE Event AUTOMATIC, MANUAL, MANUAL_DATA_INPUT Distingue la production du réglage
PROGRAM Event O1234 Quel travail est en cours
PART_COUNT Event 1843 La production
ROTARY_VELOCITY (broche) Sample 12000 L'activité d'usinage
PATH_FEEDRATE_OVERRIDE Event ou Sample 100 Les interventions de l'opérateur
Conditions système et logiques Condition Normal, Warning, Fault Les alarmes

Exécutez /probe sur votre agent et notez l'id de chaque data item souhaité. Les ID sont choisis par la personne qui a configuré l'agent, ils diffèrent donc d'une installation à l'autre.

Étape 2 : le pont MTConnect vers MQTT

Le pont associe les ID de data items à des noms de topics, lit /current pour l'état initial, puis boucle sur /sample. Il détecte les redémarrages de l'agent (un nouvel instanceId) et les débordements de tampon (un from plus ancien que firstSequence) et se resynchronise dans les deux cas.

# mtconnect_mqtt_bridge.py - suit un agent MTConnect et publie les observations en MQTT
import json, logging, time, uuid
import xml.etree.ElementTree as ET
import paho.mqtt.client as mqtt
import requests

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("mtc")

AGENT = "http://localhost:5000"
TOPIC_ROOT = "connectmq/demo/f40b/shop1/cnc"        # votre propre id aléatoire
INTERVAL = 1.0                                       # secondes entre deux requêtes /sample
MQTT_HOST, MQTT_PORT = "broker.connectmq.com", 1883  # production: 8883 with TLS
MQTT_USER, MQTT_PASS = None, None                    # production: "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = f"mtc-bridge-{uuid.uuid4().hex[:8]}"     # production: "YOUR_CLIENT_ID"

# dataItemId -> feuille du topic. Prenez les ID dans la sortie /probe de votre agent.
WATCH = {
    "avail": "availability",
    "exec": "execution",
    "mode": "controller_mode",
    "program": "program",
    "pc": "part_count",
    "Sspeed": "spindle_speed",
    "logic_cond": "logic_condition",
}

CONDITION_TAGS = {"Normal", "Warning", "Fault", "Unavailable"}


def local(tag):
    """Retire le namespace XML MTConnect versionné d'un nom de balise."""
    return tag.rsplit("}", 1)[-1]


def fetch(path):
    r = requests.get(f"{AGENT}{path}", timeout=10)
    r.raise_for_status()
    return ET.fromstring(r.content)


def parse(root):
    header = next(e for e in root.iter() if local(e.tag) == "Header")
    observations = []
    for stream in root.iter():
        if local(stream.tag) != "DeviceStream":
            continue
        device = stream.get("name")
        for el in stream.iter():
            item_id = el.get("dataItemId")
            if item_id is None:
                continue
            tag = local(el.tag)
            if tag in CONDITION_TAGS:
                value = {"level": tag, "native_code": el.get("nativeCode"), "text": (el.text or "").strip()}
            else:
                value = (el.text or "").strip()
            observations.append({
                "device": device, "id": item_id, "value": value,
                "ts": el.get("timestamp"), "seq": int(el.get("sequence", 0)),
            })
    observations.sort(key=lambda o: o["seq"])
    return header, observations


def coerce(value):
    if isinstance(value, dict) or value == "UNAVAILABLE":
        return value
    try:
        return float(value) if "." in value else int(value)
    except ValueError:
        return value


def publish(mq, obs):
    leaf = WATCH.get(obs["id"])
    if not leaf:
        return
    topic = f"{TOPIC_ROOT}/{obs['device']}/{leaf}"
    payload = {"value": coerce(obs["value"]), "ts": obs["ts"], "seq": obs["seq"]}
    mq.publish(topic, json.dumps(payload), qos=1, retain=True)
    log.info("%s = %s", topic, payload["value"])


def main():
    mq = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
    if MQTT_USER:
        mq.username_pw_set(MQTT_USER, MQTT_PASS)
        mq.tls_set()
    mq.will_set(f"{TOPIC_ROOT}/bridge", "offline", qos=1, retain=True)
    mq.on_connect = lambda c, u, f, rc, p: c.publish(f"{TOPIC_ROOT}/bridge", "online", qos=1, retain=True)
    mq.connect(MQTT_HOST, MQTT_PORT, keepalive=30)
    mq.loop_start()

    instance, next_seq = None, None
    while True:
        try:
            if next_seq is None:                       # (re)synchronisation depuis /current
                header, obs = parse(fetch("/current"))
                instance, next_seq = header.get("instanceId"), int(header.get("nextSequence"))
                for o in obs:
                    publish(mq, o)
                log.info("synchronised: instance %s, next %s", instance, next_seq)
            else:
                header, obs = parse(fetch(f"/sample?from={next_seq}&count=1000"))
                if header.get("instanceId") != instance:
                    log.warning("agent restarted, resynchronising")
                    next_seq = None
                    continue
                for o in obs:
                    publish(mq, o)
                next_seq = int(header.get("nextSequence"))
        except (ET.ParseError, StopIteration, TypeError) as exc:
            # XML invalide, ou document MTConnectError sans Header normal.
            log.error("unexpected agent response: %s", exc)
            next_seq = None
        except requests.RequestException as exc:
            # Erreurs réseau, ou statut d'erreur comme un "from" hors plage.
            log.error("agent request failed: %s", exc)
            next_seq = None
            time.sleep(5)
        time.sleep(INTERVAL)


if __name__ == "__main__":
    main()

Quelques remarques sur la conception :

  • Le tri par séquence garantit que les observations sont publiées dans l'ordre où l'agent les a enregistrées, même lorsque le XML les regroupe par composant.
  • Les retained messages permettent à un tableau de bord ouvert en cours de poste d'afficher instantanément l'état d'exécution, le programme et le compteur de pièces actuels.
  • Les conditions deviennent des objets avec un niveau et un code d'alarme natif, pour que les consommateurs distinguent un avertissement d'un défaut.
  • La resynchronisation en cas d'erreur est sans risque : /current republie le dernier état, de sorte que les consommateurs finissent avec des données correctes même si quelques échantillons intermédiaires ont été perdus.

Étape 3 : exécuter et observer

python mtconnect_mqtt_bridge.py
mosquitto_sub -h broker.connectmq.com -p 1883 -i mtc-viewer-f40b -t "connectmq/demo/f40b/#" -v
connectmq/demo/f40b/shop1/cnc/VMC-3Axis/execution {"value": "ACTIVE", "ts": "2026-10-16T11:02:44.501Z", "seq": 90213}
connectmq/demo/f40b/shop1/cnc/VMC-3Axis/spindle_speed {"value": 11980.0, "ts": "2026-10-16T11:02:44.612Z", "seq": 90215}

Le serveur public autorise dix messages par seconde et par client, ce qui suffit largement pour les événements d'état mais peut être dépassé par des échantillons qui changent vite, comme les positions d'axes. Gardez WATCH ciblé, ou ajoutez une bande morte pour les échantillons, comme expliqué dans notre article sur le report by exception.

Construire un tableau de bord d'état des machines

Avec l'exécution, le mode et la disponibilité en MQTT, une vue d'utilisation de base se résume à s'abonner et à chronométrer les changements d'état. Une correspondance simplifiée courante :

  1. En production : disponibilité AVAILABLE, mode AUTOMATIC, exécution ACTIVE.
  2. En attente : disponible, exécution READY ou STOPPED.
  3. Interrompue : exécution INTERRUPTED, FEED_HOLD ou OPTIONAL_STOP, souvent une attente opérateur.
  4. En alarme : toute condition au niveau Fault.
  5. Hors ligne : disponibilité UNAVAILABLE ou topic de statut du pont à offline.

N'importe quel outil de tableau de bord compatible MQTT peut calculer ces états, et un historian abonné aux mêmes topics vous fournit des rapports par poste et par travail. Notre guide de l'historian MQTT traite du stockage du flux.

Notes pour la production

  • Placement réseau. Exécutez le pont sur le réseau de l'atelier, à côté de l'agent, et laissez-le se connecter en sortie vers le broker sur le port 8883. N'exposez pas le port HTTP de l'agent sur Internet.
  • Plusieurs machines. Un même agent sert souvent plusieurs appareils ; le pont gère déjà plusieurs éléments DeviceStream et place chaque appareil dans sa propre branche.
  • Qualité de l'horloge. Les horodatages MTConnect proviennent de l'agent ou de l'adaptateur. Assurez-vous que ces hôtes utilisent NTP, sinon les calculs de durée dériveront.
  • Broker privé. Le serveur MQTT public gratuit est visible par tous ; les vraies données machines ont donc leur place sur un broker MQTT managé privé. Sur ConnectMQ, la vue des appareils regroupe vos machines par niveau ISA-95 et la démo de jumeau numérique 3D montre le type de visualisation CNC en temps réel que vous pouvez construire sur WebSocket sécurisé.

Pour une vue complète de la manière dont données machines, automates et passerelles s'articulent, lisez le guide de l'IoT industriel avec MQTT.

Démarrer avec ConnectMQ

Placez vos données CNC sur un broker privé en quelques minutes. Inscrivez-vous sur app.connectmq.com, choisissez l'offre Serverless gratuite (sans carte bancaire), créez un broker et collez le nom d'utilisateur, le mot de passe et le client ID générés dans le pont. Définissez ensuite une règle d'alerte à seuil dans le portail ConnectMQ, par exemple sur la vitesse de broche, et suivez le journal des alertes pendant que la machine tourne.

Questions fréquentes

MTConnect prend-il en charge MQTT nativement ?

Le standard MTConnect est construit autour d'une interface HTTP, mais les versions récentes de l'agent de référence incluent un sink MQTT qui publie les observations vers un broker. Un petit pont comme celui ci-dessus fonctionne avec toutes les versions d'agent.

Pourquoi utiliser /sample plutôt qu'interroger /current ?

Interroger /current ne montre que la dernière valeur et peut manquer des états brefs entre deux interrogations. Suivre /sample depuis nextSequence renvoie chaque observation dans l'ordre, de sorte que les alarmes ou arrêts brefs ne sont pas perdus.

Que signifie UNAVAILABLE dans MTConnect ?

Cela signifie que l'agent ne connaît pas actuellement la valeur, généralement parce que la machine ou l'adaptateur est déconnecté. Publiez-le tel quel pour que les tableaux de bord puissent afficher la machine comme hors ligne.

Peut-on écrire vers une CNC via MTConnect ?

Non. MTConnect est un standard en lecture seule destiné à la supervision. Les commandes envoyées à la machine nécessitent les interfaces propres au fabricant de la commande numérique.

Articles liés

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.