Sparkplug Birth- und Death-Zertifikate sind die Nachrichten, die jedem Konsumenten mitteilen, wann ein Edge Node oder Device online geht, welche Metriken es besitzt und wann es verschwindet. In diesem Leitfaden erfahren Sie, wie NBIRTH, NDEATH, DBIRTH und DDEATH mit den Zählern seq und bdSeq zusammenspielen, und Sie starten einen kleinen Python-Edge-Node-Simulator, der den kompletten Lebenszyklus an einen echten Broker veröffentlicht.
Warum Sparkplug Birth- und Death-Nachrichten braucht
Reines MQTT teilt einem Subscriber mit, dass ein Wert angekommen ist. Es sagt ihm nicht, ob der Sender noch lebt, ob der letzte Wert noch gültig ist oder welche anderen Werte existieren. In einem Werk, ob in der Fertigung oder in der Prozessindustrie, ist das ein echtes Problem: Ein Bedienbild, das eine Pumpe mit 1.450 U/min anzeigt, ist gefährlich, wenn das Gateway seit zehn Minuten offline ist.
Sparkplug löst das mit einem Zustandsmodell, das auf zwei MQTT-Funktionen aufbaut: dem Last Will and Testament und der geordneten Zustellung über eine einzige Verbindung. Jeder Edge Node meldet sich mit einem Birth-Zertifikat an, das alle seine Metriken mit ihren aktuellen Werten auflistet. Trennt er die Verbindung, ob sauber oder nicht, teilt ein Death-Zertifikat allen mit, dass diese Werte nun veraltet sind. Host-Anwendungen können Tags dann als schlechte Qualität markieren, statt alte Zahlen anzuzeigen, als wären sie live.
Die vier Zertifikate
| Nachricht | Veröffentlicht von | Wann | Inhalt |
|---|---|---|---|
| NBIRTH | Edge Node | Direkt nach dem Verbindungsaufbau | Alle Node-Metriken, bdSeq, seq 0, Node-Control-Metriken |
| NDEATH | Broker per Last Will oder der Node | Wenn die Node-Session endet | bdSeq passend zum NBIRTH |
| DBIRTH | Edge Node | Nach dem NBIRTH, für jedes Device | Alle Device-Metriken mit aktuellen Werten |
| DDEATH | Edge Node | Wenn ein Device hinter dem Node verloren geht | Nur die Sequenznummer |
Die Topics folgen dem Sparkplug Topic-Namespace: spBv1.0/{group}/NBIRTH/{node} für Node-Nachrichten und spBv1.0/{group}/DBIRTH/{node}/{device} für Devices.
NBIRTH
Das Node-Birth ist die erste Nachricht nach erfolgreichem MQTT-Verbindungsaufbau. Es muss jede Metrik auf Node-Ebene mit Name, Datentyp und aktuellem Wert enthalten, dazu eine bdSeq-Metrik und eine boolesche Metrik Node Control/Rebirth, damit ein Host ein frisches Birth anfordern kann. Werden Metrik-Aliase verwendet, werden Namen und Aliase im NBIRTH einander zugeordnet.
NDEATH
Das Node-Death wird beim Verbindungsaufbau als MQTT-Will-Nachricht registriert. Der Broker veröffentlicht es daher automatisch, wenn die TCP-Verbindung abbricht oder das Keepalive abläuft. Ein Node, der ordnungsgemäß herunterfährt, veröffentlicht es vor dem Trennen selbst. Es ist nicht retained, und in Sparkplug 3.0 verwendet der Will QoS 1.
DBIRTH und DDEATH
Devices haben keine eigene MQTT-Verbindung und können daher keinen Will nutzen. Der Edge Node veröffentlicht nach seinem eigenen NBIRTH ein DBIRTH für jedes Device und ein DDEATH, wenn er den Kontakt zu einem Device verliert, etwa bei einem Modbus-Timeout. Stirbt der Node selbst, gelten implizit auch alle seine Devices als tot; einzelne DDEATH-Nachrichten sind dann nicht nötig.
Sequenznummern: seq und bdSeq
Zwei Zähler halten Host-Anwendungen auf dem richtigen Stand.
seq ist ein Payload-Feld von 0 bis 255. Das NBIRTH hat immer seq 0, und jede folgende Nachricht dieses Nodes (DBIRTH, NDATA, DDATA, DDEATH) erhöht den Wert um eins, wobei nach 255 wieder 0 folgt. Ein Host, der einen Sprung sieht, weiß, dass er eine Nachricht verpasst hat und sein Bild möglicherweise falsch ist.
bdSeq (Birth/Death-Sequenz) ist eine Metrik, kein Payload-Feld. Sie wird bei jeder neuen MQTT-Session des Nodes erhöht. Der Node schreibt denselben bdSeq-Wert in den NDEATH-Will, den er beim Verbinden registriert, und in das NBIRTH, das er nach dem Verbinden veröffentlicht. Da ein Will verspätet zugestellt werden kann, könnte ein Host sonst ein altes NDEATH nach einem neuen NBIRTH erhalten und einen aktiven Node fälschlich als offline markieren. Über übereinstimmende bdSeq-Werte kann der Host ein Death ignorieren, das zu einer früheren Session gehört.
Der Lebenszyklus Schritt für Schritt
- Der Edge Node erhöht bdSeq und erstellt einen NDEATH-Payload, der diesen Wert enthält.
- Er verbindet sich mit diesem NDEATH als Will (QoS 1, nicht retained) und einer Clean Session mit dem Broker.
- Er abonniert seine NCMD- und DCMD-Topics, um Rebirth- und Schreibbefehle empfangen zu können.
- Ist er so konfiguriert, dass er einer Primary Host Application folgt, wartet er, bis deren STATE-Nachricht online meldet.
- Er veröffentlicht NBIRTH mit seq 0 und demselben bdSeq.
- Er veröffentlicht für jedes Device ein DBIRTH.
- Er veröffentlicht NDATA und DDATA bei Änderungen (Report by Exception) und erhöht seq jedes Mal.
- Beim Herunterfahren veröffentlicht er NDEATH; bei einem Absturz übernimmt der Broker das per Will.
Einen Birth- und Death-Simulator in Python starten
Das folgende Skript setzt diesen Lebenszyklus mit paho-mqtt 2.x um. Es benötigt Python-Klassen, die aus der Datei sparkplug_b.proto von Eclipse Tahu generiert werden. Laden Sie das Proto aus dem Tahu-Repository herunter und generieren Sie die Klassen einmalig:
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
Dabei entsteht sparkplug_b_pb2.py neben dem Proto. Speichern Sie den Simulator als edge_sim.py im selben Ordner:
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] # unique group on the public broker
NODE = "line1"
DEVICE = "cnc1"
# Sparkplug datatype codes
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()
Starten Sie es mit python edge_sim.py. Beobachten Sie die Gruppe mit mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-1234 -t "spBv1.0/demo-xxxxxx/#" -v und ersetzen Sie die Gruppe durch diejenige, die das Skript ausgegeben hat. Um den Will in Aktion zu sehen, beenden Sie den Prozess hart, statt Strg+C zu drücken: Nach Ablauf des Keepalive veröffentlicht der Broker das NDEATH im Namen des Nodes.
Der öffentliche MQTT-Broker ist für Tests und Prototypen gedacht, für alle lesbar und erlaubt 10 Nachrichten pro Sekunde und Client. Halten Sie das Veröffentlichungsintervall also großzügig und senden Sie niemals echte Anlagendaten. Für einen echten Einsatz wechseln Sie auf Port 8883 mit TLS und verwenden Ihre Werte für YOUR_USERNAME, YOUR_PASSWORD und YOUR_CLIENT_ID aus dem Portal.
Births und Deaths dekodiert sehen
Die Rohausgabe von mosquitto_sub wirkt teilweise binär, weil die Payloads Protobuf sind. In ConnectMQ dekodiert der Topic-Explorer Sparkplug B, sodass Sie das NBIRTH öffnen und bdSeq, Node Control/Rebirth und jede Device-Metrik mit Namen sehen können. So prüfen Sie am schnellsten, ob der bdSeq im NDEATH zum NBIRTH passt und ob seq ohne Lücken hochzählt. Wenn Sie einen eigenen Decoder bauen möchten, folgen Sie der Anleitung Sparkplug B in Python dekodieren.
Typische Fehler
| Fehler | Auswirkung | Lösung |
|---|---|---|
| Will erst nach dem Connect gesetzt | Kein NDEATH bei einem Absturz | will_set vor connect aufrufen |
| bdSeq unterscheidet sich zwischen NBIRTH und NDEATH | Host ignoriert Deaths oder wendet sie falsch an | Für eine Session denselben Wert verwenden |
| DDATA vor DBIRTH | Host hat keine Metrikdefinitionen | Births immer zuerst veröffentlichen |
| seq beim Rebirth nicht zurückgesetzt | Host erkennt falsche Lücken | NBIRTH verwendet immer seq 0 |
| Retained Births | Veraltete Births werden neuen Hosts erneut zugestellt | Births und Deaths sind niemals retained |
| Persistente Session | Alte Subscriptions und eingereihte Befehle | Eine Clean Session verwenden |
Wo Birth und Death in Ihre Architektur passen
Birth- und Death-Zertifikate machen aus einem Haufen MQTT-Topics eine vertrauenswürdige, zustandsbewusste Datenschicht. Deshalb ist Sparkplug in SCADA-Systemen und als Edge-Transport für einen Unified Namespace (UNS) so verbreitet. Im UNS wird die ISA-95-Equipment-Hierarchie (Enterprise → Site → Area → Line → Cell) zur Topic-Struktur auf dem MQTT-Broker, etwa acme/werk-stuttgart/montage/linie-1/zelle-3/temperatur. Birth und Death sorgen dafür, dass jeder Wert in diesem Baum eine verlässliche Qualitätsaussage trägt: Fällt das Gateway einer Linie aus, sehen MES, OEE-Dashboards und Leitstand sofort, dass die Werte veraltet sind. Wie beide Konzepte zusammenspielen, zeigt der Artikel Sparkplug B und Unified Namespace; für das Gesamtbild lesen Sie den Leitfaden zu Industrial IoT mit MQTT. Im Produktivbetrieb hängt die Zuverlässigkeit des Will-Mechanismus auch vom Broker ab, weshalb die meisten Teams Sparkplug auf einem verwalteten MQTT-Broker betreiben statt auf einem Rechner unter dem Schreibtisch.
Starten Sie mit ConnectMQ
Erstellen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker, ganz ohne Kreditkarte. Richten Sie den Simulator mit den generierten Zugangsdaten auf Ihren Broker aus und verfolgen Sie NBIRTH, DBIRTH, DDATA und NDEATH live und dekodiert im ConnectMQ-Portal.
Häufig gestellte Fragen
Sind Sparkplug-Birth-Zertifikate retained?
Nein. Births und Deaths werden ohne Retain-Flag veröffentlicht. Ein später startender Host sendet einen Rebirth-Befehl, um aktuelle Births zu erhalten, statt sich auf Retained Messages zu verlassen.
Wer veröffentlicht die NDEATH-Nachricht?
In der Regel der Broker, weil das NDEATH als MQTT-Will des Edge Nodes registriert ist. Ein Node, der ordnungsgemäß herunterfährt, kann es vor dem Trennen selbst veröffentlichen.
Braucht jedes Device ein DDEATH, wenn der Node stirbt?
Nein. Sobald das NDEATH eintrifft, behandelt der Host alle Devices unter diesem Node als offline. DDEATH ist nur nötig, wenn ein einzelnes Device verloren geht, während der Node verbunden bleibt.
Was passiert, wenn seq 255 erreicht?
Der Zähler springt auf 0 zurück und läuft weiter. Nur ein NBIRTH setzt ihn bewusst zurück; jeder andere unerwartete Sprung weist auf eine verpasste Nachricht hin.



