# MQTT write task

> Publish a message to an MQTT topic each time a command channel gets a value.

An MQTT write task publishes a message each time a value is written to a command channel. Use it to send setpoints and commands to devices that listen on MQTT topics. It can also command [Sparkplug B](https://docs.synnaxlabs.com/reference/hardware/mqtt/sparkplug#command-tags) tags. Before you start, [connect an MQTT broker](https://docs.synnaxlabs.com/reference/hardware/mqtt/connect-broker).

The task has no state channels and no data saving option. To confirm a command, read the value back from the device with a [read task](https://docs.synnaxlabs.com/reference/hardware/mqtt/read-task).

## Targets

A target is one topic and one command channel. Each value written to the command channel publishes one message to the topic:

* **Pointer** -> where the value goes in a JSON payload, such as `/position`. An empty pointer sends the bare value as the whole payload, with no other fields.
* **JSON type** -> the value goes out as a number, a string, or a boolean. With a string, the **Enum mapping** turns numbers into text labels, such as `1` into `OPEN`.
* **Additional fields** -> the same fields in each payload. A static field adds a fixed value, and a generated field adds a new UUID or the current time.

With the pointer `/position`, a static field `/source`, and a generated UUID at `/id`, a command of 42 publishes:

```json
{ "position": 42, "source": "synnax", "id": "6f1c2e3a-..." }
```

## Create an MQTT write task

**Console**

1. In the devices toolbar, right-click the broker and select **Create write task**. You can also run the “Create MQTT write task” command.
2. Click **Add targets**. Select a topic, then select the field that carries the command value. For a topic that publishes rarely, click **Add a topic by name**.
3. Click **Add** *N* **targets**. Each field becomes a target.
4. Select a target to set its **Pointer** and **JSON type**. To add fields to the payload, click **Static** or **Generated** under **Additional fields**.
5. Click (**Start**).

The Console creates a command channel for each target.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/hardware/mqtt/write-task/aff9e8869b14-dark.mp4#t=0.001)

**Python**

Python does not create channels. Create the command channel and its index first.

```python
import synnax as sy
from synnax import mqtt

broker = client.devices.retrieve(name="Plant broker")
cmd_time = client.channels.create(
    name="valve1_cmd_time", is_index=True, data_type=sy.DataType.TIMESTAMP
)
cmd = client.channels.create(
    name="valve1_cmd", index=cmd_time.key, data_type=sy.DataType.FLOAT64
)

task = mqtt.WriteTask(
    name="Valve 1 commands",
    device=broker.key,
    targets=[
        mqtt.PlainWriteTarget(
            topic="plant/valve1/set",
            channel=mqtt.ChannelField(pointer="/position", channel=cmd.key),
            fields=[
                mqtt.StaticWriteField(
                    pointer="/source", json_type="string", value="synnax"
                ),
                mqtt.GeneratedWriteField(pointer="/id", generator="uuid"),
            ],
        )
    ],
)
client.tasks.configure(task)
task.start()
```

## When the broker is down

The task never holds a command back for later. If the broker is not connected when a command arrives, the task drops the command and shows a warning. A command that waited out an outage would reach the device long after the operator sent it, which is not safe. The warning also shows while no command arrives, so you can see the outage before you send one.

## Task options

| Setting                 | Default | Notes                                      |
| ----------------------- | ------- | ------------------------------------------ |
| Auto start `auto_start` | Off     | Starts the task each time the Core starts. |

## Target reference

A target has these settings:

| Setting                            | Default       | Notes                                                      |
| ---------------------------------- | ------------- | ---------------------------------------------------------- |
| Topic `topic`                      |               | The topic to publish to. No wildcards.                     |
| Quality of service `qos`           | At least once | At most once (0), at least once (1), or exactly once (2).  |
| Retain `retained`                  | Off           | Asks the broker to keep the message for later subscribers. |
| Pointer `channel.pointer`          | Empty         | Empty sends the bare value as the whole payload.           |
| JSON type `channel.json_type`      | Number        | Number, string, or boolean.                                |
| Time format `channel.time_format`  | ISO 8601      | For a `timestamp` command channel.                         |
| Channel `channel.channel`          |               | The command channel.                                       |
| Enum mapping `channel.enum_values` | None          | With a string JSON type, maps numbers to text labels.      |

An additional field has these settings:

| Setting                   | Default  | Notes                                      |
| ------------------------- | -------- | ------------------------------------------ |
| Pointer `pointer`         |          | Where the value goes.                      |
| JSON type `json_type`     | Number   | Static fields only. The type of the value. |
| Value `value`             |          | Static fields only. The fixed value.       |
| Generator `generator`     | UUID     | Generated fields only. UUID or timestamp.  |
| Time format `time_format` | ISO 8601 | Generated timestamps only.                 |

In code, a target is `PlainWriteTarget`, its command channel is `ChannelField`, and the additional fields are `StaticWriteField` and `GeneratedWriteField`.

## Troubleshooting

* [broker is not connected](https://docs.synnaxlabs.com/reference/hardware/mqtt/write-task#broker-is-not-connected)

  * Cause

    The connection to the broker is down, so the task drops each command that arrives. The Core connects again on its own, and the warning clears when the connection returns.

* [targets: the task has no enabled targets](https://docs.synnaxlabs.com/reference/hardware/mqtt/write-task#targets-the-task-has-no-enabled-targets)

  * Cause

    The task has no targets, or each target is disabled.

  * Fix

    Add a target, or enable one.

* [target ...: channel ... does not exist](https://docs.synnaxlabs.com/reference/hardware/mqtt/write-task#target-channel-does-not-exist)

  * Cause

    The command channel of a target was deleted.

  * Fix

    Remove the target, then add it again with **Add targets**. The Console creates a new command channel when you start the task.

For problems with the connection, see [Connect an MQTT broker](https://docs.synnaxlabs.com/reference/hardware/mqtt/connect-broker#troubleshooting).
