IoT industriel

Templates et UDT Sparkplug expliqués

Les templates Sparkplug apportent à MQTT les types définis par l'utilisateur des automates. Ce guide explique définitions et instances de templates, paramètres, imbrication et versionnage, avec du code Python qui construit un template de pompe et des conseils pour garder des modèles cohérents entre edge nodes.

Schéma des templates Sparkplug montrant une définition de pompe et plusieurs instances de pompes publiées par des edge nodes
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 templates Sparkplug sont la manière dont Sparkplug B définit des types d'équipements réutilisables : l'équivalent MQTT d'un type défini par l'utilisateur (UDT) dans un automate ou un système SCADA. Dans ce guide, vous verrez comment fonctionnent les définitions et les instances de templates, quelle place occupent les paramètres, l'imbrication et les versions, comment construire un template de pompe en Python, et comment garder le même modèle cohérent sur de nombreux edge nodes.

Pourquoi les templates existent

Sans templates, une pompe n'est qu'un ensemble de métriques vaguement liées : Pump1/Speed, Pump1/Running, Pump1/Pressure. Une seconde pompe répète les mêmes noms avec un autre préfixe, et rien n'indique à l'application hôte que les deux sont des pompes. Si un edge node appelle la métrique Speed et un autre RPM, chaque consommateur doit connaître la différence.

Les templates règlent ce problème en séparant le type de l'instance. Vous définissez une Pump une seule fois avec ses métriques membres, leurs types de données et leurs valeurs par défaut. Chaque pompe physique est alors une instance qui fait référence à la définition. Une application hôte qui comprend les templates peut créer automatiquement les objets correspondants, appliquer les mêmes vues et alarmes à chaque pompe, et détecter lorsqu'une instance ne correspond pas à son type.

Définitions et instances

Définitions et instances sont des métriques de type 19 (Template) dont la valeur est un message Template :

Champ du template Rôle Dans une définition Dans une instance
version Chaîne de version optionnelle Recommandé Optionnel
metrics Métriques membres Membres avec types et valeurs par défaut Membres avec valeurs courantes
parameters Constantes nommées et typées Déclarées avec des valeurs par défaut Surchargées par instance
template_ref Nom de la définition utilisée Non renseigné Obligatoire, pointe vers la définition
is_definition Marque une définition true false

Où se trouvent les définitions

Les définitions de templates sont publiées dans le NBIRTH, avant toute instance qui les utilise. Elles ne sont pas répétées dans les messages de données. Certaines plateformes préfixent les noms de définitions par un dossier comme _types_/ pour séparer les types des tags en direct ; il s'agit d'une convention de plateforme et non d'une exigence : suivez ce qu'attend votre application hôte.

Où se trouvent les instances

Les instances peuvent apparaître dans le NBIRTH (équipement de niveau nœud) ou dans un DBIRTH (équipement derrière un device). Dans le birth, chaque instance porte l'ensemble complet des métriques membres avec leurs valeurs courantes. Les messages de données transportent ensuite les changements.

Un exemple décodé

Voici une définition de pompe telle qu'elle apparaît dans un NBIRTH après décodage :

{
  "name": "_types_/Pump",
  "datatype": 19,
  "templateValue": {
    "version": "1.2",
    "isDefinition": true,
    "parameters": [
      { "name": "RatedSpeed", "type": 9, "floatValue": 1500.0 }
    ],
    "metrics": [
      { "name": "Running", "datatype": 11, "booleanValue": false },
      { "name": "Speed", "datatype": 9, "floatValue": 0.0 },
      { "name": "DischargePressure", "datatype": 9, "floatValue": 0.0 },
      { "name": "StartCount", "datatype": 8, "longValue": "0" }
    ]
  }
}

Et une instance de celle-ci dans un DBIRTH :

{
  "name": "CoolingPump1",
  "alias": 20,
  "datatype": 19,
  "templateValue": {
    "templateRef": "_types_/Pump",
    "version": "1.2",
    "isDefinition": false,
    "parameters": [
      { "name": "RatedSpeed", "type": 9, "floatValue": 2900.0 }
    ],
    "metrics": [
      { "name": "Running", "datatype": 11, "booleanValue": true },
      { "name": "Speed", "datatype": 9, "floatValue": 2875.5 },
      { "name": "DischargePressure", "datatype": 9, "floatValue": 3.4 },
      { "name": "StartCount", "datatype": 8, "longValue": "1287" }
    ]
  }
}

