IoT industrial

MTConnect para MQTT: Enviando Dados de Máquinas CNC para Dashboards

Os agents MTConnect expõem dados de CNC via HTTP e XML. Construa uma ponte que segue os números de sequência do agent, escolhe os data items que importam e publica o estado das máquinas via MQTT para dashboards e analytics.

Máquinas CNC alimentando um agent MTConnect cujo fluxo XML é convertido por uma ponte MTConnect para MQTT em topics de dashboard ao vivo
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

MTConnect para MQTT é o caminho mais curto entre os dados padronizados de uma máquina CNC e dashboards ao vivo, alertas e relatórios de utilização. Neste tutorial você vai entender como um agent MTConnect expõe os dados e depois construir uma ponte em Python que segue os números de sequência do agent sem perder observações, mapeia data items como estado de execução, rotação do spindle e contagem de peças para topics legíveis e os publica via MQTT. A mesma ponte funciona para uma máquina ou para uma célula inteira, como a célula de usinagem de uma fábrica de autopeças em Joinville.

Como o MTConnect expõe os dados das máquinas

O MTConnect é um padrão aberto para equipamentos de manufatura, especialmente máquinas-ferramenta. Ele define um vocabulário (o que significam "Execution", "SpindleSpeed" ou "PartCount") e uma interface HTTP somente leitura servida por um agent. As máquinas falam com o agent por meio de um adapter, muitas vezes fornecido pelo fabricante do comando ou embutido nele, e os clients leem do agent.

O agent oferece três requisições principais:

Requisição Retorna Use para
/probe O modelo do dispositivo: componentes e data items com IDs, tipos, unidades Montar um catálogo de data items uma vez na inicialização
/current O valor mais recente de cada data item, mais informações de sequência no cabeçalho Estado inicial e ressincronização após erros
/sample?from=N&count=M Todas as observações a partir da sequência N, até M itens Acompanhar as mudanças sem perder nenhuma

Cada observação traz um número de sequence atribuído pelo agent, um timestamp e um dataItemId. O cabeçalho da resposta contém firstSequence, lastSequence, nextSequence e um instanceId. Esses quatro valores são a chave de uma ponte confiável: você começa pelo /current, guarda o nextSequence e pede amostras a partir dali.

As observações MTConnect se dividem em três categorias, que se mapeiam bem para a forma como você deve tratá-las no MQTT:

  • Samples são medições numéricas, como rotação do spindle, carga ou posição.
  • Events são estados ou valores discretos, como estado de execução, modo do comando, nome do programa ou contagem de peças.
  • Conditions descrevem a saúde: Normal, Warning, Fault ou Unavailable, muitas vezes com um código de alarme nativo.

Um data item cujo valor não é conhecido reporta UNAVAILABLE. Sua ponte deve repassar isso, e não esconder, porque "a máquina está desligada ou desconectada" é uma informação importante.

Por que fazer a ponte entre MTConnect e MQTT

O MTConnect é baseado em pull e pesado em XML. Isso serve para um dashboard, mas cada novo consumidor faz polling do agent separadamente e precisa interpretar XML. A ponte para MQTT oferece entrega push, um formato JSON amigável para os consumidores, estado atual retido para quem chega depois e a possibilidade de combinar dados das máquinas com dados de CLPs, energia e qualidade em uma única hierarquia de topics. Se você está construindo um Unified Namespace, as máquinas MTConnect se tornam mais uma fonte que o alimenta; nosso guia sobre topics MQTT ISA-95 mostra como posicioná-las.

Versões recentes do agent de referência MTConnect também podem publicar diretamente em um broker MQTT por meio de um sink MQTT embutido. Se a versão do seu agent suporta isso, vale a pena avaliar; as chaves de configuração variam entre versões, então siga a documentação do próprio agent. A ponte deste tutorial funciona com qualquer versão de agent e dá controle total sobre os nomes de topics e o formato do payload.

