# OPC UA write task

> Write a value to an OPC UA node each time a command channel gets a new value.

An OPC UA write task writes a value to a node each time you write a value to a command channel. For example, a valve on a schematic can set a PLC setpoint. If you write several values at once, the task writes only the last one. The task writes single values, not arrays.

The task has no state channels. To see the value on the server, read the node back with an [OPC UA read task](https://docs.synnaxlabs.com/reference/hardware/opc-ua/read-task). Before you start, you need a [connected OPC UA server](https://docs.synnaxlabs.com/reference/hardware/opc-ua/connect-server).

## Create an OPC UA 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. In the **Browser**, expand the folders of the server.
3. Drag the variables to write into **Channels**.
4. Click (**Start**).

The Console creates a command channel for each node, named `<node>_cmd`, and its index `<node>_cmd_time`. To choose another name, right-click the channel and select **Rename** before you start.

To add many nodes at once, drag a folder into **Channels**, or import a CSV file. See [find nodes](https://docs.synnaxlabs.com/reference/hardware/opc-ua/read-task#find-nodes). A write task CSV has no `index` column, and the Console skips rows with a `field`.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/hardware/opc-ua/write-task/cf461460e8b7-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 opcua

server = client.devices.retrieve(name="Line 1 PLC")
cmd_time = client.channels.create(
    name="pump_setpoint_cmd_time", is_index=True, data_type=sy.DataType.TIMESTAMP
)
cmd = client.channels.create(
    name="pump_setpoint_cmd", index=cmd_time.key, data_type=sy.DataType.FLOAT64
)

task = opcua.WriteTask(
    name="Line 1 PLC write",
    device=server.key,
    channels=[
        opcua.WriteChannel(cmd_channel=cmd.key, node_id="NS=2;S=Pump1.Setpoint")
    ],
)
client.tasks.configure(task)
task.start()
```

**TypeScript**

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

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

const [server] = await client.devices.retrieve({
  where: { name: { eq: "Line 1 PLC" } },
});
const cmdTime = await client.channels.create({
  name: "pump_setpoint_cmd_time",
  isIndex: true,
  dataType: "timestamp",
});
const cmd = await client.channels.create({
  name: "pump_setpoint_cmd",
  index: cmdTime.key,
  dataType: "float64",
});

const task = await client.tasks.create({
  name: "Line 1 PLC write",
  rack: server.rack,
  type: "opc_write",
  config: opcua.writeConfigZ.parse({
    device: server.key,
    channels: [{ cmdChannel: cmd.key, nodeId: "NS=2;S=Pump1.Setpoint" }],
  }),
});
await task.start();
```

The OPC UA write task has one option, **Auto start** (`auto_start`), which starts the task each time the Driver starts. For node IDs, see [node IDs](https://docs.synnaxlabs.com/reference/hardware/opc-ua/read-task#node-ids). When a frame has more commands than the server accepts in one request, the Driver splits the write into smaller requests.

## Channel reference

The table shows the Console label of each setting, with its Python field under it.

| Setting               | Default   | Notes                                                                                     |
| --------------------- | --------- | ----------------------------------------------------------------------------------------- |
| Channel name `name`   | Empty     | The name of the command channel that the Console creates.                                 |
| `cmd_channel`         |           | The key of the command channel.                                                           |
| Node ID `node_id`     |           | See [node IDs](https://docs.synnaxlabs.com/reference/hardware/opc-ua/read-task#node-ids). |
| Node name `node_name` | Empty     | The browse name. For display only.                                                        |
| `data_type`           | `float32` | The data type of the channel that the Console creates.                                    |
| Enabled `disabled`    | Off       | A disabled channel is not written.                                                        |

### Data types

The Driver reads the type of each node when it connects, and converts each command to that type. For example, a `float64` channel can write `3` to an Int16 node, or `1` to a Boolean node.

| OPC UA type        | Accepts                                                    |
| ------------------ | ---------------------------------------------------------- |
| Boolean            | `0`, `1`, or the text `true` or `false`                    |
| An integer type    | A whole number in the range of the type, or the text of it |
| Float, Double      | A number, or the text of one                               |
| String             | Any value except a timestamp, written as text              |
| DateTime           | A `timestamp`                                              |
| Guid               | A `uuid`, or the text of a GUID                            |
| ByteString         | A `bytes` or a `string`                                    |
| An enumeration     | A whole number in the range of `int32`                     |
| BaseDataType (any) | Any value, with the type in the table below                |

The Driver does not send a command that does not fit the node, such as `300` for a Byte node or `1.5` for an Int16 node. The task shows [“Failed to write commands”](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#troubleshooting) and writes the other channels.

When the server does not give the type of a node, the Driver writes the value with the OPC UA type of the command channel:

| Synnax data type | OPC UA type |
| ---------------- | ----------- |
| `boolean`        | Boolean     |
| `int8`           | SByte       |
| `uint8`          | Byte        |
| `int16`          | Int16       |
| `uint16`         | UInt16      |
| `int32`          | Int32       |
| `uint32`         | UInt32      |
| `int64`          | Int64       |
| `uint64`         | UInt64      |
| `float32`        | Float       |
| `float64`        | Double      |
| `string`         | String      |
| `timestamp`      | DateTime    |
| `uuid`           | Guid        |
| `bytes`          | ByteString  |

A write task cannot write to a field of a structure node.

## Troubleshooting

* [... returned BadTypeMismatch. The value supplied for the attribute is not of the same type as the attribute's value.](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#returned-badtypemismatch-the-value-supplied-for-the-attribute-is)

  * Cause

    The server did not give the type of the node, so the Driver wrote the type of the command channel, and the type does not match the node.

  * Fix

    Use the data type from the [table](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#data-types). For example, a Double node needs a `float64` channel.

* [... returned BadNodeIdUnknown. The node id refers to a node that does not exist in the server address space.](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#returned-badnodeidunknown-the-node-id-refers-to-a-node-that-does)

  * Cause

    The server has no node with that ID.

  * Fix

    Drag the node from the **Browser** again.

* [... the server has no namespace ...](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#the-server-has-no-namespace)

  * Cause

    The server has no namespace with the URI in the node ID of the channel. The server can add the namespace later, for example when a PLC loads its program.

  * Fix

    Check that the server loaded its program, or drag the node from the **Browser** again.

* [... returned BadNotWritable. The access level does not allow writing to the Node.](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#returned-badnotwritable-the-access-level-does-not-allow-writing-)

  * Cause

    The node is read only on the server, or the user of the connection cannot write to it.

  * Fix

    Make the node writable on the server, or connect with a user that can write to it.

* [Invalid NodeId format](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#invalid-nodeid-format)

  * Cause

    The node ID is not in a form that the Driver accepts.

  * Fix

    Write the node ID in one of the forms in [node IDs](https://docs.synnaxlabs.com/reference/hardware/opc-ua/read-task#node-ids).

* [Failed to write commands](https://docs.synnaxlabs.com/reference/hardware/opc-ua/write-task#failed-to-write-commands)

  * Cause

    The task could not write a command. The description names each channel and the reason. The task writes the other channels of the command and keeps running. When the connection is lost, the Driver connects again once and repeats the write, so a value that the server already got can arrive twice. If that fails, the task drops the command. It does not keep commands for later, because a late command could move hardware at the wrong time.

  * Fix

    Fix the cause in the description. For a lost connection, check the [server connection](https://docs.synnaxlabs.com/reference/hardware/opc-ua/connect-server#troubleshooting). The next command connects again.

For other problems, see [Troubleshoot hardware](https://docs.synnaxlabs.com/reference/hardware/troubleshooting).
