Node-RED

Node-RED Sparkplug B: Publishing and Consuming Edge Data

Turn Node-RED into a Sparkplug B edge node with node-red-contrib-mqtt-sparkplug-plus: define metrics, publish NBIRTH, DBIRTH and DDATA, handle DCMD commands, then decode the Protobuf payloads into plain MQTT topics.

Node-RED Sparkplug B edge node publishing birth and data messages for a CNC machine to an MQTT broker
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

Node-RED Sparkplug B support lets a low-code flow behave like a proper industrial edge node: it announces its metrics with birth certificates, publishes compact Protobuf data, reports its death when it disconnects, and accepts commands. In this tutorial you will build a Sparkplug B edge node for a simulated CNC machine, consume and decode the data in a second flow, and check the result in a broker that understands Sparkplug. Along the way you will learn which details of the specification trip people up most often.

Sparkplug B in Brief

Sparkplug B is a specification from the Eclipse Foundation that sits on top of MQTT. Plain MQTT says nothing about topic structure or payload format; Sparkplug defines both, plus session state, so that equipment from different vendors interoperates with SCADA and MES applications out of the box.

The key ideas:

  • Topic namespace: spBv1.0/<group_id>/<message_type>/<edge_node_id>/[<device_id>].
  • Payload: Google Protocol Buffers with a list of metrics, each with a name, data type, value and timestamp.
  • Session awareness: an edge node publishes NBIRTH when it connects and registers an NDEATH as its MQTT Last Will. Devices behind it publish DBIRTH and DDEATH.
  • Report by exception: after birth, DDATA messages contain only changed metrics.
  • Commands: applications send NCMD and DCMD messages, including a "Rebirth" request.
Message Direction Meaning
NBIRTH / DBIRTH Edge to broker Full metric list with types and current values
NDATA / DDATA Edge to broker Changed metrics only
NDEATH / DDEATH Edge to broker (NDEATH via Last Will) Node or device offline
NCMD / DCMD Application to edge Write a metric or request a rebirth
STATE Primary host application Whether the host application is online

For the full topic grammar, see the guide to the Sparkplug topic namespace, and for how births and deaths keep state consistent, read Sparkplug birth and death certificates.

Install the Sparkplug Nodes

The most complete Sparkplug implementation for Node-RED is node-red-contrib-mqtt-sparkplug-plus. Install it from the palette manager or the command line:

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

It adds three nodes and one config node:

  • mqtt sparkplug device: represents one device behind the edge node. It handles DBIRTH, DDATA, DDEATH and DCMD for you.
  • mqtt sparkplug in: subscribes to Sparkplug topics and decodes the Protobuf payload into a JavaScript object.
  • mqtt sparkplug out: publishes raw Sparkplug messages when you need full control.
  • Sparkplug broker config: the MQTT connection plus the Sparkplug Group ID and Edge Node ID. It publishes NBIRTH and registers NDEATH automatically.

Build a Node-RED Sparkplug B Edge Node

Step 1: Configure the broker and identity

Add an mqtt sparkplug device node and create a new broker config:

  • Server: broker.connectmq.com, port 1883, with a unique client ID. This is the free public MQTT broker, so anything you publish is readable by others; use simulated data only.
  • Group ID: demo-a7f3k2. Sparkplug topics must start with spBv1.0, so you cannot use the usual connectmq/demo/... prefix here. Make the group ID unique instead, replacing a7f3k2 with your own random string.
  • Edge Node ID: line1.

Then set the device name in the device node to cnc1. The device will publish to spBv1.0/demo-a7f3k2/DDATA/line1/cnc1.

Step 2: Define the metrics

In the device node, add metrics with names and Sparkplug data types:

Metric name Data type Meaning
spindle/speed Int32 Spindle speed in rpm
spindle/load Float Spindle load in percent
coolant/temperature Float Coolant temperature in °C
running Boolean Machine running
partCount Int64 Cumulative part counter

Declaring types matters: the DBIRTH tells every consumer what to expect, and a host application will reject or misinterpret data that changes type later. By default the node waits until every metric has received a value before publishing DBIRTH, which prevents a birth certificate full of empty values.

Step 3: Feed it data

An inject node repeating every 2 seconds feeds a function node that simulates the machine. The device node expects msg.payload.metrics as an array of name and value pairs:

// 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;

Deploy. The broker config publishes NBIRTH for line1, the device publishes DBIRTH for cnc1, and from then on only changed metrics go out in DDATA messages.

Step 4: Handle commands

When an application sends a DCMD to spBv1.0/demo-a7f3k2/DCMD/line1/cnc1, the device node emits it on its output as a message with the requested metrics. Wire the output to a function node that validates the request and acts on it, for example resetting the part counter:

// 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;

