> ## 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 Host Route

> Make Coreflux the Sparkplug B Primary Host Application for namespace state, commands, decoding, and rebirth control

## Make Coreflux the namespace authority

The `SPARKPLUG_HOST` route makes Coreflux the Sparkplug B Primary Host Application. It publishes authoritative host state, decodes the complete Sparkplug namespace, issues commands to edge nodes, and requests rebirth when it detects missing aliases or sequence gaps.

> [!TIP]
>
> **The Primary Host is the control room for a Sparkplug namespace.** Edge nodes report their catalogues and values; the host watches their health and sends commands back.

### When to use it

Use this route when Coreflux must:

* publish retained `STATE` as the namespace's Primary Host;
* consume and decode all edge-node traffic;
* issue `NCMD` and `DCMD` commands from LoT;
* detect sequence gaps and request a fresh BIRTH; or
* prevent two hosts from asserting the same Host ID.

Use [Sparkplug B Route](./sparkplug-b) instead when Coreflux only needs to decode traffic or publish as an edge node.

***

Start with the broker where the Sparkplug edge nodes publish.

## Quick Start

**Local broker**

Make Coreflux the Primary Host for edge nodes connected to its local broker:

```lot wrap focus={3-4} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE PlantHost WITH TYPE SPARKPLUG_HOST
    ADD SPARKPLUG_HOST_CONFIG
        WITH SERVER "localhost"
        WITH HOST_ID "CorefluxHost"
```

Coreflux publishes retained state at `spBv1.0/STATE/CorefluxHost` and decodes the local namespace.

**Remote plant broker**

Connect the Host route to the broker already used by plant edge nodes:

```lot wrap focus={3-9} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE PlantHost WITH TYPE SPARKPLUG_HOST
    ADD SPARKPLUG_HOST_CONFIG
        WITH SERVER "plant-broker.local"
        WITH PORT 8883
        WITH HOST_ID "CorefluxHost"
        WITH HOST_ID_CONFLICT "REFUSE"
        WITH USE_TLS true
        WITH USERNAME GET ENV "SPARKPLUG_USER"
        WITH PASSWORD GET SECRET "SPARKPLUG_PASSWORD"
```

Decoded metrics are republished on the local Coreflux broker under `sparkplug/decoded/#`.

**Declared command**

Add an explicit command target that works even before Coreflux sees the edge node's BIRTH:

```lot wrap focus={6-9} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE PlantHost WITH TYPE SPARKPLUG_HOST
    ADD SPARKPLUG_HOST_CONFIG
        WITH SERVER "plant-broker.local"
        WITH HOST_ID "CorefluxHost"
        WITH HOST_ID_CONFLICT "REFUSE"
    ADD METRIC "Setpoint"
        WITH DATA_TYPE "Float"
        WITH TARGET "Factory/Line1/Press01"
        WITH COMMAND_TOPIC "commands/line1/press01/setpoint"
```

Publishing a value to the command topic sends a typed `DCMD` to `Press01`.

***

## Understand the Host role

A Host route connects two MQTT contexts:

| Context | Purpose |
| - | - |
| Target broker (`SERVER`/`PORT`) | Carries `spBv1.0/#`, retained host `STATE`, and outbound commands |
| Local Coreflux broker | Receives `sparkplug/decoded/#` JSON and local command triggers |

The target and local brokers can be the same broker. If they differ, configure `SERVER` to the broker used by the Sparkplug edge nodes.

> [!WARNING]
>
> A `SPARKPLUG_HOST` route consumes the complete Sparkplug namespace. Do not run it alongside a `SPARKPLUG_B` route in `DECODE` or `BOTH` mode on the same broker. You can run separate `SPARKPLUG_B` routes in `ENCODE` mode.

## Configure the Primary Host

| Setting | Required | Default | Description |
| - | - | - | - |
| `HOST_ID` | Yes | — | Identity published in `spBv1.0/STATE/<HOST_ID>` |
| `HOST_ID_CONFLICT` | No | `REFUSE` | `REFUSE` backs off when another host appears to own the ID; `WARN` proceeds and logs |
| `SERVER` | No | `localhost` | Target broker where edge nodes publish |
| `PORT` | No | `1883` | Target broker port |
| `USE_TLS` | No | `false` | Enables TLS for the target broker |
| `USERNAME` | No | — | Target broker username |
| `PASSWORD` | No | — | Target broker password; use `GET SECRET` |

There is no `MODE` setting: `SPARKPLUG_HOST` defines the role.

### Prevent Host ID conflicts

With the default `HOST_ID_CONFLICT "REFUSE"`, Coreflux watches the configured state topic before asserting the role. If it sees a foreign `online:true` state for the same Host ID, it disconnects and stands down for that session.