Pré-requisitos

  • Python 3.10 ou mais recente com requests e paho-mqtt 2.x.
  • A URL de um agent MTConnect, como http://192.168.10.50:5000. Se você não tiver uma máquina conectada, o projeto do agent de referência inclui configurações de exemplo e um simulador que você pode rodar localmente.
  • Um broker. Para testes, use o servidor MQTT público (gratuito) com um prefixo de topic exclusivo; ele serve apenas para testes e protótipos, não para dados de produção.
pip install requests "paho-mqtt>=2.0"
curl -s http://localhost:5000/probe | head -40     # verifica se o agent responde e lista os data items

Passo 1: escolha os data items

Uma CNC moderna pode expor centenas de data items. Publique o que os consumidores precisam, não tudo. Um conjunto inicial prático para dashboards de utilização e status:

Tipo MTConnect Categoria Valores de exemplo Por que importa
AVAILABILITY Event AVAILABLE, UNAVAILABLE Se a máquina está conectada
EXECUTION Event ACTIVE, READY, INTERRUPTED, FEED_HOLD, STOPPED O núcleo do acompanhamento de utilização
CONTROLLER_MODE Event AUTOMATIC, MANUAL, MANUAL_DATA_INPUT Separa produção de setup
PROGRAM Event O1234 Qual job está rodando
PART_COUNT Event 1843 Produção
ROTARY_VELOCITY (spindle) Sample 12000 Atividade de corte
PATH_FEEDRATE_OVERRIDE Event ou Sample 100 Intervenção do operador
Conditions de sistema e lógica Condition Normal, Warning, Fault Alarmes

Execute /probe no seu agent e anote o id de cada data item que você quer. Os IDs são escolhidos por quem configurou o agent, então diferem entre instalações.

Passo 2: a ponte MTConnect para MQTT

A ponte converte os IDs dos data items em nomes de topics, lê o /current para obter o estado inicial e depois entra em loop no /sample. Ela detecta reinícios do agent (um novo instanceId) e estouros de buffer (um from mais antigo que o firstSequence) e se ressincroniza nos dois casos.

# mtconnect_mqtt_bridge.py - segue um agent MTConnect e publica as observações no 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"        # seu próprio id aleatório
INTERVAL = 1.0                                       # segundos entre requisições /sample
MQTT_HOST, MQTT_PORT = "broker.connectmq.com", 1883  # produção: 8883 com TLS
MQTT_USER, MQTT_PASS = None, None                    # produção: "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = f"mtc-bridge-{uuid.uuid4().hex[:8]}"     # produção: "YOUR_CLIENT_ID"

# dataItemId -> folha do topic. Pegue os IDs da saída /probe do seu 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):
    """Remove o namespace XML versionado do MTConnect do nome da tag."""
    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)sincroniza a partir do /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 inválido ou um documento MTConnectError sem Header normal.
            log.error("unexpected agent response: %s", exc)
            next_seq = None
        except requests.RequestException as exc:
            # Erros de rede ou um status de erro, como um "from" fora do intervalo.
            log.error("agent request failed: %s", exc)
            next_seq = None
            time.sleep(5)
        time.sleep(INTERVAL)


if __name__ == "__main__":
    main()

Alguns pontos sobre o projeto:

  • Ordenar pela sequência garante que as observações sejam publicadas na ordem em que o agent as registrou, mesmo quando o XML as agrupa por componente.
  • Retained messages fazem com que um dashboard aberto no meio do turno mostre instantaneamente o estado de execução, o programa e a contagem de peças atuais.
  • As conditions viram objetos com nível e código de alarme nativo, para que os consumidores distingam um aviso de uma falha.
  • Ressincronizar em caso de erro é seguro: o /current republica o estado mais recente, então os consumidores terminam com o estado correto mesmo que algumas amostras intermediárias tenham se perdido.

Passo 3: execute e acompanhe

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}

