IoT industrial

Plantillas (templates) y UDTs de Sparkplug explicados

Las plantillas Sparkplug llevan a MQTT los tipos definidos por el usuario al estilo de los PLC. Esta guía explica las definiciones e instancias de template, los parámetros, el anidamiento y el versionado, con código Python que construye una plantilla de bomba y consejos para mantener la coherencia de los modelos entre edge nodes.

Diagrama de plantillas Sparkplug con una definición de bomba y varias instancias de bomba publicadas por edge nodes
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Las plantillas Sparkplug (templates) son la forma que tiene Sparkplug B de definir tipos de equipo reutilizables, el equivalente en MQTT de un tipo definido por el usuario (UDT) en un PLC o un sistema SCADA. En esta guía aprenderás cómo funcionan las definiciones e instancias de template, cómo encajan los parámetros, el anidamiento y las versiones, cómo construir una plantilla de bomba en Python y cómo mantener el mismo modelo coherente en muchos edge nodes.

Por qué existen las plantillas

Sin plantillas, una bomba no es más que un conjunto de métricas vagamente relacionadas: Pump1/Speed, Pump1/Running, Pump1/Pressure. Una segunda bomba repite los mismos nombres con otro prefijo, y nada le indica a la aplicación host que ambas son bombas. Si un edge node llama a la métrica Speed y otro la llama RPM, cada consumidor tiene que conocer esa diferencia.

Las plantillas lo resuelven separando el tipo de la instancia. Defines una Pump una sola vez con sus métricas miembro, tipos de datos y valores por defecto. Cada bomba física es entonces una instancia que hace referencia a la definición. Una aplicación host que entiende las plantillas puede crear automáticamente los objetos correspondientes, aplicar las mismas pantallas y alarmas a todas las bombas y detectar cuándo una instancia no coincide con su tipo.

Definiciones e instancias

Tanto las definiciones como las instancias son métricas con tipo de datos 19 (Template) cuyo valor es un mensaje Template:

Campo del template Finalidad En una definición En una instancia
version Cadena de versión opcional Recomendado Opcional
metrics Métricas miembro Miembros con tipos de datos y valores por defecto Miembros con valores actuales
parameters Constantes con nombre y tipo Declarados con valores por defecto Sobrescritos por instancia
template_ref Nombre de la definición utilizada No se establece Obligatorio, apunta a la definición
is_definition Marca una definición true false

Dónde viven las definiciones

Las definiciones de template se publican en el NBIRTH, antes de cualquier instancia que las use. No se repiten en los mensajes de datos. Algunas plataformas anteponen a los nombres de definición una carpeta como _types_/ para separar los tipos de los tags en vivo; es una convención de la plataforma, no un requisito, así que sigue lo que espere tu aplicación host.

Dónde viven las instancias

Las instancias pueden aparecer en el NBIRTH (equipos a nivel de nodo) o en un DBIRTH (equipos detrás de un dispositivo). Cada instancia lleva en el birth el conjunto completo de métricas miembro con sus valores actuales. Después, los mensajes de datos transportan los cambios.

Un ejemplo decodificado

Esta es una definición de bomba tal como aparece en un NBIRTH tras decodificarla:

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

Y una instancia de ella en 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" }
    ]
  }
}

La instancia sobrescribe el parámetro RatedSpeed porque esta bomba tiene un motor distinto. Los parámetros son ideales para datos de placa y límites que difieren por activo pero no cambian en tiempo de ejecución.

Construir una plantilla en Python

Este fragmento construye la definición y una instancia usando clases generadas a partir del archivo sparkplug_b.proto de Eclipse Tahu. Nuestro tutorial sobre cómo decodificar Sparkplug B en Python muestra el paso único de generación de código.

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

En un edge node real, el NBIRTH también contiene bdSeq y Node Control/Rebirth, como se muestra en certificados birth y death de Sparkplug. Publica estos payloads en spBv1.0/{group}/NBIRTH/{node} y spBv1.0/{group}/DBIRTH/{node}/{device}.

Actualizar valores de plantillas en tiempo de ejecución

Los births transportan instancias completas, pero los mensajes de datos deben seguir siendo pequeños. Las plataformas difieren en cómo informan de los cambios en un miembro de un template. Algunas vuelven a enviar la métrica de la instancia en NDATA o DDATA con solo los miembros que han cambiado. Otras exponen cada miembro como su propia métrica con alias tras el birth, de modo que un cambio de velocidad viaja como un único valor escalar. Ambos enfoques dependen del birth para establecer nombres, tipos de datos y alias, y por eso un host que se pierde el birth tampoco puede interpretar las actualizaciones de templates.

Antes de comprometerte con un diseño, publica un birth y algunos mensajes de datos desde tu plataforma edge y observa el resultado decodificado. Confirma que tu aplicación host actualiza el miembro correcto de la instancia, que los miembros sin cambios conservan sus valores y que un rebirth restaura la instancia completa. Hacerlo con dos o tres bombas en un grupo de pruebas lleva minutos y evita descubrir una discrepancia después de haber configurado cientos de activos.

