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,FaultouUnavailable, 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
requestsepaho-mqtt2.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
/currentrepublica 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:
- Produzindo: availability AVAILABLE, modo AUTOMATIC, execution ACTIVE.
- Ociosa: disponível, execution READY ou STOPPED.
- Interrompida: execution INTERRUPTED, FEED_HOLD ou OPTIONAL_STOP, muitas vezes uma espera pelo operador.
- Em alarme: qualquer condition no nível Fault.
- 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
DeviceStreame 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.