L'instance surcharge le paramètre RatedSpeed car cette pompe a un moteur différent. Les paramètres sont idéaux pour les données de plaque signalétique et les limites qui diffèrent d'un actif à l'autre sans changer en cours d'exécution.

Construire un template en Python

Cet extrait construit la définition et une instance à l'aide de classes générées à partir du fichier sparkplug_b.proto d'Eclipse Tahu. Notre tutoriel pour décoder Sparkplug B en Python présente l'étape de génération de code, à effectuer une seule fois.

import time

import sparkplug_b_pb2 as spb

BOOLEAN, FLOAT, UINT64, TEMPLATE = 11, 9, 8, 19
MEMBERS = [("Running", BOOLEAN), ("Speed", FLOAT),
           ("DischargePressure", FLOAT), ("StartCount", UINT64)]


def set_value(metric, datatype, value):
    metric.datatype = datatype
    if datatype == BOOLEAN:
        metric.boolean_value = value
    elif datatype == FLOAT:
        metric.float_value = value
    elif datatype == UINT64:
        metric.long_value = value


def add_pump_definition(payload):
    m = payload.metrics.add()
    m.name = "_types_/Pump"
    m.datatype = TEMPLATE
    t = m.template_value
    t.version = "1.2"
    t.is_definition = True
    p = t.parameters.add()
    p.name, p.type, p.float_value = "RatedSpeed", FLOAT, 1500.0
    for name, dtype in MEMBERS:
        member = t.metrics.add()
        member.name = name
        set_value(member, dtype, False if dtype == BOOLEAN else 0)


def add_pump_instance(payload, name, alias, rated_speed, values):
    m = payload.metrics.add()
    m.name = name
    m.alias = alias
    m.timestamp = int(time.time() * 1000)
    m.datatype = TEMPLATE
    t = m.template_value
    t.template_ref = "_types_/Pump"
    t.version = "1.2"
    t.is_definition = False
    p = t.parameters.add()
    p.name, p.type, p.float_value = "RatedSpeed", FLOAT, rated_speed
    for name, dtype in MEMBERS:
        member = t.metrics.add()
        member.name = name
        set_value(member, dtype, values[name])


nbirth = spb.Payload(timestamp=int(time.time() * 1000), seq=0)
add_pump_definition(nbirth)

dbirth = spb.Payload(timestamp=int(time.time() * 1000), seq=1)
add_pump_instance(dbirth, "CoolingPump1", 20, 2900.0,
                  {"Running": True, "Speed": 2875.5,
                   "DischargePressure": 3.4, "StartCount": 1287})

print(len(nbirth.SerializeToString()), "byte NBIRTH,",
      len(dbirth.SerializeToString()), "byte DBIRTH")

Dans un vrai edge node, le NBIRTH contient aussi bdSeq et Node Control/Rebirth, comme le montre certificats birth et death Sparkplug. Publiez ces payloads sur spBv1.0/{group}/NBIRTH/{node} et spBv1.0/{group}/DBIRTH/{node}/{device}.

Mettre à jour les valeurs d'un template en cours d'exécution

Les births transportent des instances complètes, mais les messages de données doivent rester légers. Les plateformes diffèrent dans leur manière de signaler les changements d'un membre de template. Certaines renvoient la métrique d'instance dans NDATA ou DDATA en n'y incluant que les membres modifiés. D'autres exposent chaque membre comme une métrique distincte avec son propre alias après le birth, si bien qu'un changement de vitesse voyage sous forme d'une seule valeur scalaire. Les deux approches s'appuient sur le birth pour établir noms, types et alias : c'est pourquoi un hôte qui a manqué le birth ne peut pas non plus interpréter les mises à jour de templates.

Avant de vous engager sur une conception, publiez un birth et quelques messages de données depuis votre plateforme edge et examinez le résultat décodé. Vérifiez que votre application hôte met à jour le bon membre de l'instance, que les membres inchangés conservent leurs valeurs et qu'un rebirth restaure l'instance complète. Le faire avec deux ou trois pompes dans un groupe de test prend quelques minutes et évite de découvrir une incohérence après avoir configuré des centaines d'actifs.

Imbrication et composition

Une métrique membre d'un template peut elle-même être un template. Un template Skid peut contenir deux instances de Pump, une instance de Tank et quelques métriques scalaires. La composition garde les modèles lisibles et permet de réutiliser de petits types bien testés.

