IoT industriel

Certificats birth et death Sparkplug : NBIRTH, NDEATH, DBIRTH et DDEATH

Les certificats birth et death permettent à Sparkplug de savoir ce qui est en ligne et si les données sont à jour. Ce guide explique NBIRTH, NDEATH, DBIRTH et DDEATH, les numéros de séquence et bdSeq, avec un simulateur Python fonctionnel.

Chronologie des certificats birth et death Sparkplug montrant NBIRTH, DBIRTH, les messages de données et NDEATH pour un edge node
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Les certificats birth et death Sparkplug sont les messages qui indiquent à chaque consommateur quand un edge node ou un device se connecte, quelles métriques il possède et quand il disparaît. Dans ce guide, vous verrez comment NBIRTH, NDEATH, DBIRTH et DDEATH fonctionnent avec les compteurs seq et bdSeq, et vous lancerez un petit simulateur d'edge node en Python qui publie le cycle de vie complet sur un broker réel.

Pourquoi Sparkplug a besoin de messages birth et death

MQTT seul indique à un abonné qu'une valeur est arrivée. Il ne lui dit pas si l'émetteur est toujours vivant, si la dernière valeur est encore valide ni quelles autres valeurs existent. Dans une usine, c'est un vrai problème : un écran opérateur qui affiche une pompe tournant à 1 450 tr/min est dangereux si la passerelle s'est déconnectée il y a dix minutes.

Sparkplug résout ce problème avec un modèle d'état reposant sur deux fonctionnalités MQTT : le last will and testament et la livraison ordonnée sur une connexion unique. Chaque edge node s'annonce avec un certificat de birth qui liste toutes ses métriques et leurs valeurs courantes. Lorsqu'il se déconnecte, proprement ou non, un certificat de death indique à tous que ces valeurs sont désormais périmées. Les applications hôtes peuvent alors marquer les tags en mauvaise qualité au lieu d'afficher d'anciens chiffres comme s'ils étaient en direct.

Les quatre certificats

Message Publié par Quand Contenu
NBIRTH Edge node Juste après la connexion Toutes les métriques du nœud, bdSeq, seq 0, métriques Node Control
NDEATH Broker via le last will, ou le nœud À la fin de la session du nœud bdSeq identique à celui du NBIRTH
DBIRTH Edge node Après le NBIRTH, pour chaque device Toutes les métriques du device avec leurs valeurs courantes
DDEATH Edge node Lorsqu'un device derrière le nœud est perdu Numéro de séquence uniquement

Les topics suivent l'espace de noms des topics Sparkplug : spBv1.0/{group}/NBIRTH/{node} pour les messages de nœud et spBv1.0/{group}/DBIRTH/{node}/{device} pour les devices.

NBIRTH

Le birth du nœud est le premier message après le succès de la connexion MQTT. Il doit contenir chaque métrique de niveau nœud avec son nom, son type de données et sa valeur courante, ainsi qu'une métrique bdSeq et une métrique booléenne Node Control/Rebirth pour qu'un hôte puisse demander un nouveau birth. Si des alias de métriques sont utilisés, c'est dans le NBIRTH que noms et alias sont associés.

NDEATH

Le death du nœud est enregistré comme message will MQTT lors de la connexion du nœud : le broker le publie donc automatiquement si la connexion TCP tombe ou si le keepalive expire. Un nœud qui s'arrête proprement le publie lui-même avant de se déconnecter. Il n'est pas retained, et dans Sparkplug 3.0 le will utilise la QoS 1.

DBIRTH et DDEATH

Les devices n'ont pas leur propre connexion MQTT et ne peuvent donc pas utiliser de will. L'edge node publie un DBIRTH pour chaque device après son propre NBIRTH, et un DDEATH lorsqu'il perd le contact avec un device, par exemple sur un timeout Modbus. Quand le nœud lui-même meurt, tous ses devices sont implicitement morts aussi ; inutile d'envoyer des DDEATH individuels.

Numéros de séquence : seq et bdSeq

Deux compteurs garantissent la cohérence des applications hôtes.

seq est un champ du payload compris entre 0 et 255. Le NBIRTH a toujours seq 0, et chaque message suivant de ce nœud (DBIRTH, NDATA, DDATA, DDEATH) l'incrémente de un, en repassant de 255 à 0. Un hôte qui constate un saut sait qu'il a manqué un message et que sa vue peut être erronée.

bdSeq (séquence birth/death) est une métrique, pas un champ du payload. Elle s'incrémente chaque fois que le nœud ouvre une nouvelle session MQTT. Le nœud place la même valeur de bdSeq dans le will NDEATH qu'il enregistre à la connexion et dans le NBIRTH qu'il publie ensuite. Comme un will peut être délivré en retard, un hôte pourrait sinon recevoir un ancien NDEATH après un nouveau NBIRTH et marquer à tort un nœud actif comme hors ligne. La correspondance des valeurs bdSeq permet à l'hôte d'ignorer un death appartenant à une session antérieure.