O servidor MQTT público permite dez mensagens por segundo por client, o que é mais que suficiente para eventos de estado, mas pode ser ultrapassado por samples que mudam rápido, como posições de eixos. Mantenha o WATCH enxuto ou adicione uma banda morta para os samples, como explicado no nosso artigo sobre report by exception.

Construindo um dashboard de status das máquinas

Com execução, modo e disponibilidade no MQTT, uma visão básica de utilização é questão de assinar os topics e cronometrar as mudanças de estado. Um mapeamento simplificado comum:

  1. Produzindo: availability AVAILABLE, modo AUTOMATIC, execution ACTIVE.
  2. Ociosa: disponível, execution READY ou STOPPED.
  3. Interrompida: execution INTERRUPTED, FEED_HOLD ou OPTIONAL_STOP, muitas vezes uma espera pelo operador.
  4. Em alarme: qualquer condition no nível Fault.
  5. Offline: availability UNAVAILABLE ou o topic de status da ponte indica offline.

Qualquer ferramenta de dashboard compatível com MQTT consegue calcular esses estados, e um historiador que assina os mesmos topics fornece relatórios por turno e por job. Nosso guia de historiador MQTT aborda o armazenamento do fluxo.

Notas para produção

  • Posição na rede. Rode a ponte na rede da oficina, ao lado do agent, e deixe-a se conectar para fora até o broker na porta 8883. Não exponha a porta HTTP do agent à internet.
  • Várias máquinas. Um agent muitas vezes atende vários dispositivos; a ponte já trata vários elementos DeviceStream e coloca cada dispositivo em seu próprio ramo.
  • Qualidade do relógio. Os timestamps MTConnect vêm do agent ou do adapter. Garanta que esses hosts usem NTP, ou os cálculos de duração vão se desviar.
  • Broker privado. O servidor MQTT público é visível para todos, então dados reais das máquinas pertencem a um broker MQTT gerenciado privado. No ConnectMQ, a visão de dispositivos agrupa suas máquinas por nível ISA-95, e a demo de gêmeo digital 3D mostra o tipo de visualização de CNC ao vivo que você pode construir sobre WebSockets seguros.

Para o panorama completo de como dados de máquinas, CLPs e gateways se encaixam, leia o guia de IoT industrial com MQTT.

Comece com o ConnectMQ

Coloque os dados das suas CNCs em um broker privado em minutos. Cadastre-se em app.connectmq.com, escolha o plano Serverless (Free), sem cartão de crédito, crie um broker e cole o usuário, a senha e o client ID gerados na ponte. Depois, defina uma regra de alerta por limite no portal do ConnectMQ, por exemplo para a rotação do spindle, e acompanhe o log de alertas enquanto a máquina trabalha.

Perguntas frequentes

O MTConnect suporta MQTT nativamente?

O padrão MTConnect é construído em torno de uma interface HTTP, mas versões recentes do agent de referência incluem um sink MQTT que publica as observações em um broker. Uma pequena ponte como a apresentada acima funciona com qualquer versão de agent.

Por que usar /sample em vez de fazer polling do /current?

O polling do /current mostra apenas o valor mais recente e pode perder estados curtos entre as leituras. Seguir o /sample a partir do nextSequence retorna todas as observações em ordem, então alarmes ou paradas breves não se perdem.

O que significa UNAVAILABLE no MTConnect?

Significa que o agent não conhece o valor no momento, normalmente porque a máquina ou o adapter está desconectado. Publique-o como está, para que os dashboards possam mostrar a máquina como offline.

Posso escrever em uma CNC por meio do MTConnect?

Não. O MTConnect é um padrão somente leitura para monitoramento. Comandos para a máquina exigem as interfaces próprias do fabricante do comando.

Artigos relacionados

Cliente MQTT no CODESYS: Publicando Variáveis do CLP em um Broker

Configure a biblioteca IIoT MQTT Client do CODESYS para publicar variáveis do CLP em JSON, verifique-as no servidor MQTT público broker.connectmq.com e depois migre para um broker privado com credenciais e TLS.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.