# Output Datasources

> Write predictions and setpoints back to external systems — configure an OPC-UA, MQTT, or Modbus output and verify it with a test write.

An **output datasource** writes data out to an external system — a PLC, broker, or
control application. Unlike input datasources, outputs have no model or tag mapping:
they accept a JSON payload and deliver it to the target.

**Test-write today**

Output datasources currently support **on-demand test writes** — each write is sent
individually so you can verify connectivity and addressing. Scheduled, batched
production write paths are a future enhancement.

## Supported outputs

| Protocol | Capability |
|----------|------------|
| OPC-UA   | Write to a node (synchronous) |
| MQTT     | Publish to a topic (configurable QoS / retain) |
| Modbus TCP | Write to holding registers or coils |

## Configure an output

1. ### Create the output

   Go to **Datasources → Output**, click **+ Create**, and pick the protocol.

2. ### Fill the connection config

   Each protocol has its own fields. Secret fields are masked as `***` after saving.

   
     
**OPC-UA**

     ```json
     {
       "endpoint": "opc.tcp://your-plc-host:4840",
       "securityPolicy": "None",
       "authentication": "Anonymous"
     }
     ```

     
     
**MQTT**

     ```json
     {
       "brokerUrl": "mqtt://your-broker-host:1883",
       "topic": "devices/plc/setpoint",
       "qos": 1,
       "retain": false,
       "username": "your-username",
       "password": "your-password"
     }
     ```

     
     
**Modbus TCP**

     ```json
     {
       "host": "your-plc-host",
       "port": 502,
       "slaveId": 1,
       "defaultCoilAddress": 1000,
       "defaultRegisterAddress": 40001
     }
     ```

     Addresses follow the Modicon convention (coils from `1`, holding registers from
     `40001`).

     
   

3. ### Save and enable

   Save the output, then enable it. An output must be **enabled** before it will
   accept a test write.

## Send a test write

Open the output's details, find the **Test Write** action, enter a JSON payload, and
send it. The result shows success or the protocol error returned by the target.

  
**OPC-UA**

  Write a single node:

  ```json
  {
    "nodeId": "ns=2;s=Temperature",
    "value": 42.5
  }
  ```

  
  
**MQTT**

  Publish a payload:

  ```json
  {
    "setpoint": 65.0,
    "mode": "heating"
  }
  ```

  
  
**Modbus**

  Write one or more registers:

  ```json
  {
    "addresses": [
      { "address": 1000, "value": 100 },
      { "address": 1002, "value": 250 }
    ]
  }
  ```

  

A successful write returns a success result; a protocol error returns a message such
as `OPC UA: node not found` or `Modbus: address out of range`.

## If something goes wrong

| Symptom | Likely cause |
|---------|--------------|
| `Connection timeout` | Target unreachable — check network path, host, and port (MQTT `1883`, Modbus `502`). |
| Datasource disabled error | Enable the output before sending a test write. |
| `Node not found` (OPC-UA) | Check the NodeId format and that the node exists on the server. |
| Address out of range (Modbus) | Stay within Modicon ranges (coils `1+`, holding registers `40001+`). |
| `Admin only` (403) | Test writes require an admin account. |

See the [Troubleshooting](/troubleshooting/) runbook for more.

## Next steps

  - [Connect an input](/configure/input-datasources/) — Stream sensor data in to drive inference.
  - [Monitor the runtime](/operate/monitoring/) — Latency, throughput, and KPIs.
