> ## 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.
</Tip>

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

<Tabs>
  <Tab title="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.
  </Tab>

  <Tab title="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/#`.
  </Tab>

  <Tab title="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`.
  </Tab>
</Tabs>

***

## 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.
</Warning>

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

<Steps>
  <Step title="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.
  </Step>

  <Step title="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`.
  </Step>

  <Step title="Confirm decoded output">
    Subscribe to `sparkplug/decoded/#` on the local Coreflux broker, then connect or rebirth an edge node.
  </Step>

  <Step title="Test a command">
    Publish a correctly typed value to a convention or declared command topic and confirm the edge node receives `NCMD` or `DCMD`.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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`.
  </Accordion>

  <Accordion title="Repeated rebirth requests occur">
    Persistent alias or sequence gaps usually indicate an unstable edge node. Monitor decoded `$error` topics and the route status.
  </Accordion>
</AccordionGroup>

## 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.
</Warning>

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

<CardGroup cols={2}>
  <Card title="Configure Sparkplug B" icon="industry" href="./sparkplug-b">
    Decode traffic or publish Coreflux metrics as an edge node.
  </Card>

  <Card title="Create LoT Actions" icon="bolt" href="../../actions/overview">
    Automate decoded metrics and Sparkplug command topics.
  </Card>
</CardGroup>
