Node-RED

Node-RED Sparkplug B: publicar y consumir datos del edge

Convierte Node-RED en un edge node Sparkplug B con node-red-contrib-mqtt-sparkplug-plus: define métricas, publica NBIRTH, DBIRTH y DDATA, gestiona comandos DCMD y decodifica los payloads Protobuf en topics MQTT sencillos.

Edge node Sparkplug B en Node-RED publicando mensajes de birth y de datos de una máquina CNC en un broker MQTT
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

El soporte de Sparkplug B en Node-RED permite que un flujo low-code se comporte como un auténtico edge node industrial: anuncia sus métricas con certificados de birth, publica datos Protobuf compactos, informa de su death cuando se desconecta y acepta comandos. En este tutorial construirás un edge node Sparkplug B para una máquina CNC simulada, consumirás y decodificarás los datos en un segundo flujo y comprobarás el resultado en un broker que entiende Sparkplug. Por el camino aprenderás qué detalles de la especificación dan más problemas.

Sparkplug B en pocas palabras

Sparkplug B es una especificación de la Eclipse Foundation que funciona sobre MQTT. MQTT por sí solo no dice nada sobre la estructura de los topics ni sobre el formato del payload; Sparkplug define ambas cosas, además del estado de sesión, para que equipos de distintos fabricantes interoperen de serie con aplicaciones SCADA y MES.

Las ideas clave:

  • Namespace de topics: spBv1.0/<group_id>/<message_type>/<edge_node_id>/[<device_id>].
  • Payload: Google Protocol Buffers con una lista de métricas, cada una con nombre, tipo de dato, valor y marca de tiempo.
  • Conciencia de sesión: un edge node publica NBIRTH al conectarse y registra un NDEATH como su Last Will de MQTT. Los dispositivos que hay detrás publican DBIRTH y DDEATH.
  • Report by exception: tras el birth, los mensajes DDATA solo contienen las métricas que han cambiado.
  • Comandos: las aplicaciones envían mensajes NCMD y DCMD, incluida una petición de "Rebirth".
Mensaje Dirección Significado
NBIRTH / DBIRTH Del edge al broker Lista completa de métricas con tipos y valores actuales
NDATA / DDATA Del edge al broker Solo las métricas modificadas
NDEATH / DDEATH Del edge al broker (NDEATH vía Last Will) Nodo o dispositivo fuera de línea
NCMD / DCMD De la aplicación al edge Escribir una métrica o pedir un rebirth
STATE Primary host application Si la aplicación host está en línea

Para la gramática completa de los topics, consulta la guía del namespace de topics de Sparkplug, y para ver cómo los births y deaths mantienen la coherencia del estado, lee certificados de birth y death en Sparkplug.

Instala los nodos Sparkplug

La implementación de Sparkplug más completa para Node-RED es node-red-contrib-mqtt-sparkplug-plus. Instálala desde el gestor de paleta o desde la línea de comandos:

cd ~/.node-red
npm install node-red-contrib-mqtt-sparkplug-plus
# restart Node-RED afterwards

Añade tres nodos y un nodo de configuración:

  • mqtt sparkplug device: representa un dispositivo detrás del edge node. Gestiona por ti DBIRTH, DDATA, DDEATH y DCMD.
  • mqtt sparkplug in: se suscribe a topics Sparkplug y decodifica el payload Protobuf en un objeto JavaScript.
  • mqtt sparkplug out: publica mensajes Sparkplug en bruto cuando necesitas control total.
  • Sparkplug broker config: la conexión MQTT más el Group ID y el Edge Node ID de Sparkplug. Publica NBIRTH y registra NDEATH automáticamente.

Construye un edge node Sparkplug B en Node-RED

Paso 1: configura el broker y la identidad

Añade un nodo mqtt sparkplug device y crea una nueva configuración de broker:

  • Servidor: broker.connectmq.com, puerto 1883, con un client ID único. Es el servidor MQTT público gratuito, así que todo lo que publiques puede leerlo cualquiera; usa solo datos simulados.
  • Group ID: demo-a7f3k2. Los topics Sparkplug deben empezar por spBv1.0, así que aquí no puedes usar el prefijo habitual connectmq/demo/.... En su lugar, haz que el group ID sea único sustituyendo a7f3k2 por tu propia cadena aleatoria.
  • Edge Node ID: line1.

Después pon cnc1 como nombre del dispositivo en el nodo device. El dispositivo publicará en spBv1.0/demo-a7f3k2/DDATA/line1/cnc1.

Paso 2: define las métricas

En el nodo device, añade métricas con nombres y tipos de dato Sparkplug:

Nombre de la métrica Tipo de dato Significado
spindle/speed Int32 Velocidad del husillo en rpm
spindle/load Float Carga del husillo en porcentaje
coolant/temperature Float Temperatura del refrigerante en °C
running Boolean Máquina en marcha
partCount Int64 Contador acumulado de piezas

