> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Sparkplug B Route

> Decode Sparkplug B traffic to JSON or publish Coreflux MQTT topics as a Sparkplug edge node

## Give industrial MQTT data a shared structure

The `SPARKPLUG_B` route connects Coreflux to a Sparkplug B namespace. It can decode binary Sparkplug payloads into readable JSON, publish local MQTT topics as a Sparkplug edge node, or run both directions in one route.

<Tip>
  **Sparkplug is a shared vocabulary for industrial MQTT.** MQTT carries the messages; Sparkplug defines how devices announce themselves, report values, and signal whether they are online.
</Tip>

### When to use it

Use this route when you need to:

* consume `spBv1.0/#` traffic in LoT Actions, dashboards, or storage Routes;
* publish Coreflux topics as `NBIRTH`, `NDATA`, and `NDEATH`;
* group edge-node metrics into Sparkplug devices;
* accept `NCMD` or `DCMD` writes for selected metrics; or
* gate edge-node publishing on an external Primary Host.

Use the separate [Sparkplug Host Route](./sparkplug-host) when Coreflux must be the Primary Host Application.

***

Start by choosing the direction in which Coreflux participates.

## Quick Start

<Tabs>
  <Tab title="Decode to JSON">
    Decode every Sparkplug B publisher on the local broker into readable MQTT topics:

    ```lot wrap focus={3} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE PlantDecoder WITH TYPE SPARKPLUG_B
        ADD SPARKPLUG_CONFIG
            WITH MODE "DECODE"
    ```

    This mode listens to all `spBv1.0/#` traffic. You do not need a Group ID or Edge Node ID.
  </Tab>

  <Tab title="Publish as an edge node">
    Publish a local temperature topic as a Sparkplug edge-node metric:

    ```lot wrap focus={3-5,6-8} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE Line1Edge WITH TYPE SPARKPLUG_B
        ADD SPARKPLUG_CONFIG
            WITH MODE "ENCODE"
            WITH GROUP_ID "Factory"
            WITH EDGE_NODE_ID "Line1"
        ADD METRIC "Temperature"
            WITH DATA_TYPE "Float"
            WITH SOURCE_TOPIC "factory/line1/temperature"
    ```

    Coreflux publishes a birth certificate when the route connects and sends data when the source topic changes.
  </Tab>

  <Tab title="Decode and publish">
    Decode the namespace while publishing Coreflux metrics as a gateway edge node:

    ```lot wrap focus={3-5} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE PlantGateway WITH TYPE SPARKPLUG_B
        ADD SPARKPLUG_CONFIG
            WITH MODE "BOTH"
            WITH GROUP_ID "Factory"
            WITH EDGE_NODE_ID "CorefluxGateway"
        ADD METRIC "Uptime"
            WITH DATA_TYPE "Int64"
            WITH SOURCE_TOPIC "gateway/uptime"
    ```

    The decode and encode paths operate independently inside the same route.
  </Tab>
</Tabs>

***

## Choose the Coreflux role

| Mode     | Coreflux role            | Inbound behavior                           | Outbound behavior                         |
| -------- | ------------------------ | ------------------------------------------ | ----------------------------------------- |
| `DECODE` | Translator and consumer  | Decodes all `spBv1.0/#` traffic            | None                                      |
| `ENCODE` | Sparkplug edge node      | Handles commands for writable metrics      | Publishes birth, data, and death messages |
| `BOTH`   | Translator and edge node | Decodes the namespace and handles commands | Publishes Coreflux metrics                |

`MODE` is the canonical setting. `DIRECTION` remains accepted as a deprecated alias with the same values.

<Warning>
  Only one namespace consumer can run per broker. Deploy either one `SPARKPLUG_B` route in `DECODE` or `BOTH` mode, or one `SPARKPLUG_HOST` route. Multiple `ENCODE`-only routes are allowed.
</Warning>

## Configure the Sparkplug connection

The `SPARKPLUG_CONFIG` block controls the route mode, edge-node identity, target MQTT broker, and optional Primary Host gating.

