Un payload Sparkplug B es un mensaje codificado en Protobuf que transporta una marca de tiempo, un número de secuencia y una lista de métricas tipadas. Al terminar esta guía sabrás qué significa cada campo, por qué los bytes en bruto resultan ilegibles en un cliente MQTT corriente y cómo inspeccionar payloads rápidamente durante la puesta en marcha o la depuración de un edge node.
Por qué los payloads Sparkplug B parecen un galimatías
Si te suscribes a spBv1.0/# con una herramienta genérica como mosquitto_sub, verás nombres de tags legibles rodeados de caracteres extraños. No se trata de datos corruptos. Sparkplug B utiliza Google Protocol Buffers, un formato de serialización binario, de modo que los números de campo, las longitudes y los valores numéricos se escriben como varints compactos y bytes de ancho fijo en lugar de texto.
Es una decisión deliberada. Las redes industriales suelen funcionar sobre enlaces celulares, backhaul satelital o Ethernet de planta congestionada, y un gateway puede publicar miles de tags. Una codificación binaria mantiene los mensajes pequeños, conserva los tipos numéricos exactos (un contador sin signo de 64 bits sigue siendo un contador sin signo de 64 bits) y ofrece a todos los consumidores el mismo esquema. El precio es que necesitas el esquema, el archivo sparkplug_b.proto, para convertir los bytes de nuevo en algo legible.
Pruébalo tú mismo con un suscriptor genérico:
mosquitto_sub -h broker.connectmq.com -p 1883 -i payload-viewer-7f3a -t "spBv1.0/demo-7f3a/#" -v
Todo lo que publique un edge node Sparkplug en ese grupo se mostrará como texto parcialmente binario. Para interpretarlo, necesitas entender la estructura subyacente.
La estructura del payload Sparkplug B
El esquema se encuentra en el proyecto Eclipse Tahu como sparkplug_b.proto. En el nivel superior hay un único mensaje Payload:
message Payload {
optional uint64 timestamp = 1; // ms desde la época Unix, UTC
repeated Metric metrics = 2; // los datos propiamente dichos
optional uint64 seq = 3; // 0-255, vuelve a empezar
optional string uuid = 4; // identificador de esquema opcional
optional bytes body = 5; // bytes opacos opcionales
}
| Campo | Tipo | Finalidad | Notas |
|---|---|---|---|
| timestamp | uint64 | Momento en que se creó el payload | Milisegundos desde la época Unix en UTC |
| metrics | repeated Metric | Los valores de tags que se reportan | Puede contener una métrica o miles |
| seq | uint64 | Número de secuencia del mensaje | De 0 a 255 y luego vuelve a 0 |
| uuid | string | Identificador opcional del esquema del payload | Rara vez se usa en la práctica |
| body | bytes | Bytes opcionales específicos de la aplicación | Sparkplug no los interpreta |
El campo seq es lo que permite a una aplicación host detectar mensajes perdidos. El NBIRTH empieza en 0 y cada mensaje posterior del mismo edge node lo incrementa en uno. Un salto significa que algo se perdió, lo que normalmente desencadena una solicitud de rebirth. Ese flujo de recuperación se denomina rebirth.
Dentro de una métrica
La mayor parte de los datos interesantes está en el mensaje Metric. Cada métrica es un único valor con nombre y metadatos opcionales:
message Metric {
optional string name = 1;
optional uint64 alias = 2;
optional uint64 timestamp = 3;
optional uint32 datatype = 4;
optional bool is_historical = 5;
optional bool is_transient = 6;
optional bool is_null = 7;
optional MetaData metadata = 8;
optional PropertySet properties = 9;
oneof value {
uint32 int_value = 10;
uint64 long_value = 11;
float float_value = 12;
double double_value = 13;
bool boolean_value = 14;
string string_value = 15;
bytes bytes_value = 16;
DataSet dataset_value = 17;
Template template_value = 18;
MetricValueExtension extension_value = 19;
}
}
Algunos puntos que suelen confundir:
- name frente a alias. Los mensajes de birth deben incluir el nombre completo de la métrica, como
Line1/Spindle/Speed. Si el edge node asigna un alias, los mensajes NDATA y DDATA posteriores pueden enviar solo el alias numérico para ahorrar bytes. Un decodificador que no haya visto el birth no puede traducir el alias de vuelta a un nombre. - datatype es un número. El campo
datatypees un código entero, como 3 para Int32, 9 para Float o 12 para String. Indica cómo interpretar el campo de valor. La lista completa está en nuestra referencia de tipos de datos de Sparkplug B. - El campo de valor depende del tipo. De Int8 a UInt32 viajan en
int_value; Int64, UInt64 y DateTime enlong_value. Los valores con signo en un campo sin signo se codifican en complemento a dos, así que un decodificador tiene que consultardatatypepara recuperar correctamente un número negativo. - is_null es explícito. Una métrica puede existir sin valor actual. En lugar de enviar cero, el nodo pone
is_nulla true, algo importante para los consumidores que tienen en cuenta la calidad del dato. - is_historical e is_transient. Las métricas históricas transportan datos de relleno (backfill) que no deben sobrescribir el valor en vivo. Las métricas transitorias deben mostrarse, pero un historian no debe almacenarlas.
Un ejemplo decodificado
Así se ve un payload DDATA típico de una máquina CNC tras decodificarlo, representado como JSON para facilitar la lectura:
{
"timestamp": 1792137600123,
"seq": 42,
"metrics": [
{ "alias": 3, "timestamp": 1792137600120, "datatype": 9, "floatValue": 1487.5 },
{ "alias": 4, "timestamp": 1792137600120, "datatype": 11, "booleanValue": true },
{ "alias": 7, "timestamp": 1792137600121, "datatype": 3, "intValue": 4294967291 }
]
}
Fíjate en dos detalles. Primero, las métricas tienen alias pero no nombres, así que necesitas el DBIRTH para saber que el alias 3 es la velocidad del husillo. Segundo, la métrica Int32 muestra 4294967291 en el campo sin signo en bruto. Interpretado como entero de 32 bits con signo, es -5. Este es justo el tipo de cosa que un decodificador ingenuo interpreta mal.
El DBIRTH correspondiente contendría las definiciones completas:
{
"timestamp": 1792137590000,
"seq": 1,
"metrics": [
{ "name": "Spindle/Speed", "alias": 3, "datatype": 9, "floatValue": 0.0 },
{ "name": "Spindle/Running", "alias": 4, "datatype": 11, "booleanValue": false },
{ "name": "Axis/X/Offset", "alias": 7, "datatype": 3, "intValue": 0 }
]
}
Propiedades, DataSets y Templates
Más allá de los escalares simples, el payload Sparkplug B puede transportar estructuras más ricas:
- PropertySet. Una lista de claves y valores tipados asociada a una métrica. La conocida propiedad
Qualityusa 192 para bueno, 0 para malo y 500 para obsoleto (stale). También se pueden adjuntar como propiedades unidades de ingeniería, rangos y descripciones. - DataSet. Una pequeña tabla con nombres de columna, tipos de columna y filas. Útil para parámetros de receta o un lote de lecturas.
- Template. Un tipo definido por el usuario, similar a un UDT en un PLC. La definición de un template se declara una vez en el NBIRTH y las instancias hacen referencia a ella. Los templates son la forma en que Sparkplug modela bombas, motores y otros equipos repetidos.
- MetaData. Información para métricas de bytes y de archivo, como tipo de contenido, tamaño, MD5 y nombre de archivo.
La mayoría de los sistemas en producción usan escalares con una propiedad Quality. Los DataSets y los templates son potentes pero añaden complejidad, así que introdúcelos solo cuando una lista plana de métricas se vuelva difícil de gestionar.
Cómo leer payloads Sparkplug B en la práctica
Tienes tres opciones prácticas para convertir datos binarios de Sparkplug en algo legible.
Decodificar con tu propio código
Compila sparkplug_b.proto para tu lenguaje y analiza cada mensaje. Es la opción adecuada para consumidores en producción, y en Python son apenas unas líneas. Nuestro tutorial sobre cómo decodificar Sparkplug B en Python recorre un suscriptor completo, incluida la resolución de alias y el tratamiento de enteros con signo.
Usar las bibliotecas de referencia de Tahu
El proyecto Eclipse Tahu ofrece el archivo proto canónico e implementaciones de referencia en varios lenguajes. Son un buen punto de partida cuando construyes un edge node o una aplicación host y quieres un comportamiento acorde con la especificación.
Usar un broker que decodifique por ti
Durante la puesta en marcha no quieres escribir código solo para comprobar si un tag está publicando. ConnectMQ detecta los topics Sparkplug B, decodifica payloads Protobuf (y Sparkplug codificado en JSON) y los muestra de forma legible en el explorador de topics del portal. También puede republicar datos Sparkplug en topics ISA-95, de modo que spBv1.0/factory1/DDATA/line1/cnc1 queda disponible como connectmq/factory1/production/line1/cnc1/telemetry para herramientas que no hablan Protobuf. Si alojas tu propio broker, necesitarías un servicio de decodificación aparte para obtener la misma vista.
Errores habituales con el payload
| Síntoma | Causa probable | Solución |
|---|---|---|
| Las métricas muestran números en lugar de nombres | El decodificador no recibió el mensaje de birth | Solicita un rebirth o arranca el consumidor antes que el nodo |
| Los valores negativos aparecen como números enormes | Tipo con signo leído desde un campo sin signo | Aplica complemento a dos según datatype |
| Las marcas de tiempo parecen del año 50000 | Confusión entre segundos y milisegundos | Las marcas de tiempo de Sparkplug siempre están en milisegundos |
| DecodeError en el parser | El payload no es Sparkplug B, o la versión del proto es incorrecta | Comprueba que el topic empieza por spBv1.0 y usa el proto de Tahu |
| Seq salta de forma inesperada | Mensajes perdidos o dos nodos con el mismo ID | Asegura IDs de edge node únicos y usa el QoS adecuado |
La mayoría de estos problemas aparecen durante la puesta en marcha. Tener abierta una vista decodificada en vivo mientras levantas un nuevo gateway ahorra muchas conjeturas.
Cómo encaja el payload en el panorama general
El payload es solo la mitad de Sparkplug. La otra mitad es el namespace de topics de Sparkplug y las reglas de estado construidas en torno a los certificados de birth y death. Juntos hacen que los datos sean autodescriptivos y conscientes del estado, y por eso Sparkplug es tan popular como transporte para un Unified Namespace. Para la visión de arquitectura, lee MQTT, Sparkplug B y el Unified Namespace y nuestra guía principal sobre IoT industrial con MQTT.
Cualquier broker MQTT que cumpla el estándar puede transportar Sparkplug B, porque el broker nunca necesita analizar el payload para enrutarlo. Lo que aporta un broker compatible con Sparkplug es visibilidad: vistas decodificadas, republicación legible y detección de la estructura de topics, que hacen los datos binarios accesibles para todo el equipo.
Empieza con ConnectMQ
Apunta un edge node o simulador Sparkplug al servidor MQTT público gratuito con un group ID único y pasa después a tu propio broker MQTT gestionado cuando necesites credenciales y aislamiento. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, y observa tus payloads Sparkplug B decodificados en vivo en el explorador de topics de ConnectMQ.
Preguntas frecuentes
¿Un payload Sparkplug B es siempre Protobuf?
La especificación define Protobuf como la codificación de Sparkplug B. Algunas herramientas también generan una representación JSON de la misma estructura para depuración o integración, y ConnectMQ puede decodificar ambas formas.
¿Por qué mis métricas tienen alias pero no nombres?
El edge node envió los nombres completos solo en su certificado de birth y después usa alias numéricos para ahorrar ancho de banda. Tu consumidor debe guardar la correspondencia entre nombre y alias del NBIRTH o DBIRTH, o solicitar un rebirth para obtenerla de nuevo.
¿Cuál es el tamaño máximo de un payload Sparkplug B?
Sparkplug en sí no fija un límite pequeño, pero tu broker sí. En el broker público de ConnectMQ los mensajes están limitados a 64 KB, y los planes Serverless permiten 256 KB (gratuito) o 1 MB (de pago).
¿Necesito el archivo proto para leer datos Sparkplug?
Sí, salvo que una herramienta los decodifique por ti. El archivo sparkplug_b.proto de Eclipse Tahu es el esquema canónico, y todos los decodificadores de Sparkplug se basan en él.



