Industrial IoT

Sparkplug Templates und UDTs einfach erklärt

Sparkplug Templates bringen benutzerdefinierte Typen im SPS-Stil zu MQTT. Dieser Leitfaden erklärt Template-Definitionen und -Instanzen, Parameter, Verschachtelung und Versionierung, mit Python-Code für ein Pumpen-Template und Tipps für konsistente Modelle über alle Edge Nodes hinweg.

Diagramm zu Sparkplug Templates mit einer Pumpendefinition und mehreren Pumpeninstanzen, die von Edge Nodes veröffentlicht werden
Probieren Sie es auf Ihrem eigenen MQTT-Broker ausHolen Sie sich im Free-Tarif einen privaten, verwalteten MQTT-Broker und starten Sie mit fertigen Codebeispielen.
Kostenlos testen Codebeispiele Keine Kreditkarte erforderlich

Sparkplug Templates sind der Weg von Sparkplug B, wiederverwendbare Anlagentypen zu definieren, das MQTT-Gegenstück zu einem benutzerdefinierten Datentyp (UDT) in einer SPS oder einem SCADA-System, vergleichbar mit einem PLC-Datentyp in TIA Portal oder einem Objekttyp in OPC UA. In diesem Leitfaden erfahren Sie, wie Template-Definitionen und -Instanzen funktionieren, wie Parameter, Verschachtelung und Versionen hineinpassen, wie Sie ein Pumpen-Template in Python bauen und wie Sie dasselbe Modell über viele Edge Nodes hinweg konsistent halten.

Warum es Templates gibt

Ohne Templates ist eine Pumpe nur eine Menge lose zusammenhängender Metriken: Pump1/Speed, Pump1/Running, Pump1/Pressure. Eine zweite Pumpe wiederholt dieselben Namen mit anderem Präfix, und nichts teilt der Host-Anwendung mit, dass beides Pumpen sind. Nennt ein Edge Node die Metrik Speed und ein anderer RPM, muss jeder Konsument diesen Unterschied kennen.

Templates lösen das, indem sie den Typ von der Instanz trennen. Sie definieren eine Pump einmal mit ihren Member-Metriken, Datentypen und Standardwerten. Jede physische Pumpe ist dann eine Instanz, die auf die Definition verweist. Eine Host-Anwendung, die Templates versteht, kann automatisch passende Objekte anlegen, auf jede Pumpe dieselben Anzeigen und Alarme anwenden und erkennen, wenn eine Instanz nicht zu ihrem Typ passt.

Definitionen und Instanzen

Sowohl Definitionen als auch Instanzen sind Metriken mit dem Datentyp 19 (Template), deren Wert eine Template-Nachricht ist:

Template-Feld Zweck In einer Definition In einer Instanz
version Optionaler Versions-String Empfohlen Optional
metrics Member-Metriken Member mit Datentypen und Standardwerten Member mit aktuellen Werten
parameters Benannte, typisierte Konstanten Mit Standardwerten deklariert Pro Instanz überschrieben
template_ref Name der verwendeten Definition Nicht gesetzt Pflicht, verweist auf die Definition
is_definition Kennzeichnet eine Definition true false

Wo Definitionen stehen

Template-Definitionen werden im NBIRTH veröffentlicht, vor jeder Instanz, die sie nutzt. In Datennachrichten werden sie nicht wiederholt. Manche Plattformen stellen Definitionsnamen einen Ordner wie _types_/ voran, um Typen von Live-Tags zu trennen. Das ist eine Plattformkonvention, keine Vorgabe; richten Sie sich also danach, was Ihre Host-Anwendung erwartet.

Wo Instanzen stehen

Instanzen können im NBIRTH (Anlagen auf Node-Ebene) oder in einem DBIRTH (Anlagen hinter einem Device) erscheinen. Jede Instanz enthält im Birth den vollständigen Satz an Member-Metriken mit aktuellen Werten. Datennachrichten übertragen danach die Änderungen.

Ein dekodiertes Beispiel

So sieht eine Pumpendefinition in einem NBIRTH nach dem Dekodieren aus:

{
  "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" }
    ]
  }
}

Und eine Instanz davon in einem 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" }
    ]
  }
}

Die Instanz überschreibt den Parameter RatedSpeed, weil diese Pumpe einen anderen Motor hat. Parameter eignen sich ideal für Typenschilddaten und Grenzwerte, die sich je Anlage unterscheiden, sich zur Laufzeit aber nicht ändern.

Ein Template in Python bauen