Declarar los tipos importa: el DBIRTH indica a cada consumidor qué esperar, y una aplicación host rechazará o malinterpretará datos que cambien de tipo más adelante. Por defecto el nodo espera a que todas las métricas hayan recibido un valor antes de publicar el DBIRTH, lo que evita un certificado de birth lleno de valores vacíos.

Paso 3: aliméntalo con datos

Un nodo inject que se repite cada 2 segundos alimenta un nodo function que simula la máquina. El nodo device espera msg.payload.metrics como un array de pares nombre-valor:

// Function node "simulate cnc1" -> mqtt sparkplug device
let parts = context.get("parts") || 0;
const running = Math.random() > 0.1;
if (running) {
    parts += 1;
}
context.set("parts", parts);

msg.payload = {
    metrics: [
        { name: "spindle/speed", value: running ? Math.round(11800 + Math.random() * 400) : 0 },
        { name: "spindle/load", value: running ? Math.round(450 + Math.random() * 200) / 10 : 0 },
        { name: "coolant/temperature", value: Math.round((21 + Math.random() * 3) * 10) / 10 },
        { name: "running", value: running },
        { name: "partCount", value: parts }
    ]
};
return msg;

Despliega. La configuración del broker publica el NBIRTH de line1, el dispositivo publica el DBIRTH de cnc1 y, a partir de ahí, solo salen las métricas modificadas en mensajes DDATA.

Paso 4: gestiona los comandos

Cuando una aplicación envía un DCMD a spBv1.0/demo-a7f3k2/DCMD/line1/cnc1, el nodo device lo emite por su salida como un mensaje con las métricas solicitadas. Conecta la salida a un nodo function que valide la petición y actúe en consecuencia, por ejemplo reiniciando el contador de piezas:

// Function node "handle DCMD" (wired from the device node output)
const metrics = (msg.payload && msg.payload.metrics) || [];
for (const m of metrics) {
    if (m.name === "partCount" && Number(m.value) === 0) {
        flow.set("cnc1_reset_requested", true);
        node.warn("Part counter reset requested");
    } else {
        node.warn("Ignored command for metric " + m.name);
    }
}
return null;

Para que el simulador respete el reinicio, lee cnc1_reset_requested del contexto del flujo en el simulador y vuelve a poner parts a cero. Las peticiones de rebirth las gestiona el propio nodo, que vuelve a publicar los certificados de birth.

Consume y decodifica Sparkplug B en Node-RED

Los payloads Sparkplug son binarios. Un nodo mqtt in normal sobre spBv1.0/# te daría un Buffer lleno de bytes Protobuf. El nodo mqtt sparkplug in los decodifica:

  1. Añade un nodo mqtt sparkplug in que use una configuración de broker aparte, con su propio client ID único.
  2. Suscríbete a spBv1.0/demo-a7f3k2/+/line1/#.
  3. Conéctalo a un nodo debug configurado para mostrar el mensaje completo.

Verás objetos con un timestamp, un número seq y un array metrics. Para que los datos sean útiles a consumidores que no hablan Sparkplug, aplánalos en un topic MQTT sencillo por métrica:

// Function node "sparkplug to plain topics"
// msg.topic: spBv1.0/<group>/<type>/<edge>/<device>
const t = msg.topic.split("/");
const type = t[2];
if (type !== "DDATA" && type !== "DBIRTH") {
    return null;
}

const group = t[1];
const edge = t[3];
const device = t[4];
const out = [];

