# Stream from a PLC over Modbus

# Stream from a PLC over Modbus

Read a PLC, power meter or controller over Modbus TCP or RTU. Each register
you map becomes a channel.

## Before you start

- For TCP, the device's address and port (usually `502`). For RTU, its serial
  port (`/dev/ttyUSB0`, `COM3`) and line settings.
- Its unit ID — usually `1`.
- Its register map, from the device manual.

## Steps

1. Open **Connectors**, search for `modbus`, and press **Install**.
2. Open **Inputs**, press **Add input**, and choose **modbus**.
3. Fill the fields:

   | Field | Example |
   |---|---|
   | **Device name** | `plc1` — channels read `/modbus/plc1/…` |
   | **Connection (host:port or serial device)** | `192.168.1.60:502` or `/dev/ttyUSB0` |
   | **Transport** | `tcp` (default) or `rtu` |
   | **Unit ID** | `1` |
   | **Poll rate (Hz)** | `10` |

   For `rtu`, also set **Serial baud rate (RTU)**, **Serial parity (RTU)**,
   **Serial stop bits (RTU)** and **Serial data bits (RTU)**. Defaults are
   9600 8N1.
4. Paste your device's map into **Register map (JSON)**, one entry per value:

   ```json
   [{"alias": "temp", "address": 0, "kind": "input", "dtype": "i16",
     "scale": {"gain": 0.1, "offset": 0}, "unit": "degC"},
    {"alias": "pump_speed_sp", "address": 10, "kind": "holding",
     "dtype": "u16", "unit": "rpm", "writable": true}]
   ```

   | Key | Value |
   |---|---|
   | `alias` | the channel's last path segment |
   | `address` | zero-based — a manual's `40001` is `0` |
   | `kind` | `input` · `holding` · `coil` · `discrete` |
   | `dtype` | `u16` · `i16` · `u32` · `i32` · `f32`; `bool` for `coil` and `discrete` |
   | `scale` | `gain` and `offset` into engineering units |
   | `writable` | `true` to accept setpoints |

5. Press **Test connection**. It reads the first mapped register. A pass means
   the device answered.
6. Press **Add & start**.
7. In **Channels**, type a **name** and **unit** for each, such as
   `temp` → `bearing temperature`, `degC`.

## Check it worked

On **Inputs**, the row counts samples at about your poll rate. On **Live**,
each value shows as `/modbus/plc1/<alias>`.

> **Tip:** A 32-bit value reads as nonsense? Add `"word_swap": true` to its map
> entry. Some devices send the low word first.

- [Verify that your data is arriving](https://phloem.ai/docs/guides/verify-data/): Read an input's row when nothing shows
- [Name channels and units](https://phloem.ai/docs/inputs/channels/): Name a signal, set its unit
- [Inputs](https://phloem.ai/docs/inputs/): Every way to get data in