Dieses Snippet erstellt die Definition und eine Instanz mit Klassen, die aus der Datei sparkplug_b.proto von Eclipse Tahu generiert wurden. Den einmaligen Schritt der Codegenerierung zeigt unser Tutorial zum Dekodieren von Sparkplug B in Python.

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")

In einem echten Edge Node enthält das NBIRTH außerdem bdSeq und Node Control/Rebirth, wie in Sparkplug Birth- und Death-Zertifikate gezeigt. Veröffentlichen Sie diese Payloads auf spBv1.0/{group}/NBIRTH/{node} und spBv1.0/{group}/DBIRTH/{node}/{device}.

Template-Werte zur Laufzeit aktualisieren

Births enthalten vollständige Instanzen, Datennachrichten sollten aber klein bleiben. Plattformen unterscheiden sich darin, wie sie Änderungen an einem Template-Member melden. Manche senden die Instanz-Metrik in NDATA oder DDATA erneut und nehmen nur die geänderten Member auf. Andere stellen jeden Member nach dem Birth als eigene Metrik mit Alias bereit, sodass eine Drehzahländerung als einzelner Skalarwert übertragen wird. Beide Ansätze verlassen sich darauf, dass das Birth Namen, Datentypen und Aliase festlegt. Deshalb kann ein Host, der das Birth verpasst, auch Template-Aktualisierungen nicht interpretieren.

Bevor Sie sich auf ein Design festlegen, veröffentlichen Sie ein Birth und einige Datennachrichten von Ihrer Edge-Plattform und sehen sich das dekodierte Ergebnis an. Prüfen Sie, ob Ihre Host-Anwendung den richtigen Instanz-Member aktualisiert, ob unveränderte Member ihre Werte behalten und ob ein Rebirth die vollständige Instanz wiederherstellt. Mit zwei oder drei Pumpen in einer Testgruppe dauert das Minuten und erspart Ihnen, eine Abweichung erst nach der Konfiguration Hunderter Anlagen zu entdecken.

Verschachtelung und Komposition

Eine Member-Metrik eines Templates kann selbst ein Template sein. Ein Skid-Template könnte zwei Pump-Instanzen, eine Tank-Instanz und einige skalare Metriken enthalten. Komposition hält Modelle lesbar und erlaubt es, kleine, gut getestete Typen wiederzuverwenden.

Halten Sie die Verschachtelung flach. Jeder Host muss jede Ebene auflösen, und tiefe Hierarchien machen Births groß. Große Births zählen auf geteilter Infrastruktur: Der öffentliche MQTT-Broker akzeptiert Nachrichten bis 64 KB, und jeder Plan hat ein eigenes Größenlimit für Nachrichten. Modelliert ein Node Hunderte von Anlagen, prüfen Sie die Birth-Größe frühzeitig.

Templates über Edge Nodes hinweg konsistent halten

Templates zahlen sich nur aus, wenn jeder Edge Node dieselbe Definition verwendet. In der Praxis schleichen sich Abweichungen ein, wenn Nodes von verschiedenen Personen konfiguriert oder zu unterschiedlichen Zeiten aktualisiert werden. Diese Gewohnheiten verhindern das:

  1. Führen Sie eine zentrale Bibliothek von Definitionen unter Versionskontrolle und generieren Sie daraus die Edge-Node-Konfiguration.
  2. Setzen Sie das Feld version und erhöhen Sie es bei jeder Änderung an Membern, Datentypen oder Parametern.
  3. Ändern Sie nie den Datentyp eines Members an Ort und Stelle; fügen Sie einen neuen Member oder eine neue Version hinzu.
  4. Verwenden Sie überall denselben Definitionsnamen, einschließlich Groß- und Kleinschreibung.
  5. Bilden Sie Unterschiede zwischen Anlagen über Parameter ab, nicht über zusätzliche Member.
  6. Vergleichen Sie nach dem Deployment die dekodierten NBIRTH-Definitionen jedes Nodes mit der Bibliothek.
  7. Rollen Sie neue Versionen Node für Node aus und bestätigen Sie, dass der Host während des Übergangs beide akzeptiert.

Bei Schritt 6 hilft eine dekodierte Ansicht. ConnectMQ dekodiert Sparkplug B im Topic-Explorer des Portals, sodass Sie das NBIRTH jedes Nodes öffnen und Definitionen vergleichen können, ohne ein Skript zu schreiben. Beachten Sie, dass Births angezeigt werden, wenn sie veröffentlicht werden; ist ein Node bereits online, fordern Sie ein Rebirth an, um sie zu sehen.

Häufige Probleme

