Topics MQTT ISA-95 colocam a hierarquia de equipamentos da planta diretamente no caminho do topic, de modo que acme/dallas/packaging/line-02/filler/telemetry diz a cada assinante exatamente de onde vem um valor. Neste guia você vai aprender a codificar cada nível ISA-95, a projetar a folha do topic, a planejar as assinaturas com curinga antes de precisar delas e quais armadilhas geram mais retrabalho quando um namespace já está em produção.
Por que codificar a ISA-95 nos topics MQTT
Topics MQTT são strings livres separadas por barras, e o broker MQTT não atribui a elas nenhum significado além de casar assinaturas. Essa liberdade é perigosa na escala de uma planta, seja uma fábrica em Joinville, uma mineradora ou uma usina. Se cada integrador inventar uma estrutura, os consumidores acabam com uma tabela de consulta por fonte.
A hierarquia de equipamentos ISA-95 resolve isso ao oferecer uma estrutura que já existe na documentação da planta, no MES e no sistema de manutenção. Codificá-la nos topics traz três propriedades de graça:
- Descoberta. Qualquer pessoa que conheça a planta encontra um valor navegando pela árvore.
- Contexto. O topic carrega o endereço do ativo, então os payloads não precisam repeti-lo.
- Assinatura seletiva. Os curingas correspondem naturalmente a escopos organizacionais: um site, uma área, todas as envasadoras.
Se você precisa revisar os próprios níveis, leia primeiro sobre a hierarquia de equipamentos ISA-95.
O padrão básico
O padrão canônico posiciona os níveis do mais amplo ao mais restrito, seguidos por um namespace que diz que tipo de dado a mensagem contém:
<enterprise>/<site>/<area>/<work center>/<work unit>/<namespace>[/<detail>]
acme/dallas/packaging/line-02/filler/telemetry
acme/dallas/packaging/line-02/filler/state
acme/dallas/packaging/line-02/filler/alarms
acme/dallas/packaging/line-02/filler/events/batch-complete
acme/dallas/packaging/line-02/filler/cmd/stop
Regras para cada nível
| Nível | Regra | Exemplo |
|---|---|---|
| Empresa | Um nome curto e estável; omita apenas se o broker atender uma única empresa | acme |
| Site | Código de localização que sobreviva a reorganizações | dallas, izmir |
| Área | Área de função ou de produto | packaging, utilities |
| Centro de trabalho | Linha, célula, célula de processo, unidade ou zona de armazenagem | line-02, cell-03 |
| Unidade de trabalho | Máquina ou unidade, de preferência pela tag do ativo | filler, cnc-01 |
| Namespace | Vocabulário fixo | telemetry, state, alarms, events, cmd |
Mantenha a profundidade fixa nos topics de equipamento. Quando todas as unidades de trabalho ficam no nível cinco, +/+/+/+/+/state retorna o estado de todas as máquinas da empresa, e a posição de cada nível no caminho fica garantida.
Projetando a folha
O namespace e o que vem depois dele é onde acontece a maioria dos debates de projeto. Há duas opções principais para a telemetria.
Um objeto por equipamento. Todos os valores atuais de uma máquina vão em um único documento JSON em .../filler/telemetry. Isso é compacto, mantém valores relacionados consistentes no tempo e exige apenas uma retained message por máquina.
{ "ts": "2026-10-16T08:15:02Z", "speed_bpm": 118.4, "temp_c": 41.2, "good_count": 18342, "v": 1 }
Um topic por métrica. Cada valor tem seu próprio topic, como .../filler/telemetry/speed_bpm, com um payload escalar ou um JSON pequeno. Isso combina naturalmente com ferramentas baseadas em tags, como sistemas SCADA, e os consumidores podem assinar exatamente os sinais de que precisam.
As duas são válidas. Escolha por namespace e documente. Um híbrido comum é um objeto para a telemetria e valores retidos por topic para state e alguns KPIs-chave.
Planeje suas assinaturas com curinga
Antes de finalizar a estrutura, anote as assinaturas de que seus consumidores vão precisar e confira se cada uma é um único filtro com curinga:
| Consumidor | Precisa de | Assinatura |
|---|---|---|
| Dashboard do site | Tudo de um site | acme/dallas/# |
| Supervisor de envase | Todos os estados de uma área | acme/dallas/packaging/+/+/state |
| Analytics da frota | Todas as envasadoras, em qualquer lugar | acme/+/+/+/filler/telemetry |
| Serviço de alarmes | Todos os alarmes | acme/+/+/+/+/alarms |
| Historiador | Toda a telemetria | acme/+/+/+/+/telemetry |
Se um escopo necessário exigir várias assinaturas ou filtragem no cliente, a estrutura está jogando contra você. Normalmente isso significa que falta um nível, que a ordem é inconsistente ou que o vocabulário das folhas está solto demais.
Publicando topics ISA-95 a partir do código
Gerar os topics em um só lugar evita que erros de digitação criem ramos indevidos. Este helper em Python monta e valida o caminho e depois publica o estado e a telemetria como mensagens retidas. Instale o cliente com pip install "paho-mqtt>=2.0". Ele usa o servidor MQTT público com um prefixo de demonstração; em um broker privado, defina PREFIX com o nome da sua empresa.
import json
import re
import threading
from dataclasses import dataclass
from datetime import datetime, timezone
import paho.mqtt.client as mqtt
PREFIX = "connectmq/demo/r8t5" # no seu próprio broker: "acme"
SAFE = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
NAMESPACES = {"telemetry", "state", "alarms", "events", "cmd"}
@dataclass(frozen=True)
class Asset:
site: str
area: str
work_center: str
work_unit: str
def topic(self, namespace: str) -> str:
for level in (self.site, self.area, self.work_center, self.work_unit):
if not SAFE.match(level):
raise ValueError(f"invalid level: {level!r}")
if namespace not in NAMESPACES:
raise ValueError(f"unknown namespace: {namespace!r}")
return f"{PREFIX}/{self.site}/{self.area}/{self.work_center}/{self.work_unit}/{namespace}"
filler = Asset("dallas", "packaging", "line-02", "filler")
connected = threading.Event()
def on_connect(client, userdata, flags, reason_code, properties):
print("connected:", reason_code)
connected.set()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="isa95-pub-r8t5")
client.on_connect = on_connect
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
connected.wait(timeout=10)
client.publish(filler.topic("state"), "running", qos=1, retain=True).wait_for_publish()
telemetry = {"ts": datetime.now(timezone.utc).isoformat(), "speed_bpm": 118.4, "temp_c": 41.2, "v": 1}
client.publish(filler.topic("telemetry"), json.dumps(telemetry), qos=1, retain=True).wait_for_publish()
print("published to", filler.topic("telemetry"))
client.loop_stop()
client.disconnect()
Verifique com um curinga que corresponda à tabela acima:
mosquitto_sub -h broker.connectmq.com -p 1883 -i isa95-sub-r8t5 -t "connectmq/demo/r8t5/+/packaging/+/+/state" -v
O servidor MQTT público (gratuito) serve para testes, pode ser lido por qualquer pessoa e permite 8 níveis de topic, por isso o prefixo de demonstração substitui aqui o nível da empresa. Reserve nomes e valores reais de ativos, e qualquer dado de produção, para um broker privado.
Trazendo o Sparkplug B para a árvore ISA-95
Topics Sparkplug B seguem um formato fixo, spBv1.0/<group>/<type>/<edge node>/<device>, com payloads Protobuf. Eles não seguem a ISA-95, e consumidores que não entendem Sparkplug não conseguem lê-los. Em vez de abandonar o Sparkplug na borda, republique seus dados na sua árvore ISA-95.
O ConnectMQ faz isso automaticamente: decodifica payloads Sparkplug B, em Protobuf ou JSON, e os republica em topics ISA-95. Por exemplo, spBv1.0/factory1/DDATA/line1/cnc1 é republicado como connectmq/factory1/production/line1/cnc1/telemetry. Escolha IDs de grupo e de edge node do Sparkplug que carreguem nomes significativos da planta, para que os caminhos ISA-95 resultantes sejam legíveis. Os prós e contras das duas abordagens são discutidos em MQTT, Sparkplug B e o Unified Namespace.
Armadilhas a evitar
- Barra inicial.
/acme/dallascria um primeiro nível vazio e divide as assinaturas. - Maiúsculas e minúsculas misturadas. Topics diferenciam maiúsculas de minúsculas;
Line-02eline-02são ramos diferentes. - Nomes de protocolo ou fabricante no caminho.
acme/dallas/opcua/...acopla os consumidores à tecnologia de integração atual. - Profundidade variável. Pular um nível para uma máquina quebra os curingas posicionais. Use um centro de trabalho de preenchimento.
- Timestamps ou IDs nos topics. Topics como
.../telemetry/20261016criam ramos ilimitados e acúmulo de retained messages. - Reter eventos. Retenha estado, não fluxos de eventos; um novo assinante não deveria receber um "batch complete" antigo.
- Comandos sem requisição e resposta. Use response topics e correlation data do MQTT 5 em
cmd, para que quem envia saiba se o comando teve sucesso. - Caminhos longos em links limitados. Topics longos adicionam bytes a cada mensagem. Os topic aliases do MQTT 5 reduzem essa sobrecarga sem mudar o projeto.
Documente o padrão antes da implantação
Um padrão de topics que existe só na cabeça de um engenheiro será quebrado pelo segundo integrador. Antes que o primeiro gateway entre em operação, escreva um padrão de uma página que cubra:
- A ordem dos níveis e os caracteres permitidos em cada nível.
- A lista de namespaces e o que cada um pode conter, com um payload de exemplo.
- Quais topics são retidos e quais não são.
- O formato de timestamp, o fuso horário e a convenção de unidades.
- Quem aprova novos sites, áreas e centros de trabalho, e como as solicitações são feitas.
Entregue essa página a cada integrador de sistemas e fornecedor de gateway, junto com o helper de topics acima ou seu equivalente na linguagem deles. Quando o padrão e o código concordam, a maioria dos erros é pega antes de chegar ao broker.
A segurança merece uma nota própria: emita uma credencial por gateway e aplicação, para que cada publicador seja identificável e revogável, e use TLS na porta 8883 em todo lugar fora do laboratório. Nossas boas práticas de segurança MQTT cobrem o restante.
Uma árvore ISA-95 consistente também é a base de dados de um gêmeo digital da planta. Para árvores completas prontas para copiar, veja a estrutura de topics UNS. Para a arquitetura ao redor delas, o guia de MQTT para IoT industrial é o ponto de partida.
Rode topics MQTT ISA-95 no ConnectMQ
O ConnectMQ é um broker MQTT gerenciado que entende estruturas de topics industriais: detecta topics ISA-95 e de Unified Namespace, mostra os dispositivos por nível ISA-95 no portal e republica Sparkplug B na sua árvore. Crie um broker no plano gratuito Serverless em app.connectmq.com, sem cartão de crédito, e publique hoje mesmo seu primeiro ramo ISA-95.
Perguntas frequentes
O nome da empresa deve ser o primeiro nível do topic?
Sim, se o broker puder algum dia atender mais de uma empresa ou unidade de negócio. Em um broker de uma única empresa você pode omiti-lo, mas adicioná-lo depois significa renomear todos os topics.
Como lidar com máquinas que não pertencem a uma linha?
Dê a elas um centro de trabalho de preenchimento, como standalone ou shared, para que fiquem na mesma profundidade que todo o resto.
Posso usar espaços ou letras maiúsculas em topics MQTT ISA-95?
O MQTT permite, mas isso causa bugs sutis. Use apenas letras minúsculas, dígitos e hifens.
Topics ISA-95 funcionam com MQTT 3.1.1?
Sim. O projeto de topics independe da versão. O MQTT 5 acrescenta extras úteis, como topic aliases e response topics para comandos.