| Setting           | Required            | Default     | Description                                                        |
| ----------------- | ------------------- | ----------- | ------------------------------------------------------------------ |
| `MODE`            | No                  | `DECODE`    | `DECODE`, `ENCODE`, or `BOTH`                                      |
| `GROUP_ID`        | For `ENCODE`/`BOTH` | —           | Group identity Coreflux publishes on the Sparkplug wire            |
| `EDGE_NODE_ID`    | For `ENCODE`/`BOTH` | —           | Unique edge-node identity within the group                         |
| `PRIMARY_HOST_ID` | No                  | —           | External Primary Host whose retained `STATE` gates edge publishing |
| `SERVER`          | No                  | `localhost` | MQTT broker used by the encode path                                |
| `PORT`            | No                  | `1883`      | Target MQTT broker port                                            |
| `USERNAME`        | No                  | —           | Target broker username                                             |
| `PASSWORD`        | No                  | —           | Target broker password; use `GET SECRET`                           |
| `USE_TLS`         | No                  | `false`     | Enables TLS for the target broker connection                       |

<Note>
  `GROUP_ID` and `EDGE_NODE_ID` do not filter decoded traffic. The decode path always consumes the complete `spBv1.0/#` namespace.
</Note>

## Declare edge-node metrics

In `ENCODE` or `BOTH` mode, add node-level metrics directly to the route and device-level metrics inside `ADD DEVICE`.

| Setting                              | Required               | Description                                        |
| ------------------------------------ | ---------------------- | -------------------------------------------------- |
| `DATA_TYPE`                          | Yes                    | Sparkplug datatype for the metric                  |
| `SOURCE_TOPIC`                       | Yes                    | Local MQTT topic whose value Coreflux publishes    |
| `WRITE_TOPIC` or `DESTINATION_TOPIC` | For command write-back | Local topic that receives an inbound command value |
| `WRITABLE`                           | No                     | Set to `"true"` to accept `NCMD` or `DCMD` writes  |

This complete route publishes a node metric and a writable device metric to a remote broker:

```lot wrap focus={10-15} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE Line1Edge WITH TYPE SPARKPLUG_B
    ADD SPARKPLUG_CONFIG
        WITH MODE "ENCODE"
        WITH GROUP_ID "Factory"
        WITH EDGE_NODE_ID "Line1"
        WITH SERVER GET ENV "SPARKPLUG_BROKER"
        WITH PORT 8883
        WITH USERNAME GET ENV "SPARKPLUG_USER"
        WITH PASSWORD GET SECRET "SPARKPLUG_PASSWORD"
        WITH USE_TLS true
    ADD METRIC "Uptime"
        WITH DATA_TYPE "Int64"
        WITH SOURCE_TOPIC "factory/line1/uptime"
    ADD DEVICE "Press01"
        ADD METRIC "Setpoint"
            WITH DATA_TYPE "Float"
            WITH SOURCE_TOPIC "factory/line1/press01/setpoint"
            WITH WRITE_TOPIC "factory/line1/press01/setpoint/write"
            WITH WRITABLE "true"
```

Supported scalar and array datatypes include signed and unsigned integers, `Float`, `Double`, `Boolean`, `String`, `Text`, `UUID`, `DateTime`, and `Bytes`. `DataSet` and `Template` values can be decoded but not encoded.

## Understand the message lifecycle

When the encode path connects, Coreflux:

1. publishes `NBIRTH`, including `bdSeq` and `Node Control/Rebirth`;
2. publishes one `DBIRTH` for each declared device;
3. publishes `NDATA` or `DDATA` when a source topic changes;
4. republishes births after a `Node Control/Rebirth` command; and
5. publishes death messages on a graceful stop or delivers `NDEATH` through the MQTT Will after a crash.

Writable node and device metrics accept inbound `NCMD` and `DCMD` values. Coreflux republishes each accepted value to its local write topic.

### Gate publishing on a Primary Host

Set `PRIMARY_HOST_ID` when an external Primary Host must be online before the edge node publishes:

