Uma boa estrutura de topics UNS é o que torna um Unified Namespace navegável: qualquer pessoa que conheça a planta, seja uma fábrica em Joinville ou uma mineradora em Minas Gerais, consegue adivinhar onde um valor está sem abrir a documentação. Este guia traz árvores de topics prontas para manufatura discreta e de processo, as regras de nomenclatura e de payload que as mantêm organizadas e um pequeno validador que você pode rodar no CI ou no gateway para barrar topics ruins antes que cheguem ao broker.
Os princípios por trás de uma estrutura de topics UNS
Todos os exemplos deste artigo seguem os mesmos cinco princípios. Se você adaptar as árvores, mantenha os princípios.
- Modele a planta, não a tecnologia. Os topics descrevem onde algo está e o que é, não qual protocolo ou marca de CLP o gerou.
opcua/es7/não pertencem ao caminho. - Hierarquia primeiro, com a ISA-95 como espinha dorsal. Empresa, site, área, linha ou célula e equipamento formam uma estrutura que a operação já entende. O guia da hierarquia de equipamentos ISA-95 explica cada nível.
- Profundidade fixa sempre que possível. Quando todas as máquinas ficam no mesmo nível, assinaturas com curinga como
+/+/+/+/telemetryfuncionam em toda a empresa. - Um conjunto pequeno de tipos de folha. Termine cada ramo de equipamento em um conjunto previsível de namespaces, como
telemetry,state,alarms,eventsecmd. - Identificadores estáveis. Nomes curtos, em minúsculas e com hifens, que sobrevivam a reorganizações. Números de ativo costumam ser melhores que nomes descritivos que mudam.
Exemplo 1: manufatura discreta
Uma planta discreta com linhas de montagem, células de usinagem e utilidades compartilhadas:
acme/ enterprise
dallas/ site
machining/ area
cell-03/ work cell
cnc-01/ equipment
telemetry {"spindle_rpm":..., "load_pct":..., "ts":...}
state "running" | "idle" | "down" (retained)
alarms active alarm list (retained)
events/cycle-complete one message per finished part
cmd/ commands, request/response
robot-01/
telemetry
state
assembly/
line-02/ production line
station-10/
telemetry
events/part-scanned
station-20/
telemetry
line-02/kpi/oee line-level calculated values
utilities/
compressors/
comp-01/telemetry
Repare no ramo kpi no nível da linha. Valores calculados como OEE ou throughput pertencem ao nível que descrevem e são publicados pela aplicação que os calcula. Isso mantém dados brutos de máquina e dados derivados claramente separados, sem sair da mesma árvore.
Exemplo 2: manufatura de processo
Plantas de processo pensam em células de processo e unidades, não em linhas e estações. A ISA-95 acomoda as duas visões, então a árvore muda de vocabulário, mas não de forma:
acme/
izmir/ site
brewing/ area
brewhouse-1/ process cell
mash-tun/ unit
telemetry {"temp_c":..., "level_pct":..., "ts":...}
state "heating" | "resting" | "transferring"
batch current batch id and recipe (retained)
lauter-tun/
telemetry
fermentation/
fv-07/
telemetry
batch
utilities/
boiler-1/telemetry
water-treatment/ro-1/telemetry
A folha batch é o equivalente, na planta de processo, a uma ordem de produção: retida, pequena e atualizada quando o lote muda. Os consumidores associam o contexto do lote à telemetria pelo caminho do topic, sem consulta a um banco de dados separado.
Exemplo 3: empresa multissite com serviços compartilhados
Quando vários sites compartilham um broker ou um namespace interligado por bridge, adicione um ramo de nível superior para os sistemas corporativos, de modo que dados de MES, ERP e qualidade tenham um lugar próprio que não finja ser um equipamento:
acme/dallas/... site trees as above
acme/izmir/...
acme/_enterprise/erp/work-orders/dallas work orders per site (retained)
acme/_enterprise/quality/spc/dallas/line-02
acme/_enterprise/mes/schedule/izmir
O sublinhado inicial mantém o ramo ordenado separadamente dos nomes de site e deixa claro que ele não é um local físico.
Como o Sparkplug B se encaixa em uma estrutura de topics UNS
O Sparkplug B usa seu próprio formato fixo de topic, spBv1.0/<group>/<message type>/<edge node>/<device>. Esse formato é otimizado para o gerenciamento de estado entre edge nodes e aplicações host, não para a navegação pela hierarquia da planta. Nosso artigo sobre o namespace de topics do Sparkplug explica tudo em detalhes.
Você não precisa escolher. Um padrão comum mantém o Sparkplug para o tráfego entre borda e host e republica os valores na árvore ISA-95 para todos os demais. O ConnectMQ faz isso automaticamente com o tráfego Sparkplug B: decodifica o payload Protobuf ou JSON e o republica em topics ISA-95, de modo que spBv1.0/factory1/DDATA/line1/cnc1 se torna connectmq/factory1/production/line1/cnc1/telemetry. Dashboards e historiadores assinam JSON legível na árvore ISA-95, enquanto os hosts SCADA continuam usando Sparkplug nativo.
Regras de nomenclatura e de payload
| Regra | Bom | Evite |
|---|---|---|
| Apenas minúsculas | line-02 |
Line_02, LINE02 |
| Hifens, sem espaços | mash-tun |
mash tun, mash%20tun |
| Sem barra inicial ou final | acme/dallas/... |
/acme/dallas/ |
Sem curingas ou $ nos nomes |
cnc-01 |
cnc#1, $cnc |
| Unidades nos nomes dos campos | temp_c, speed_bpm |
temp, speed |
| Timestamps nos payloads | "ts": "2026-10-16T08:00:00Z" |
Depender do horário de chegada |
| Reter o estado atual | state, batch, alarms |
Reter fluxos de eventos |
| Versionar os payloads | "v": 2 |
Mudanças incompatíveis silenciosas |
A barra inicial é um erro clássico: ela cria um primeiro nível vazio, de modo que /acme/# e acme/# são assinaturas diferentes. Misturar maiúsculas e minúsculas é outro: topics MQTT diferenciam maiúsculas de minúsculas, e Line-02 e line-02 viram dois ramos distintos que dividem seus dados sem que ninguém perceba.
Valide os topics antes que cheguem ao broker
O script abaixo verifica os topics com base nas regras acima e na estrutura de equipamentos em cinco níveis. Use-o em um gateway, em um teste de CI sobre o seu arquivo de mapeamento de tags ou como um assinante de monitoramento que reporta violações.
import re
LEVEL = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
LEAVES = {"telemetry", "state", "alarms", "batch", "events", "cmd", "kpi"}
def validate(topic: str, depth: int = 5) -> list[str]:
"""Return a list of problems; an empty list means the topic is valid."""
problems = []
if topic.startswith("/") or topic.endswith("/"):
problems.append("leading or trailing slash")
levels = topic.strip("/").split("/")
if any(ch in topic for ch in "+#$"):
problems.append("wildcard or $ character in topic name")
if any(" " in level for level in levels):
problems.append("space in topic level")
if len(levels) < depth + 1:
problems.append(f"expected at least {depth + 1} levels, got {len(levels)}")
return problems
for level in levels[:depth]:
if not (LEVEL.match(level) or level.startswith("_")):
problems.append(f"level '{level}' is not lowercase-hyphenated")
if levels[depth] not in LEAVES:
problems.append(f"leaf '{levels[depth]}' not in {sorted(LEAVES)}")
return problems
if __name__ == "__main__":
tests = [
"acme/dallas/machining/cell-03/cnc-01/telemetry",
"acme/dallas/machining/cell-03/CNC_01/telemetry",
"/acme/dallas/assembly/line-02/station-10/telemetry",
"acme/dallas/assembly/line-02/station-10/temperature",
]
for t in tests:
result = validate(t)
print("OK " if not result else "FAIL", t, "" if not result else result)
Execute com python validate_topics.py e ajuste LEAVES e depth de acordo com o seu padrão.
Evoluindo a estrutura sem quebrar os consumidores
Nenhuma estrutura de topics sobrevive intacta ao contato com uma planta real. Linhas são reconstruídas, máquinas mudam de célula, um novo site é adquirido com seus próprios hábitos de nomenclatura. O objetivo não é evitar mudanças, e sim torná-las seguras.
- Adicione, nunca renomeie no lugar. Quando um ramo precisar mudar, publique no novo caminho e no antigo em paralelo por um período definido e depois desative o antigo. Comunique a data de desativação a todos os responsáveis por consumidores.
- Limpe as retained messages ao desativar. Um ramo desativado continua devolvendo valores retidos a novos assinantes. Publique uma mensagem retida vazia em cada topic de estado antigo para removê-lo.
- Mantenha um registro. Um arquivo simples sob controle de versão listando cada ramo, seu responsável, seus tipos de folha e a versão do schema de payload é suficiente. O validador acima pode ler suas regras a partir desse arquivo.
- Versione os payloads, não os topics. Coloque um campo
vno payload quando o schema mudar. Topics com/v2/no caminho tendem a se multiplicar e confundir as assinaturas com curinga. - Revise os novos ramos. Uma revisão rápida do responsável pelo namespace antes de um gateway entrar em operação pega a maioria dos problemas enquanto ainda são baratos de corrigir.
Trate a estrutura como uma API da qual toda a planta depende, porque é exatamente isso que ela se torna quando dashboards, historiadores, integrações de MES e um gêmeo digital da planta passam a assiná-la.
Teste a estrutura em um broker ao vivo
Antes de implantar uma estrutura, publique algumas mensagens de exemplo e navegue por elas. No servidor MQTT público (gratuito) em broker.connectmq.com você pode fazer isso sem conta, desde que use um prefixo único e lembre que ele pode ser lido por qualquer pessoa e serve para testes e protótipos, não para dados de produção. O servidor MQTT público permite 8 níveis de topic, então connectmq/demo/<id>/ mais a árvore de cinco níveis e uma folha cabe exatamente quando você omite o nível da empresa:
mosquitto_pub -h broker.connectmq.com -p 1883 -i uns-test-pub-q7 -r \
-t "connectmq/demo/q7w2/dallas/machining/cell-03/cnc-01/state" -m "running"
mosquitto_sub -h broker.connectmq.com -p 1883 -i uns-test-sub-q7 \
-t "connectmq/demo/q7w2/dallas/+/+/+/state" -v
Em um broker privado do ConnectMQ você pode usar a árvore completa sem o prefixo de demonstração, e o explorador de topics em tempo real e a visão de dispositivos ISA-95 do portal mostram de relance se os dispositivos estão caindo na empresa, no site, na área e na linha corretos. Para regras de codificação passo a passo, continue com topics MQTT ISA-95 e, para o processo completo de construção, veja como construir um Unified Namespace. O panorama geral está no nosso guia de MQTT para IoT industrial.
Coloque sua estrutura de topics UNS no ConnectMQ
Uma estrutura de topics é tão boa quanto o broker que a transporta e a visibilidade que você tem sobre ela. O ConnectMQ é um broker MQTT gerenciado que detecta topics ISA-95 e de Unified Namespace, decodifica Sparkplug B e o republica na sua árvore ISA-95. Crie um broker no plano gratuito Serverless em app.connectmq.com, sem cartão de crédito, e publique o primeiro ramo do seu namespace em minutos.
Perguntas frequentes
Quantos níveis uma estrutura de topics UNS deve ter?
A maioria das plantas usa cinco ou seis: empresa, site, área, linha ou célula, equipamento e uma folha como telemetry ou state. A profundidade fixa mantém as assinaturas com curinga simples.
Cada métrica deve ter seu próprio topic?
As duas abordagens funcionam. Um objeto JSON por topic de telemetria de equipamento é mais simples e barato; um topic por métrica atende ferramentas que mapeiam topics diretamente para tags. Escolha uma por tipo de folha e aplique-a de forma consistente.
Onde ficam os KPIs calculados?
No nível que descrevem, publicados pela aplicação que os calcula, por exemplo um ramo kpi/oee sob a linha.
Topics Sparkplug B podem fazer parte de um UNS?
Sim, mas eles não são organizados pela hierarquia da planta. Republique os valores Sparkplug em topics ISA-95 para que todos os consumidores naveguem por uma única árvore.