Symptom Wahrscheinliche Ursache Lösung
Host zeigt Instanz-Member als unbekannt an Definition fehlt im NBIRTH Definitionen im NBIRTH vor den Instanzen veröffentlichen
Instanz abgelehnt oder nur teilweise angezeigt template_ref passt nicht zum Definitionsnamen Exakter Name, Groß-/Kleinschreibung beachten
Derselbe Typ verhält sich je Node anders Definitionen sind zwischen Nodes auseinandergedriftet Zentrale Bibliothek und Versionsprüfungen
Births zu groß Viele tief verschachtelte Instanzen Abflachen, Devices aufteilen oder Plan-Limits prüfen
Manche Konsumenten ignorieren Templates Werkzeug unterstützt Datentyp 19 nicht Einen Host mit Template-Unterstützung nutzen oder für diesen Konsumenten abflachen

Templates, ISA-95 und der Unified Namespace (UNS)

Templates modellieren, was eine Anlage ist; ISA-95 modelliert, wo sie steht. Beides ergänzt sich: ein Pump-Typ, instanziiert unter Standort, Bereich und Linie. Der Ort, an dem beides zusammenkommt, ist der UNS: Die ISA-95-Equipment-Hierarchie (Enterprise → Site → Area → Line → Cell) wird zur Topic-Struktur auf dem MQTT-Broker, etwa acme/werk-ludwigshafen/kuehlung/linie-1/kuehlpumpe-1/drehzahl, und jede Pumpe im Baum trägt dieselben Member, weil sie aus derselben Template-Definition stammt. So finden MES, Instandhaltung und Predictive-Maintenance-Modelle jede Pumpe am erwarteten Ort und im erwarteten Format. ConnectMQ kann Sparkplug-Daten in ISA-95-Topics wie connectmq/factory1/production/line1/cnc1/telemetry erneut veröffentlichen und gibt Konsumenten ohne Sparkplug-Unterstützung so eine lesbare, standortbasierte Sicht. Mehr zur Strukturierung von Anlagendaten finden Sie in MQTT, Sparkplug B und der Unified Namespace, in der Referenz zu den Sparkplug B Datentypen und im Grundlagenleitfaden zu Industrial IoT mit MQTT.

Starten Sie mit ConnectMQ

Betreiben Sie Ihre Template-basierten Edge Nodes auf einem verwalteten MQTT-Broker, ohne die Infrastruktur selbst zu betreiben, oder bauen Sie zuerst einen Prototyp auf dem öffentlichen MQTT-Broker mit einer zufälligen Group ID; er ist für Tests gedacht, nicht für echte Produktionsdaten. Erstellen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker, ganz ohne Kreditkarte, und prüfen Sie Ihre Template-Definitionen und -Instanzen dekodiert im Portal.

Häufig gestellte Fragen

Sind Sparkplug Templates dasselbe wie SPS-UDTs?

Sie erfüllen denselben Zweck: ein wiederverwendbarer Typ mit benannten, typisierten Membern. Viele Edge-Plattformen bilden UDTs aus SPS oder SCADA direkt auf Sparkplug Templates ab.

Wo müssen Template-Definitionen veröffentlicht werden?

Im NBIRTH, vor jeder Instanz, die auf sie verweist. Instanzen können dann im NBIRTH oder in DBIRTH-Nachrichten erscheinen.

Wofür werden Template-Parameter verwendet?

Parameter enthalten Konstanten pro Instanz wie Nenndrehzahl, Grenzwerte oder Typenschilddaten. Die Definition liefert Standardwerte, und jede Instanz kann sie überschreiben.

Unterstützen alle Sparkplug-Host-Anwendungen Templates?

Nein. Die Unterstützung variiert, prüfen Sie Ihren Host also, bevor Sie alles als Templates modellieren. Für Konsumenten ohne Unterstützung flachen Sie Member zu regulären Metriken ab oder nutzen eine lesbare, per ISA-95 erneut veröffentlichte Ansicht.

Verwandte Artikel

Industrial DataOps: Werksdaten kontextualisieren und steuern

Was Industrial DataOps in der Praxis bedeutet: Kontextualisierung, Normalisierung, Qualitätsprüfungen und Governance von OT-Daten und wie Sie diese Schicht auf einem MQTT-Namespace betreiben.

8 Min. Lesezeit

Alle Artikel →

Ihr privater MQTT-Broker ist nur wenige Klicks entfernt

Konto anlegen, Broker-Zugangsdaten erhalten und das erste Gerät verbinden — ohne Server, die installiert, gepatcht oder skaliert werden müssen.