```lot wrap focus={6} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE GatedEdge WITH TYPE SPARKPLUG_B
    ADD SPARKPLUG_CONFIG
        WITH MODE "ENCODE"
        WITH GROUP_ID "Factory"
        WITH EDGE_NODE_ID "Line1"
        WITH PRIMARY_HOST_ID "PlantHost"
    ADD METRIC "Temperature"
        WITH DATA_TYPE "Float"
        WITH SOURCE_TOPIC "factory/line1/temperature"
```

The route watches the retained `spBv1.0/STATE/PlantHost` topic. It defers births and suppresses data until the host reports `online:true`, then publishes fresh births and resumes data.

<Warning>
  Primary Host gating does not buffer values. Data produced while the host is offline is dropped, and multi-server Primary Host failover is not supported.
</Warning>

***

## Consume decoded topics

The decode path converts the fixed Sparkplug wire namespace into a JSON topic tree:

```text wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
spBv1.0/<group>/<verb>/<node>/<device>
  → sparkplug/decoded/<group>/<node>/<device>/<metric>

spBv1.0/<group>/<verb>/<node>
  → sparkplug/decoded/<group>/<node>/<metric>
```

Each decoded metric contains its canonical name, value, datatype, timestamp, and quality:

```json wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "name": "Inputs/Temperature",
  "value": 24.6,
  "type": "Double",
  "timestamp": 1717160400123,
  "quality": "GOOD"
}
```

The route also publishes:

| Topic suffix | Retained | Purpose                                          |
| ------------ | -------- | ------------------------------------------------ |
| `/<metric>`  | No       | Latest decoded metric event                      |
| `/$status`   | Yes      | Node or device online state from BIRTH and DEATH |
| `/$error`    | No       | Decode or alias-resolution error                 |

Metric names containing `/` create deeper topic levels. The `name` field in the JSON payload remains authoritative.

## Verify the route

<Steps>
  <Step title="Check route health">
    Publish the connection check command to `$SYS/Coreflux/Command`:

    ```text wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    -checkRouteConnection PlantDecoder
    ```

    Confirm `$SYS/Coreflux/Routes/PlantDecoder/status` reports the route as connected or active.
  </Step>

  <Step title="Observe Sparkplug traffic">
    Use any MQTT client to confirm messages arrive under `spBv1.0/#`.
  </Step>

  <Step title="Subscribe to decoded output">
    Subscribe to `sparkplug/decoded/#`. After a BIRTH message, named metric topics and retained `$status` topics appear.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="No decoded topics appear">
    Confirm the route is active and that a Sparkplug B publisher is sending valid protobuf payloads under `spBv1.0/#`. Decoded output appears under `sparkplug/decoded/#`.
  </Accordion>

  <Accordion title="Metrics appear with unresolved aliases">
    Alias-only DATA arrived before its matching BIRTH. Wait for or request a rebirth and monitor `$error` for `alias_map_unavailable`.
  </Accordion>

  <Accordion title="The edge node remains silent">
    If `PRIMARY_HOST_ID` is configured, confirm the matching host publishes retained `{"online":true}` state on the same target broker configured by `SERVER` and `PORT`.
  </Accordion>

  <Accordion title="Commands do not reach local topics">
    Confirm the metric has `WRITABLE "true"` and a `WRITE_TOPIC` or `DESTINATION_TOPIC`. Read-only metrics reject inbound commands.
  </Accordion>
</AccordionGroup>

## Best Practices

* Give every edge node a unique `GROUP_ID` and `EDGE_NODE_ID` pair.
* Build automations on `sparkplug/decoded/#`, not on opaque protobuf topics.
* Use retained `$status` topics for availability checks.
* Load broker credentials with `GET ENV` and `GET SECRET`.
* Monitor `$error` and route status for repeated alias or decode failures.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Configure Sparkplug Host" icon="tower-broadcast" href="./sparkplug-host">
    Make Coreflux the Primary Host and issue commands to edge nodes.
  </Card>

  <Card title="Store decoded data" icon="database" href="../data-storage/overview">
    Persist readable Sparkplug metrics in a database.
  </Card>
</CardGroup>