Le cycle de vie étape par étape

  1. L'edge node incrémente bdSeq et construit un payload NDEATH qui le contient.
  2. Il se connecte au broker avec ce NDEATH comme will (QoS 1, non retained), en clean session.
  3. Il s'abonne à ses topics NCMD et DCMD pour recevoir les commandes de rebirth et d'écriture.
  4. S'il est configuré pour suivre une application hôte primaire, il attend que le message STATE de cet hôte indique qu'il est en ligne.
  5. Il publie le NBIRTH avec seq 0 et le même bdSeq.
  6. Il publie un DBIRTH pour chaque device.
  7. Il publie NDATA et DDATA sur changement (report by exception), en incrémentant seq à chaque fois.
  8. À l'arrêt, il publie le NDEATH ; en cas de crash, le broker publie le will à sa place.

Lancer un simulateur birth et death en Python

Le script ci-dessous implémente ce cycle de vie avec paho-mqtt 2.x. Il nécessite des classes Python générées à partir du fichier sparkplug_b.proto d'Eclipse Tahu. Téléchargez le proto depuis le dépôt Tahu et générez-les une fois :

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

Vous obtenez sparkplug_b_pb2.py à côté du proto. Enregistrez le simulateur sous edge_sim.py dans le même dossier :

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]   # groupe unique sur le broker public
NODE = "line1"
DEVICE = "cnc1"

# Codes de types de données 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()

Lancez-le avec python edge_sim.py. Observez le groupe avec mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-1234 -t "spBv1.0/demo-xxxxxx/#" -v, en remplaçant le groupe par celui affiché par le script. Pour voir le will en action, tuez le processus au lieu d'appuyer sur Ctrl+C : une fois le keepalive expiré, le broker publie le NDEATH au nom du nœud.

Le serveur MQTT public gratuit est lisible par tous et autorise 10 messages par seconde et par client : gardez un intervalle de publication raisonnable et n'envoyez jamais de vraies données d'usine. Pour un vrai déploiement, passez au port 8883 avec TLS et utilisez vos YOUR_USERNAME, YOUR_PASSWORD et YOUR_CLIENT_ID issus du portail.

Voir les births et deaths décodés

La sortie brute de mosquitto_sub paraîtra en partie binaire, car les payloads sont en Protobuf. Dans ConnectMQ, l'explorateur de topics décode Sparkplug B : vous pouvez ouvrir le NBIRTH et voir bdSeq, Node Control/Rebirth et chaque métrique du device par son nom. C'est le moyen le plus rapide de confirmer que le bdSeq du NDEATH correspond à celui du NBIRTH, et que seq s'incrémente sans trou. Si vous voulez construire votre propre décodeur, suivez décoder Sparkplug B en Python.

Erreurs courantes

Erreur Effet Solution
Will défini après la connexion Pas de NDEATH en cas de crash Appeler will_set avant connect
bdSeq différent entre NBIRTH et NDEATH L'hôte ignore ou applique mal les deaths Utiliser la même valeur pour une session
DDATA avant le DBIRTH L'hôte n'a aucune définition de métrique Toujours publier les births d'abord
seq non réinitialisé au rebirth L'hôte détecte de faux trous Le NBIRTH utilise toujours seq 0
Births retained Des births périmés rejoués aux nouveaux hôtes Births et deaths ne sont jamais retained
Session persistante Anciens abonnements et commandes en file d'attente Utiliser une clean session

La place des births et deaths dans votre architecture

Les certificats birth et death transforment un amas de topics MQTT en une couche de données fiable et consciente de son état, ce qui explique la présence fréquente de Sparkplug dans les conceptions Unified Namespace et SCADA. Pour une vue d'ensemble, consultez le guide de l'IoT industriel avec MQTT. En production, la fiabilité du mécanisme de will dépend aussi du broker : la plupart des équipes exécutent donc Sparkplug sur un broker MQTT managé plutôt que sur une machine posée sous un bureau.

Démarrer avec ConnectMQ

Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire. Pointez le simulateur vers votre broker avec les identifiants générés, puis observez NBIRTH, DBIRTH, DDATA et NDEATH décodés en direct dans le portail ConnectMQ.

Questions fréquentes

Les certificats de birth Sparkplug sont-ils retained ?

Non. Births et deaths sont publiés sans le flag retain. Un hôte qui démarre plus tard envoie une commande de rebirth pour obtenir les births actuels au lieu de s'appuyer sur des retained messages.

Qui publie le message NDEATH ?

Généralement le broker, car le NDEATH est enregistré comme will MQTT de l'edge node. Un nœud qui s'arrête proprement peut le publier lui-même avant de se déconnecter.

Chaque device a-t-il besoin d'un DDEATH quand le nœud meurt ?

Non. À l'arrivée du NDEATH, l'hôte considère tous les devices de ce nœud comme hors ligne. Le DDEATH n'est nécessaire que lorsqu'un seul device est perdu alors que le nœud reste connecté.

Que se passe-t-il quand seq atteint 255 ?

Il repasse à 0 et continue. Seul un NBIRTH le réinitialise volontairement ; tout autre saut inattendu signale un message manqué.

Articles liés

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.