# Modbus write task

> Write command channel values to the coils and holding registers of a Modbus server.

A Modbus write task writes the values of command channels to the coils and holding registers of one Modbus server. For example, a button on a schematic can start a pump through a coil of a PLC. Modbus write tasks have no state channels.

Each command writes only the addresses of the channels in the command. Channels at adjacent addresses go in one request. The Driver writes coils with function code 15 and holding registers with function code 16. For a device that supports only function codes 05 and 06, set **Write codes** of the [server](https://docs.synnaxlabs.com/reference/hardware/modbus/connect-server#connection-options) to **Single**. The Driver then writes each register on its own, so the two halves of a 32-bit value can reach the device at different times. A write goes before reads that wait for the same connection.

To write one bit of a holding register, the Driver reads the register, changes the bit, and writes the register back. If the device changes another bit of the register between the read and the write, the write removes that change. For a device that supports function code 22, select **Mask write (FC22)** on the server. The Driver then changes the bit with one request, and the other bits stay as the device has them.

Before you start, you need a [connected server](https://docs.synnaxlabs.com/reference/hardware/modbus/connect-server).

## Create a Modbus write task

When you create command channels with a client library, give each one its own index channel. A writer that holds several commands on one index must write all of them in every frame.

[Enterprise](https://docs.synnaxlabs.com/reference/get-started/editions "Needs Synnax Enterprise")

**Console**

1. In the devices toolbar, right-click the server and select **Create write task**.
2. Click **Add channel**. Select the type, then enter the address. For a holding register, select the **Data type**. For a holding register bit, enter the **Bit**.
3. Click (**Start**).

The Console creates a command channel and an index channel for each output. For the server `Pump skid PLC`, a coil at address 3 gives `Pump_skid_PLC_coil_output_3_cmd` and `Pump_skid_PLC_coil_output_3_cmd_time`. To use a different name, right-click the channel and select **Rename** before you start the task.

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

**Python**

Python does not create channels. Create them first.

```python
import synnax as sy
from synnax import modbus

dev = client.devices.retrieve(name="Pump skid PLC")
cmd_time = client.channels.create(
    name="pump_cmd_time", is_index=True, data_type=sy.DataType.TIMESTAMP
)
pump_cmd = client.channels.create(
    name="pump_cmd", index=cmd_time.key, data_type=sy.DataType.UINT8
)

task = modbus.WriteTask(
    name="Pump control",
    device=dev.key,
    channels=[modbus.CoilWriteChannel(address=3, channel=pump_cmd.key)],
)
client.tasks.configure(task)
task.start()
```

**TypeScript**

TypeScript does not create channels. Create them first.

```typescript
import { modbus } from "@synnaxlabs/client";

const [dev] = await client.devices.retrieve({
  where: { name: { eq: "Pump skid PLC" } },
});
const cmdTime = await client.channels.create({
  name: "pump_cmd_time",
  isIndex: true,
  dataType: "timestamp",
});
const pumpCmd = await client.channels.create({
  name: "pump_cmd",
  index: cmdTime.key,
  dataType: "uint8",
});

const task = await client.tasks.create({
  name: "Pump control",
  rack: dev.rack,
  type: "modbus_write",
  config: modbus.writeConfigZ.parse({
    device: dev.key,
    channels: [{ type: "coil", address: 3, channel: pumpCmd.key }],
  }),
});
await task.start();
```

The task has the options **Data saving** and **Auto start**. See [task options](https://docs.synnaxlabs.com/reference/hardware/tasks#task-options). Python `WriteTask` has no `data_saving_disabled` argument.

## Channel reference

Each channel has an `address`, from 0 to 65535, and a `channel`, the command channel. Each table shows the Console label of a setting, with its Python field under it.

The Console also accepts a six-digit Modicon address, such as 400001 for holding register 0. The first digit is the table: 0 for coils and 4 for holding registers. The Console shows the Modicon form next to each address.

**Coil**

#### [Coil](https://docs.synnaxlabs.com/reference/hardware/modbus/write-task#coil)

Python `CoilWriteChannel`TypeScript `coil`

Writes a coil. A command of 0 turns the coil off. Any other value turns it on.

**Holding register**

#### [Holding register](https://docs.synnaxlabs.com/reference/hardware/modbus/write-task#holding_register)

Python `HoldingRegisterWriteChannel`TypeScript `holding_register`

Writes a number to one or more holding registers.

| Setting               | Default  | Notes                                                                                                                                                        |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Data type `data_type` | `uint16` | `int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`, `float32`, `float64`.                                                              |
| Bytes `bytes_swapped` | device   | `True` swaps the two bytes in each register. See [byte and word order](https://docs.synnaxlabs.com/reference/hardware/modbus/read-task#byte-and-word-order). |
| Words `words_swapped` | device   | `True` writes the high word first. Only for 32-bit and 64-bit data types.                                                                                    |

**Holding register bit**

#### [Holding register bit](https://docs.synnaxlabs.com/reference/hardware/modbus/write-task#holding_register_bit)

Python `HoldingRegisterBitWriteChannel`TypeScript `holding_register_bit`

Writes one bit of a holding register. A command of 0 clears the bit. Any other value sets it. Channels can write different bits of one register, but a bit channel cannot use a register that a holding register channel writes.

| Setting   | Default | Notes                             |
| --------- | ------- | --------------------------------- |
| Bit `bit` | `0`     | From 0 (least significant) to 15. |

## Troubleshooting

### “Illegal function”

The device does not support function code 15 or 16. Set **Write codes** of the server to **Single**.

### The connection dropped

The Driver reconnects and sends the command again at once, up to the **Retries** of the server. If that fails, the task shows the warning “Failed to write commands” and keeps running. The Driver reconnects at the next command.

For other problems, see [Connect a Modbus server](https://docs.synnaxlabs.com/reference/hardware/modbus/connect-server#troubleshooting) and [Troubleshoot hardware](https://docs.synnaxlabs.com/reference/hardware/troubleshooting).
