Os certificados birth e death do Sparkplug são as mensagens que informam a todos os consumidores quando um edge node ou device fica online, quais métricas ele tem e quando ele sai do ar. Neste guia você vai aprender como NBIRTH, NDEATH, DBIRTH e DDEATH funcionam em conjunto com os contadores seq e bdSeq, e vai rodar um pequeno simulador de edge node em Python que publica o ciclo de vida completo em um broker real.
Por que o Sparkplug precisa de mensagens de birth e death
O MQTT puro avisa ao subscriber que um valor chegou. Ele não diz se o remetente ainda está vivo, se o último valor continua válido ou que outros valores existem. Em uma planta isso é um problema real: uma tela de operador que mostra uma bomba girando a 1.450 rpm é perigosa se o gateway caiu há dez minutos.
O Sparkplug resolve isso com um modelo de estado construído sobre dois recursos do MQTT: o last will and testament e a entrega ordenada em uma única conexão. Todo edge node se anuncia com um certificado de birth que lista todas as suas métricas e os valores atuais. Quando ele se desconecta, de forma limpa ou não, um certificado de death avisa a todos que esses valores agora estão desatualizados. As aplicações host podem então marcar as tags com qualidade ruim em vez de exibir números antigos como se fossem ao vivo.
Os quatro certificados
| Mensagem | Publicada por | Quando | Contém |
|---|---|---|---|
| NBIRTH | Edge node | Logo após conectar | Todas as métricas do node, bdSeq, seq 0, métricas Node Control |
| NDEATH | Broker via last will, ou o node | Quando a sessão do node termina | bdSeq igual ao do NBIRTH |
| DBIRTH | Edge node | Depois do NBIRTH, para cada device | Todas as métricas do device com valores atuais |
| DDEATH | Edge node | Quando um device atrás do node é perdido | Apenas o número de sequência |
Os topics seguem o namespace de topics do Sparkplug: spBv1.0/{group}/NBIRTH/{node} para mensagens de node e spBv1.0/{group}/DBIRTH/{node}/{device} para devices.
NBIRTH
O birth do node é a primeira mensagem depois que a conexão MQTT é estabelecida. Ele precisa conter todas as métricas em nível de node com nome, tipo de dado e valor atual, além de uma métrica bdSeq e de uma métrica booleana Node Control/Rebirth, para que um host possa solicitar um novo birth. Se forem usados aliases de métricas, é no NBIRTH que nomes e aliases são pareados.
NDEATH
O death do node é registrado como a mensagem will do MQTT quando o node se conecta, de modo que o broker o publica automaticamente se a conexão TCP cair ou o keepalive expirar. Um node que encerra de forma ordenada o publica ele mesmo antes de se desconectar. Ele não é retained e, no Sparkplug 3.0, o will usa QoS 1.
DBIRTH e DDEATH
Os devices não têm conexão MQTT própria, então não podem usar um will. O edge node publica um DBIRTH para cada device depois do seu próprio NBIRTH e um DDEATH quando perde contato com um device, por exemplo em um timeout Modbus. Quando o próprio node morre, todos os seus devices também ficam implicitamente mortos; não há necessidade de mensagens DDEATH individuais.
Números de sequência: seq e bdSeq
Dois contadores mantêm as aplicações host fiéis à realidade.
seq é um campo do payload que vai de 0 a 255. O NBIRTH sempre tem seq 0, e cada mensagem seguinte daquele node (DBIRTH, NDATA, DDATA, DDEATH) o incrementa em um, voltando de 255 para 0. Um host que vê um salto sabe que perdeu uma mensagem e que a sua visão pode estar errada.
bdSeq (sequência de birth/death) é uma métrica, não um campo do payload. Ele é incrementado a cada vez que o node inicia uma nova sessão MQTT. O node coloca o mesmo valor de bdSeq no will NDEATH que registra na conexão e no NBIRTH que publica depois de conectar. Como um will pode ser entregue com atraso, um host poderia, de outra forma, receber um NDEATH antigo depois de um NBIRTH novo e marcar erroneamente como offline um node que está vivo. Valores de bdSeq correspondentes permitem que o host ignore um death que pertence a uma sessão anterior.
O ciclo de vida passo a passo
- O edge node incrementa o bdSeq e monta um payload NDEATH que o contém.
- Ele se conecta ao broker com esse NDEATH como will (QoS 1, não retained), usando clean session.
- Ele assina os seus topics NCMD e DCMD para poder receber comandos de rebirth e de escrita.
- Se estiver configurado para seguir uma Primary Host Application, ele espera até que a mensagem STATE desse host indique online.
- Ele publica o NBIRTH com seq 0 e o mesmo bdSeq.
- Ele publica um DBIRTH para cada device.
- Ele publica NDATA e DDATA quando há mudança (report by exception), incrementando o seq a cada vez.
- No desligamento ele publica o NDEATH; em caso de falha o broker publica o will por ele.
Rode um simulador de birth e death em Python
O script abaixo implementa esse ciclo de vida com paho-mqtt 2.x. Ele precisa de classes Python geradas a partir do arquivo sparkplug_b.proto do Eclipse Tahu. Baixe o proto do repositório do Tahu e gere as classes uma vez:
pip install "paho-mqtt>=2.0" protobuf grpcio-tools
curl -O https://raw.githubusercontent.com/eclipse/tahu/master/sparkplug_b/sparkplug_b.proto
python -m grpc_tools.protoc -I. --python_out=. sparkplug_b.proto
Isso gera o sparkplug_b_pb2.py ao lado do proto. Salve o simulador como edge_sim.py na mesma pasta:
import random
import time
import uuid
import paho.mqtt.client as mqtt
import sparkplug_b_pb2 as spb
BROKER = "broker.connectmq.com"
PORT = 1883
GROUP = "demo-" + uuid.uuid4().hex[:6] # group exclusivo no broker público
NODE = "line1"
DEVICE = "cnc1"
# Códigos de tipo de dado do Sparkplug
INT64, DOUBLE, BOOLEAN = 4, 10, 11
seq = 0
bd_seq = 0
def now_ms():
return int(time.time() * 1000)
def next_seq():
global seq
value = seq
seq = (seq + 1) % 256
return value
def add_metric(payload, name, datatype, value):
m = payload.metrics.add()
m.name = name
m.timestamp = now_ms()
m.datatype = datatype
if datatype == INT64:
m.long_value = value
elif datatype == DOUBLE:
m.double_value = value
elif datatype == BOOLEAN:
m.boolean_value = value
def topic(msg_type, device=None):
base = f"spBv1.0/{GROUP}/{msg_type}/{NODE}"
return f"{base}/{device}" if device else base
def ndeath_payload():
p = spb.Payload()
p.timestamp = now_ms()
add_metric(p, "bdSeq", INT64, bd_seq)
return p.SerializeToString()
def publish_births(client):
global seq
seq = 0
nbirth = spb.Payload(timestamp=now_ms(), seq=next_seq())
add_metric(nbirth, "bdSeq", INT64, bd_seq)
add_metric(nbirth, "Node Control/Rebirth", BOOLEAN, False)
add_metric(nbirth, "Properties/Uptime", INT64, 0)
client.publish(topic("NBIRTH"), nbirth.SerializeToString(), qos=0)
dbirth = spb.Payload(timestamp=now_ms(), seq=next_seq())
add_metric(dbirth, "Spindle/Speed", DOUBLE, 0.0)
add_metric(dbirth, "Spindle/Running", BOOLEAN, False)
client.publish(topic("DBIRTH", DEVICE), dbirth.SerializeToString(), qos=0)
print(f"births published for {GROUP}/{NODE}/{DEVICE} (bdSeq={bd_seq})")
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print("connect failed:", reason_code)
return
client.subscribe(f"spBv1.0/{GROUP}/NCMD/{NODE}", qos=0)
client.subscribe(f"spBv1.0/{GROUP}/DCMD/{NODE}/#", qos=0)
publish_births(client)
def on_message(client, userdata, msg):
cmd = spb.Payload()
cmd.ParseFromString(msg.payload)
for m in cmd.metrics:
if m.name == "Node Control/Rebirth" and m.boolean_value:
print("rebirth requested")
publish_births(client)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"edge-sim-{uuid.uuid4().hex[:8]}",
clean_session=True)
client.on_connect = on_connect
client.on_message = on_message
client.will_set(topic("NDEATH"), ndeath_payload(), qos=1, retain=False)
client.connect(BROKER, PORT, keepalive=30)
client.loop_start()
try:
while True:
time.sleep(2)
ddata = spb.Payload(timestamp=now_ms(), seq=next_seq())
add_metric(ddata, "Spindle/Speed", DOUBLE, round(random.uniform(1400, 1500), 1))
add_metric(ddata, "Spindle/Running", BOOLEAN, True)
client.publish(topic("DDATA", DEVICE), ddata.SerializeToString(), qos=0)
except KeyboardInterrupt:
ddeath = spb.Payload(timestamp=now_ms(), seq=next_seq())
client.publish(topic("DDEATH", DEVICE), ddeath.SerializeToString(), qos=0)
client.publish(topic("NDEATH"), ndeath_payload(), qos=1).wait_for_publish()
client.disconnect()
client.loop_stop()
Execute com python edge_sim.py. Acompanhe o group com mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-1234 -t "spBv1.0/demo-xxxxxx/#" -v, substituindo o group pelo que o script imprimiu. Para ver o will em ação, mate o processo em vez de pressionar Ctrl+C: depois que o keepalive expira, o broker publica o NDEATH em nome do node.
O servidor MQTT público, voltado a testes e protótipos, pode ser lido por qualquer pessoa e permite 10 mensagens por segundo por cliente, então mantenha um intervalo de publicação folgado e nunca envie dados reais da planta. Em uma implantação real, troque para a porta 8883 com TLS e use os seus YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID do portal.
Vendo births e deaths decodificados
A saída bruta do mosquitto_sub vai parecer parcialmente binária porque os payloads são Protobuf. No ConnectMQ, o topic explorer decodifica Sparkplug B, então você pode abrir o NBIRTH e ver bdSeq, Node Control/Rebirth e cada métrica do device pelo nome. Essa é a forma mais rápida de confirmar que o bdSeq do NDEATH corresponde ao do NBIRTH e que o seq é incrementado sem lacunas. Se quiser construir o seu próprio decodificador, siga decodificar Sparkplug B em Python.
Erros comuns
| Erro | Efeito | Solução |
|---|---|---|
| Will definido depois do connect | Nenhum NDEATH em caso de falha | Chame will_set antes de connect |
| bdSeq diferente entre NBIRTH e NDEATH | O host ignora ou aplica deaths de forma errada | Use o mesmo valor durante uma sessão |
| DDATA antes do DBIRTH | O host não tem as definições das métricas | Sempre publique os births primeiro |
| seq não zerado no rebirth | O host detecta lacunas falsas | O NBIRTH sempre usa seq 0 |
| Births retained | Births antigos reproduzidos para novos hosts | Births e deaths nunca são retained |
| Sessão persistente | Assinaturas antigas e comandos enfileirados | Use clean session |
Onde birth e death se encaixam na sua arquitetura
Os certificados de birth e death são o que transforma um amontoado de topics MQTT em uma camada de dados confiável e consciente de estado, e é por isso que o Sparkplug é comum em projetos de Unified Namespace, SCADA e gêmeo digital, de uma mineradora a um frigorífico: o gêmeo digital só reflete a planta com fidelidade se souber quais nodes estão vivos. Para o panorama mais amplo, veja o guia de IoT Industrial com MQTT. Em produção, a confiabilidade do mecanismo de will também depende do broker, por isso a maioria das equipes roda Sparkplug em um broker MQTT gerenciado em vez de uma máquina embaixo da mesa.
Comece com o ConnectMQ
Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. Aponte o simulador para o seu broker com as credenciais geradas e acompanhe NBIRTH, DBIRTH, DDATA e NDEATH decodificados ao vivo no portal do ConnectMQ.
Perguntas frequentes
Os certificados de birth do Sparkplug são retained?
Não. Births e deaths são publicados sem a flag retain. Um host que inicia depois envia um comando de rebirth para obter os births atuais, em vez de depender de mensagens retained.
Quem publica a mensagem NDEATH?
Normalmente o broker, porque o NDEATH é registrado como o will MQTT do edge node. Um node que encerra de forma ordenada pode publicá-lo ele mesmo antes de se desconectar.
Todo device precisa de um DDEATH quando o node morre?
Não. Quando o NDEATH chega, o host trata todos os devices sob aquele node como offline. O DDEATH só é necessário quando um único device é perdido enquanto o node continua conectado.
O que acontece quando o seq chega a 255?
Ele volta para 0 e continua. Apenas um NBIRTH o zera deliberadamente; qualquer outro salto inesperado indica uma mensagem perdida.