Limitez la profondeur d'imbrication. Chaque hôte doit résoudre chaque niveau, et des hiérarchies profondes alourdissent les births. La taille des births compte sur une infrastructure partagée : le serveur MQTT public gratuit accepte des messages jusqu'à 64 Ko, et chaque offre a sa propre limite de taille de message. Si un nœud modélise des centaines d'actifs, vérifiez tôt la taille du birth.

Garder des templates cohérents entre edge nodes

Les templates ne sont rentables que si chaque edge node utilise la même définition. En pratique, des divergences s'installent lorsque les nœuds sont configurés par des personnes différentes ou mis à jour à des moments différents. Ces habitudes les évitent :

  1. Conservez une bibliothèque centrale de définitions sous contrôle de version, et générez la configuration des edge nodes à partir d'elle.
  2. Renseignez le champ version et incrémentez-le à chaque modification des membres, des types ou des paramètres.
  3. Ne changez jamais le type d'un membre sur place ; ajoutez un nouveau membre ou une nouvelle version.
  4. Utilisez partout le même nom de définition, casse comprise.
  5. Confiez les différences propres à chaque actif aux paramètres, pas à des membres supplémentaires.
  6. Après le déploiement, comparez les définitions décodées du NBIRTH de chaque nœud avec la bibliothèque.
  7. Déployez les nouvelles versions nœud par nœud et vérifiez que l'hôte accepte les deux pendant la transition.

C'est à l'étape 6 qu'une vue décodée est utile. ConnectMQ décode Sparkplug B dans l'explorateur de topics de son portail : vous pouvez ouvrir le NBIRTH de chaque nœud et comparer les définitions sans écrire de script. Notez qu'il affiche les births au moment où ils sont publiés ; si un nœud est déjà en ligne, demandez un rebirth pour les voir.

Problèmes courants

Symptôme Cause probable Solution
L'hôte affiche les membres de l'instance comme inconnus Définition absente du NBIRTH Publier les définitions dans le NBIRTH avant les instances
Instance rejetée ou partiellement affichée template_ref ne correspond pas au nom de la définition Nom exact, sensible à la casse
Un même type se comporte différemment selon le nœud Définitions divergentes entre les nœuds Bibliothèque centrale et contrôle des versions
Births trop volumineux Nombreuses instances profondément imbriquées Aplatir, répartir sur plusieurs devices ou vérifier les limites de l'offre
Certains consommateurs ignorent les templates L'outil ne prend pas en charge le type 19 Utiliser un hôte compatible templates, ou aplatir pour ce consommateur

Templates, ISA-95 et Unified Namespace

Les templates modélisent ce qu'est un équipement ; ISA-95 modélise où il se trouve. Les deux se complètent : un type Pump, instancié sous un site, une zone et une ligne. ConnectMQ peut republier les données Sparkplug dans des topics ISA-95 comme connectmq/factory1/production/line1/cnc1/telemetry, ce qui offre aux consommateurs non Sparkplug une vue lisible fondée sur l'emplacement. Pour en savoir plus sur la structuration des données d'usine, consultez MQTT, Sparkplug B et le Unified Namespace, la référence des types de données Sparkplug B et le guide de référence sur l'IoT industriel avec MQTT.

Démarrer avec ConnectMQ

Exécutez vos edge nodes à base de templates sur un broker MQTT managé sans gérer vous-même l'infrastructure, ou prototypez d'abord sur le serveur MQTT public gratuit avec un group ID aléatoire, réservé aux tests et jamais aux données de production. Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire, et inspectez vos définitions et instances de templates décodées dans le portail.

Questions fréquentes

Les templates Sparkplug sont-ils équivalents aux UDT des automates ?

Ils remplissent le même rôle : un type réutilisable avec des membres nommés et typés. De nombreuses plateformes edge associent directement les UDT d'automates ou de SCADA à des templates Sparkplug.

Où les définitions de templates doivent-elles être publiées ?

Dans le NBIRTH, avant toute instance qui y fait référence. Les instances peuvent ensuite apparaître dans le NBIRTH ou dans des messages DBIRTH.

À quoi servent les paramètres de template ?

Les paramètres contiennent des constantes propres à chaque instance, comme la vitesse nominale, des limites ou des données de plaque signalétique. La définition fournit des valeurs par défaut et chaque instance peut les surcharger.

Toutes les applications hôtes Sparkplug prennent-elles en charge les templates ?

Non. La prise en charge varie : vérifiez votre hôte avant de tout modéliser en templates. Pour les consommateurs qui ne les gèrent pas, aplatissez les membres en métriques ordinaires ou utilisez une vue ISA-95 republiée et lisible.

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.