Use `WARN` only when you know that the other state is stale and Coreflux should proceed.

## Follow the STATE lifecycle

The Host route publishes retained state with QoS 1:

1. Before connecting, it registers an MQTT Will with `online:false`.
2. After connecting, it publishes `online:true` using the same session timestamp.
3. On graceful stop, it publishes `online:false`.
4. After a crash, the target broker delivers the registered Will.
5. After reconnecting, it publishes a new offline-to-online session state.

The payload follows this shape:

```json wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "online": true,
  "timestamp": 1717160400123
}
```

Edge nodes configured with the matching `PRIMARY_HOST_ID` use this state to decide when to publish.

***

## Issue commands to edge nodes

The Host route supports two command methods.

### Use the convention topic tree

Publish a value on the local broker without declaring command metrics:

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

The node form sends `NCMD`; the device form sends `DCMD`. Coreflux uses the datatype learned from the target's BIRTH catalogue.

This Action forwards a UI value to a node-level setpoint:

```lot wrap focus={3} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION SetLine1Setpoint
ON TOPIC "ui/line1/setpoint" DO
    PUBLISH TOPIC "sparkplug/command/Factory/Line1/Setpoint" WITH PAYLOAD
```

### Declare a command overlay

Use `ADD METRIC` when you need a friendly trigger topic, an explicit datatype, or commands before the first BIRTH:

| Setting | Required | Description |
| - | - | - |
| `DATA_TYPE` | Yes | Sparkplug datatype used to encode the command |
| `TARGET` | Yes | `<group>/<node>` for `NCMD` or `<group>/<node>/<device>` for `DCMD` |
| `COMMAND_TOPIC` | Yes | Local MQTT topic that triggers the command |

The declared datatype takes precedence over a learned catalogue. If neither source provides a datatype, Coreflux drops the command instead of guessing.

## Decode and repair the namespace

The Host route feeds the same readable topic tree as a `SPARKPLUG_B` decode route:

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

It also monitors sequence integrity. When alias-only DATA arrives before BIRTH or a node's `seq` skips a value, Coreflux rate-limits and sends a node-level `Node Control/Rebirth` request.

| Output | Purpose |
| - | - |
| `sparkplug/decoded/.../<metric>` | Decoded metric JSON |
| `sparkplug/decoded/.../$status` | Retained node or device availability |
| `sparkplug/decoded/.../$error` | Decode and alias-resolution failures |

***

## Verify the Host route

**1. Check route health**

Publish the following command to `$SYS/Coreflux/Command`:

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

Confirm `$SYS/Coreflux/Routes/PlantHost/status` reports the target connection as active.

**2. Confirm Host state**

Use any MQTT client connected to the target broker and subscribe to `spBv1.0/STATE/CorefluxHost`. Confirm the retained payload reports `online:true`.

**3. Confirm decoded output**

Subscribe to `sparkplug/decoded/#` on the local Coreflux broker, then connect or rebirth an edge node.

**4. Test a command**

Publish a correctly typed value to a convention or declared command topic and confirm the edge node receives `NCMD` or `DCMD`.

## Troubleshooting

> **Host STATE is not published**
>
> Confirm `SERVER`, `PORT`, credentials, and TLS settings point to the broker used by the edge nodes. Check route status for a `HOST_ID_CONFLICT` refusal.

> **No decoded data appears**
>
> Confirm edge nodes publish valid Sparkplug B traffic to the target broker and that no `SPARKPLUG_B` decode consumer conflicts with this Host route.

> **Commands are dropped**
>
> Use the correct convention topic or declared `COMMAND_TOPIC`. If the edge node has not published BIRTH, declare the command with an explicit `DATA_TYPE`.

> **Repeated rebirth requests occur**
>
> Persistent alias or sequence gaps usually indicate an unstable edge node. Monitor decoded `$error` topics and the route status.

## Limitations

> [!WARNING]
>
> * The route connects to one target `SERVER` and `PORT`; multi-server Primary Host failover is not supported.
> * The route does not provide durable store-and-forward replay.
> * `DataSet` and `Template` metrics decode to JSON but cannot be sent as commands.

## Best Practices

* Keep `HOST_ID_CONFLICT` set to `REFUSE` unless you intentionally take ownership.
* Match every edge node's `PRIMARY_HOST_ID` to the Host route's `HOST_ID`.
* Point `SERVER` at the broker where the edge nodes actually publish.
* Prefer declared command overlays for production automations.
* Load credentials with `GET ENV` and `GET SECRET`.

***

## Next Steps

> **[Configure Sparkplug B](./sparkplug-b)**
>
> Decode traffic or publish Coreflux metrics as an edge node.

> **[Create LoT Actions](../../actions/overview)**
>
> Automate decoded metrics and Sparkplug command topics.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.