for (const m of msg.payload.metrics || []) {
    // Sparkplug allows "/" in metric names; keep each metric to one topic level
    const metric = String(m.name).replace(/\//g, "_");
    let value = m.value;
    if (value !== null && typeof value === "object" && typeof value.toNumber === "function") {
        value = value.toNumber();       // 64-bit integers may arrive as Long objects
    }
    out.push({
        topic: `connectmq/demo/a7f3k2/${group}/${edge}/${device}/${metric}`,
        payload: { value: value, ts: Number(m.timestamp) || Date.now() },
        retain: true
    });
}
return [out];

Conéctalo a un nodo mqtt out con los campos de topic y retain vacíos. Ahora un panel, un script o una hoja de cálculo pueden suscribirse a connectmq/demo/a7f3k2/demo-a7f3k2/line1/cnc1/spindle_speed sin saber nada de Protobuf. Es la misma idea que la arquitectura Sparkplug más UNS descrita en Sparkplug B y el Unified Namespace.

Comprueba los datos en un broker que entiende Sparkplug

Los nodos debug demuestran que Node-RED puede decodificar sus propios mensajes, pero vale la pena comprobarlo con una herramienta independiente. ConnectMQ decodifica payloads Sparkplug B, tanto Protobuf como JSON, así que en el portal ves las métricas de cada mensaje DBIRTH y DDATA en lugar de bytes en bruto. También puede republicar los datos Sparkplug en topics ISA-95; por ejemplo, spBv1.0/factory1/DDATA/line1/cnc1 se convierte en connectmq/factory1/production/line1/cnc1/telemetry, lo que te da el paso de aplanado anterior sin tener que mantener tú el nodo function.

Para probarlo, crea un broker gratuito en el portal de ConnectMQ y cambia la configuración del broker Sparkplug en Node-RED al host de ese broker, puerto 8883 con TLS, y al usuario, la contraseña y el client ID generados. Después abre el explorador de topics en vivo y observa cómo llegan decodificados los births y los datos.

Errores habituales con Sparkplug

  1. Reutilizar client IDs. Dos edge nodes con el mismo client ID de MQTT se expulsan mutuamente una y otra vez, y cada reconexión produce un nuevo NDEATH y NBIRTH. Cada edge node necesita un client ID único.
  2. Cambiar el tipo de las métricas. Una métrica declarada como Int32 no debe transportar más tarde un float. Corrige la definición y fuerza un rebirth.
  3. Consumidores sin births. Un consumidor que arranca después del birth solo ve DDATA con las métricas modificadas. Debería enviar un NCMD de Rebirth, o leer el estado retenido en otro lugar, antes de fiarse de su visión.
  4. Ignorar los números de secuencia. El campo seq va de 0 a 255 y vuelve a empezar. Un hueco significa que se perdió un mensaje y que conviene pedir un rebirth.
  5. Niveles de topic. Los IDs de grupo, edge y dispositivo son niveles de topic individuales y no deben contener /, + ni #.
  6. Expectativas de QoS. Los mensajes de datos suelen usar QoS 0, mientras que NDEATH y STATE usan QoS 1. Asegúrate de que el plan de tu broker admite QoS 1.

Del piloto a producción

Una arquitectura Sparkplug concentra en el broker todos los edge nodes, aplicaciones host e historiadores, de modo que el broker se convierte en infraestructura crítica. Usa conexiones autenticadas sobre TLS, client IDs únicos vinculados a credenciales y un broker que siga siendo accesible tanto desde la planta como desde la nube. Un broker MQTT en la nube se adapta a despliegues multiplanta, por ejemplo en Querétaro, Santiago y Bilbao, y un broker MQTT gestionado elimina la carga operativa de mantenerlo tú mismo. Para alimentar Sparkplug desde controladores existentes, combina este flujo con Node-RED y OPC UA como fuente de datos. Si eres nuevo con los nodos MQTT, empieza por el tutorial de Node-RED y MQTT.

Ejecuta tus edge nodes Sparkplug en ConnectMQ

Regístrate en app.connectmq.com con el plan gratuito Serverless, sin tarjeta de crédito. Crea un broker, apunta a él tu configuración Sparkplug de Node-RED con las credenciales generadas e inspecciona en el portal, en cuestión de minutos, los births, los datos y los deaths decodificados.

Preguntas frecuentes

¿Qué paquete de Node-RED admite Sparkplug B?

node-red-contrib-mqtt-sparkplug-plus es la opción más completa. Gestiona por ti los births, los deaths, los números de secuencia, las peticiones de rebirth y la codificación y decodificación Protobuf.

¿Puedo leer mensajes Sparkplug B con un nodo mqtt in normal?

Recibirás los bytes Protobuf en bruto como un Buffer. Usa el nodo mqtt sparkplug in, o un decodificador Protobuf en un nodo function, para convertirlos en métricas legibles.

¿Envía Node-RED el NDEATH automáticamente?

Sí. La configuración del broker Sparkplug registra el NDEATH como Last Will de MQTT al conectarse, de modo que el broker lo publica si el edge node se desconecta de forma inesperada.

¿Por qué solo aparecen algunas métricas en mis mensajes DDATA?

Sparkplug informa por excepción: DDATA solo lleva las métricas que han cambiado. La lista completa y los valores actuales están en el DBIRTH, así que los consumidores deben conservar el birth para interpretar los datos posteriores.

Artículos relacionados

Cliente OPC UA en Node-RED hacia MQTT con topics ISA-95

Usa node-red-contrib-opcua para suscribirte a variables OPC UA de un PLC o de un servidor de simulación, asignar los node IDs a topics MQTT de estilo ISA-95 y publicar los valores con calidad y marcas de tiempo.

10 min de lectura

Node-RED Dashboard 2.0 con MQTT: indicadores, gráficos y controles

Un tutorial práctico de Node-RED Dashboard 2.0: suscríbete a telemetría MQTT en directo, muéstrala en indicadores y en un gráfico de líneas, y controla un dispositivo con un interruptor que publica comandos y refleja el estado real.

9 min de lectura

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.