To make the simulator honour the reset, read cnc1_reset_requested from flow context in the simulator and set parts back to zero. Rebirth requests are handled by the node itself, which republishes the birth certificates.

Consume and Decode Sparkplug B in Node-RED

Sparkplug payloads are binary. A normal mqtt in node on spBv1.0/# would give you a Buffer full of Protobuf bytes. The mqtt sparkplug in node decodes them:

  1. Add an mqtt sparkplug in node using a separate broker config with its own unique client ID.
  2. Subscribe to spBv1.0/demo-a7f3k2/+/line1/#.
  3. Wire it to a debug node set to show the complete message.

You will see objects with a timestamp, a seq number and a metrics array. To make the data useful to non-Sparkplug consumers, flatten it into one plain MQTT topic per metric:

// 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];

Wire it to an mqtt out node with empty topic and retain fields. Now a dashboard, a script or a spreadsheet tool can subscribe to connectmq/demo/a7f3k2/demo-a7f3k2/line1/cnc1/spindle_speed without knowing anything about Protobuf. This is the same idea as the Sparkplug-plus-UNS architecture described in Sparkplug B and the Unified Namespace.

Check the Data in a Broker That Understands Sparkplug

Debug nodes prove that Node-RED can decode its own messages, but it is worth checking with an independent tool. ConnectMQ decodes Sparkplug B payloads, both Protobuf and JSON, so you can see the metrics of each DBIRTH and DDATA message in the portal instead of raw bytes. It can also republish Sparkplug data into ISA-95 topics, for example spBv1.0/factory1/DDATA/line1/cnc1 becomes connectmq/factory1/production/line1/cnc1/telemetry, which gives you the flattening step above without maintaining the function node yourself.

To try it, create a free broker in the ConnectMQ portal, change the Sparkplug broker config in Node-RED to that broker's host, port 8883 with TLS, and the generated username, password and client ID. Then open the live topic explorer and watch the births and data arrive decoded.

Common Sparkplug Pitfalls

  1. Reusing client IDs. Two edge nodes with the same MQTT client ID keep kicking each other off, and each reconnection produces a new NDEATH and NBIRTH. Every edge node needs a unique client ID.
  2. Changing metric types. A metric declared as Int32 must not later carry a float. Fix the definition and trigger a rebirth instead.
  3. Missing births in consumers. A consumer that starts after the birth only sees DDATA with changed metrics. It should send a Rebirth NCMD, or read retained state elsewhere, before it trusts its view.
  4. Ignoring sequence numbers. The seq field runs from 0 to 255 and wraps. A gap means a message was lost and a rebirth request is appropriate.
  5. Topic levels. Group, edge and device IDs are single topic levels and must not contain /, + or #.
  6. QoS expectations. Data messages typically use QoS 0, while NDEATH and STATE use QoS 1. Make sure your broker plan supports QoS 1.

From Pilot to Production

A Sparkplug architecture concentrates every edge node, host application and historian on the broker, so the broker becomes critical infrastructure. Use authenticated connections over TLS, unique client IDs bound to credentials, and a broker that stays reachable from both plant and cloud. A cloud MQTT broker suits multi-site deployments, and a managed MQTT broker removes the operational burden of running it yourself. To feed Sparkplug from existing controllers, combine this flow with Node-RED OPC UA as the data source. If you are new to the MQTT nodes, start with the Node-RED MQTT tutorial.

Run Your Sparkplug Edge Nodes on ConnectMQ

Sign up at app.connectmq.com with the free Serverless plan, no credit card required. Create a broker, point your Node-RED Sparkplug config at it with the generated credentials, and inspect decoded births, data and deaths in the portal within minutes.

Frequently Asked Questions

Which Node-RED package supports Sparkplug B?

node-red-contrib-mqtt-sparkplug-plus is the most complete option. It handles births, deaths, sequence numbers, rebirth requests and Protobuf encoding and decoding for you.

Can I read Sparkplug B messages with a normal MQTT in node?

You will receive the raw Protobuf bytes as a Buffer. Use the mqtt sparkplug in node, or a Protobuf decoder in a function node, to turn them into readable metrics.

Does Node-RED send NDEATH automatically?

Yes. The Sparkplug broker config registers NDEATH as the MQTT Last Will when it connects, so the broker publishes it if the edge node disconnects unexpectedly.

Why are only some metrics in my DDATA messages?

Sparkplug reports by exception: DDATA carries only metrics that changed. The full list and current values are in the DBIRTH, so consumers must keep the birth to interpret later data.

Related articles

Node-RED OPC UA Client to MQTT with ISA-95 Topics

Use node-red-contrib-opcua to subscribe to OPC UA variables on a PLC or simulation server, map node IDs to ISA-95 style MQTT topics, and publish values with quality and timestamps.

9 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.