Anidamiento y composición

Una métrica miembro de un template puede ser a su vez un template. Un template Skid podría contener dos instancias de Pump, una instancia de Tank y algunas métricas escalares. La composición mantiene los modelos legibles y te permite reutilizar tipos pequeños y bien probados.

Mantén el anidamiento poco profundo. Cada host debe resolver cada nivel, y las jerarquías profundas hacen que los births sean grandes. Los births grandes importan en infraestructura compartida: el servidor MQTT público gratuito, pensado solo para pruebas, acepta mensajes de hasta 64 KB y cada plan tiene su propio límite de tamaño de mensaje. Si un nodo modela cientos de activos, comprueba pronto el tamaño del birth.

Mantener la coherencia de las plantillas entre edge nodes

Las plantillas solo compensan cuando todos los edge nodes usan la misma definición. En la práctica, las divergencias aparecen cuando los nodos los configuran personas distintas o se actualizan en momentos distintos. Estos hábitos lo evitan:

  1. Mantén una biblioteca central de definiciones bajo control de versiones y genera a partir de ella la configuración de los edge nodes.
  2. Rellena el campo version e increméntalo con cada cambio de miembros, tipos de datos o parámetros.
  3. No cambies nunca el tipo de datos de un miembro sobre la marcha; añade un miembro nuevo o una versión nueva.
  4. Usa el mismo nombre de definición en todas partes, incluidas mayúsculas y minúsculas.
  5. Lleva las diferencias por activo a los parámetros, no a miembros adicionales.
  6. Tras el despliegue, compara las definiciones del NBIRTH decodificado de cada nodo con la biblioteca.
  7. Despliega las versiones nuevas nodo a nodo y confirma que el host acepta ambas durante la transición.

En el paso 6 es donde ayuda una vista decodificada. ConnectMQ decodifica Sparkplug B en el explorador de topics de su portal, así que puedes abrir el NBIRTH de cada nodo y comparar definiciones sin escribir un script. Ten en cuenta que muestra los births cuando se publican; si un nodo ya está online, solicita un rebirth para verlos.

Problemas habituales

Síntoma Causa probable Solución
El host muestra los miembros de la instancia como desconocidos Falta la definición en el NBIRTH Publica las definiciones en el NBIRTH antes que las instancias
Instancia rechazada o mostrada parcialmente template_ref no coincide con el nombre de la definición Nombre exacto, distingue mayúsculas
El mismo tipo se comporta distinto en cada nodo Las definiciones han divergido entre nodos Biblioteca central y comprobación de versiones
Births demasiado grandes Muchas instancias muy anidadas Aplana, divide dispositivos o revisa los límites del plan
Algunos consumidores ignoran las plantillas La herramienta no admite el tipo de datos 19 Usa un host que admita templates o aplana para ese consumidor

Plantillas, ISA-95 y el Unified Namespace

Las plantillas modelan qué es un equipo; ISA-95 modela dónde está. Ambos se complementan: un tipo Pump, instanciado bajo planta, área y línea. ConnectMQ puede republicar datos Sparkplug en topics ISA-95 como connectmq/factory1/production/line1/cnc1/telemetry, lo que ofrece a los consumidores que no usan Sparkplug una vista legible basada en la ubicación. Para saber más sobre cómo estructurar los datos de planta, consulta MQTT, Sparkplug B y el Unified Namespace, la referencia de tipos de datos de Sparkplug B y la guía principal sobre IoT industrial con MQTT.

Empieza con ConnectMQ

Ejecuta tus edge nodes basados en plantillas en un broker MQTT gestionado sin operar tú mismo la infraestructura, o haz primero un prototipo en el servidor MQTT público gratuito con un group ID aleatorio. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, e inspecciona tus definiciones e instancias de template decodificadas en el portal.

Preguntas frecuentes

¿Las plantillas Sparkplug son lo mismo que los UDT de un PLC?

Cumplen la misma función: un tipo reutilizable con miembros con nombre y tipo. Muchas plataformas edge asignan directamente los UDT de PLC o SCADA a templates de Sparkplug.

¿Dónde deben publicarse las definiciones de template?

En el NBIRTH, antes de cualquier instancia que haga referencia a ellas. Después, las instancias pueden aparecer en el NBIRTH o en mensajes DBIRTH.

¿Para qué sirven los parámetros de un template?

Los parámetros contienen constantes por instancia, como la velocidad nominal, límites o datos de placa. La definición proporciona los valores por defecto y cada instancia puede sobrescribirlos.

¿Todas las aplicaciones host de Sparkplug admiten plantillas?

No. El soporte varía, así que comprueba tu host antes de modelarlo todo como templates. Para consumidores sin soporte, aplana los miembros en métricas normales o usa una vista legible republicada en ISA-95.

Artículos relacionados

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.