> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Allen-Bradley Route

> Connect to Rockwell Automation PLCs with symbolic tag names over EtherNet/IP via libplctag — controller and program scope, UDTs, arrays, and bidirectional writes

## Connect to Rockwell PLCs by Tag Name

The `ALLEN_BRADLEY` route connects Coreflux to Rockwell Automation PLCs using **symbolic tag names** over EtherNet/IP (libplctag). Define an `ALLEN_BRADLEY_CONFIG` block, add TAGs with PLC tag addresses, and publish each data point to its own MQTT topic — with optional scaling, units, deadband, and bidirectional writes.

<Tip>
  **Like reading labels on a control panel.** Instead of numeric register addresses, you use the same tag names you see in Studio 5000 — `MainCounter`, `Program:MainProgram.Temperature`, `Motor1.Speed`.
</Tip>

<Note>
  For **explicit CIP paths** (`4.100.3.0`), use the [EtherNet/IP route](./ethernetip) instead. This route is for symbolic tag-name access; EtherNet/IP is for Class/Instance/Attribute addressing.
</Note>

### Route and config aliases

| Alias                            | Canonical form             |
| -------------------------------- | -------------------------- |
| `TYPE AB` or `TYPE ALLENBRADLEY` | `TYPE ALLEN_BRADLEY`       |
| `ADD AB_CONFIG`                  | `ADD ALLEN_BRADLEY_CONFIG` |

### Key capabilities

* **Symbolic tag names** — controller-scoped, program-scoped, UDT members, and arrays
* **Multiple PLC families** — ControlLogix, CompactLogix, Micro800, MicroLogix, PLC5, SLC500
* **TAG-based polling** — per-point MQTT topics with configurable intervals
* **Bidirectional writes** — `WRITABLE` tags with `DESTINATION_TOPIC`
* **Engineering units** — `SCALING`, `OFFSET`, `UNIT`, `DECIMAL_PLACES`, min/max clamping
* **Publish modes** — `VALUE_ONLY` (default) or `JSON` with quality metadata

***

## Quick Start

<Tabs>
  <Tab title="Poll a controller tag">
    Read a controller-scoped DINT counter every second:

    ```lot wrap focus={9-13} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE ControlLogixPLC WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.10"
            WITH DEVICE_FAMILY 0
            WITH PATH "1,0"
        ADD MAPPING ProductionData
            WITH EVERY 1 SECOND
            ADD TAG ProductCounter
                WITH ADDRESS "MainCounter"
                WITH DATA_TYPE "DINT"
                WITH SOURCE_TOPIC "production/counter"
    ```
  </Tab>

  <Tab title="Program-scoped tags">
    Read tags inside a specific program with units and deadband:

    ```lot wrap focus={9-16} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE ControlLogix WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.20"
            WITH DEVICE_FAMILY 0
        ADD MAPPING ProcessControl
            WITH EVERY 500 MILLISECONDS
            ADD TAG ReactorTemp
                WITH ADDRESS "Program:MainProgram.Temperature"
                WITH DATA_TYPE "REAL"
                WITH UNIT "°C"
                WITH DECIMAL_PLACES 2
                WITH DEADBAND 0.5
                WITH SOURCE_TOPIC "process/reactor/temperature"
    ```
  </Tab>

  <Tab title="Read and write">
    Poll a setpoint and accept MQTT writes to update it:

    ```lot wrap focus={9-18} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE TemperatureControl WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.60"
            WITH DEVICE_FAMILY 0
        ADD MAPPING ControlLoop
            WITH EVERY 1 SECOND
            ADD TAG TempSetpoint
                WITH ADDRESS "TempSetpoint"
                WITH DATA_TYPE "REAL"
                WITH UNIT "°C"
                WITH MIN_VALUE 0.0
                WITH MAX_VALUE 100.0
                WITH SOURCE_TOPIC "control/temperature/setpoint"
                WITH WRITABLE "true"
                WITH DESTINATION_TOPIC "control/temperature/setpoint/write"
    ```
  </Tab>

  <Tab title="Micro800">
    Read built-in I/O on a Micro800 controller:

    ```lot wrap focus={9-14} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE Micro800PLC WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.70"
            WITH DEVICE_FAMILY 4
        ADD MAPPING Micro800Data
            WITH EVERY 1 SECOND
            ADD TAG DigitalIn
                WITH ADDRESS "_IO_EM_DI_00"
                WITH DATA_TYPE "BOOL"
                WITH SOURCE_TOPIC "micro800/input0"
    ```
  </Tab>
</Tabs>

***

## Connection Configuration

### ALLEN\_BRADLEY\_CONFIG Parameters

| Parameter       | Required | Default | Description                                                                                                                                              |
| --------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IP`            | Yes      | —       | PLC IP address                                                                                                                                           |
| `DEVICE_FAMILY` | No       | `0`     | Device family code (0–6, see table below)                                                                                                                |
| `PORT`          | No       | `44818` | EtherNet/IP port. **Micro800** (`DEVICE_FAMILY 4`) passes this to libplctag as `gateway=IP:PORT`. Other families use the default EIP port via libplctag. |
| `SLOT`          | No       | `0`     | Parsed for documentation/legacy parity. **libplctag uses `PATH`**, not `SLOT`, for backplane routing — set the CPU slot in `PATH` (for example `"1,0"`). |
| `PATH`          | No       | `"1,0"` | Routing path to the PLC (format: `backplane,slot`). Passed to libplctag.                                                                                 |
| `TIMEOUT`       | No       | `5000`  | Per-tag read/write timeout in milliseconds                                                                                                               |

<Note>
  The config block may be declared as `ADD ALLEN_BRADLEY_CONFIG` or `ADD AB_CONFIG` — both are equivalent.
</Note>

<Note>
  `ConnectAsync` marks the route ready; libplctag opens a transport per tag read/write. `-checkRouteConnection` confirms the route is loaded but **does not probe the PLC** — verify connectivity with polling or a test read.
</Note>

### Device Family Codes

| Code | Family                      | Use when                                   |
| ---- | --------------------------- | ------------------------------------------ |
| `0`  | ControlLogix / CompactLogix | 1756-L6x, L7x, L8x, 1769-Lxx (most common) |
| `1`  | PLC5                        | 1785-L series (legacy)                     |
| `2`  | SLC500                      | 1747-L series (legacy)                     |
| `3`  | ControlLogix PLC5           | Mixed environment                          |
| `4`  | Micro800                    | 2080-LC series                             |
| `5`  | MicroLogix                  | 1766, 1764 series                          |
| `6`  | Omron                       | NJ/NX with CIP support                     |

### Connection Examples

<Tabs>
  <Tab title="ControlLogix / CompactLogix">
    Standard backplane path to CPU in slot 0:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    ADD ALLEN_BRADLEY_CONFIG
        WITH IP "192.168.1.100"
        WITH DEVICE_FAMILY 0
        WITH PATH "1,0"
        WITH TIMEOUT 5000
    ```
  </Tab>

  <Tab title="MicroLogix">
    MicroLogix 1100/1400:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    ADD ALLEN_BRADLEY_CONFIG
        WITH IP "192.168.1.50"
        WITH DEVICE_FAMILY 5
        WITH TIMEOUT 5000
    ```
  </Tab>

  <Tab title="Through backplane">
    CPU in slot 2 on backplane 1:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    ADD ALLEN_BRADLEY_CONFIG
        WITH IP "192.168.1.100"
        WITH DEVICE_FAMILY 0
        WITH PATH "1,2"
        WITH TIMEOUT 5000
    ```
  </Tab>

  <Tab title="Micro800">
    Micro800 — `PATH` is usually omitted:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    ADD ALLEN_BRADLEY_CONFIG
        WITH IP "192.168.1.70"
        WITH DEVICE_FAMILY 4
        WITH TIMEOUT 5000
    ```
  </Tab>
</Tabs>

***

## Tag Addressing

Allen-Bradley PLCs use **tag-based addressing** (not register numbers). Tag names are case-sensitive.

| Scope         | Format                        | Example                       |
| ------------- | ----------------------------- | ----------------------------- |
| Controller    | `TagName`                     | `MainCounter`                 |
| Program       | `Program:ProgramName.TagName` | `Program:MainProgram.Counter` |
| Array element | `TagName[index]`              | `Temps[5]`                    |
| UDT member    | `UDTInstance.Member`          | `Valve1.Status`               |
| Nested UDT    | `Parent.Child.GrandChild`     | `Tank1.Level.Current`         |
| I/O tags      | `Local:Slot:Type.Data[index]` | `Local:1:I.Data[0]`           |

### Tag naming rules

* Letters, numbers, and underscore only
* Must start with a letter or underscore
* Case-sensitive
* No spaces

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Valid
WITH ADDRESS "MainCounter"
WITH ADDRESS "Program:MainProgram.Temperature"
WITH ADDRESS "Valve1.Status"
WITH ADDRESS "Temps[5]"
```

***

## Data Types

| Coreflux `DATA_TYPE` | AB type | Notes                                                              |
| -------------------- | ------- | ------------------------------------------------------------------ |
| `BOOL`               | BOOL    | Boolean                                                            |
| `SINT`               | SINT    | Signed 8-bit                                                       |
| `USINT` / `BYTE`     | USINT   | Unsigned 8-bit                                                     |
| `INT`                | INT     | Signed 16-bit                                                      |
| `UINT` / `WORD`      | UINT    | Unsigned 16-bit                                                    |
| `DINT`               | DINT    | Signed 32-bit                                                      |
| `UDINT` / `DWORD`    | UDINT   | Unsigned 32-bit                                                    |
| `LINT`               | LINT    | Signed 64-bit                                                      |
| `ULINT` / `LWORD`    | ULINT   | Unsigned 64-bit                                                    |
| `REAL` / `FLOAT`     | REAL    | 32-bit float                                                       |
| `LREAL` / `DOUBLE`   | LREAL   | 64-bit float — MQTT values round to `DECIMAL_PLACES` (default `2`) |
| `CHAR`               | CHAR    | Single character                                                   |
| `WCHAR`              | WCHAR   | Wide character                                                     |
| `STRING`             | STRING  | See encoding notes below                                           |
| `TIME`               | TIME    | Duration in ms — published as `T#XdXhXmXsXms`                      |
| `DATE`               | DATE    | Date value                                                         |
| `TOD`                | TOD     | Time of day                                                        |

### STRING encoding

Depends on `DEVICE_FAMILY`:

* **ControlLogix / CompactLogix (default):** 4-byte DINT length prefix + up to 82 ASCII characters
* **Micro800:** 1-byte length prefix + characters

Set `STRING_SIZE` for the maximum string buffer size when needed.

### TIME encoding

Raw value is a signed 32-bit millisecond count. MQTT publishes Allen-Bradley-style duration strings (for example `T#1h1m1s1ms`).

***

## TAG Configuration

Every polled data point is an `ADD TAG` inside an `ADD MAPPING` block.

### Complete TAG Example

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
ADD TAG MotorSpeed
    WITH ADDRESS "Motor1.ActualSpeed"
    WITH ADDRESS_TYPE "SYMBOL"
    WITH DATA_TYPE "REAL"
    WITH SOURCE_TOPIC "plc/motor1/speed"
    WITH SCALING 1
    WITH OFFSET 0
    WITH UNIT "RPM"
    WITH DECIMAL_PLACES 2
    WITH MIN_VALUE 0
    WITH MAX_VALUE 3600
    WITH DEADBAND 10
    WITH PUBLISH_MODE "JSON"
    WITH DESCRIPTION "Motor 1 actual speed in RPM"
```

### TAG Parameters

<AccordionGroup>
  <Accordion title="Address and data type">
    <ParamField path="ADDRESS" type="string" required>
      PLC tag name — controller-scoped (`MainCounter`), program-scoped (`Program:MainProgram.Counter`), UDT member (`Valve1.Status`), or array (`Temps[0]`).
    </ParamField>

    <ParamField path="ADDRESS_TYPE" type="string">
      `SYMBOL` (default) or `PATH`.
    </ParamField>

    <ParamField path="DATA_TYPE" type="string" required>
      Logix data type: `BOOL`, `SINT`, `INT`, `DINT`, `LINT`, `USINT`, `UINT`, `UDINT`, `ULINT`, `REAL`, `LREAL`, `STRING`, `TIME`, etc.
    </ParamField>

    <ParamField path="STRING_SIZE" type="integer">
      Maximum string buffer size for `STRING` tags. Default: `256`.
    </ParamField>
  </Accordion>

  <Accordion title="Value transformation">
    <ParamField path="SCALING" type="decimal">
      Multiply the parsed value after read. Alias: `SCALING_FACTOR`. Default: `1.0`.
    </ParamField>

    <ParamField path="OFFSET" type="decimal">
      Add after scaling. Default: `0.0`.
    </ParamField>

    <ParamField path="UNIT" type="string">
      Engineering unit (for example `°C`, `bar`, `RPM`). Included in JSON publish mode.
    </ParamField>

    <ParamField path="DECIMAL_PLACES" type="integer">
      Rounding precision for float MQTT payloads. Default: `2`.
    </ParamField>
  </Accordion>

  <Accordion title="Filtering">
    <ParamField path="MIN_VALUE" type="double">
      Clamp minimum allowed value (especially for writable tags).
    </ParamField>

    <ParamField path="MAX_VALUE" type="double">
      Clamp maximum allowed value.
    </ParamField>

    <ParamField path="DEADBAND" type="double">
      Suppress MQTT publish when the change is below this threshold. Default: `0.0`.
    </ParamField>
  </Accordion>

  <Accordion title="Publishing and writes">
    <ParamField path="SOURCE_TOPIC" type="string" required>
      MQTT topic where polled values are published.
    </ParamField>

    <ParamField path="PUBLISH_MODE" type="string">
      `VALUE_ONLY` (default) or `JSON` (value, unit, quality, timestamp, description).
    </ParamField>

    <ParamField path="WRITABLE" type="boolean">
      When `"true"`, subscribe to `DESTINATION_TOPIC` and write incoming MQTT values to the PLC.
    </ParamField>

    <ParamField path="DESTINATION_TOPIC" type="string">
      MQTT topic to receive write commands. Required when `WRITABLE` is `"true"`.
    </ParamField>

    <ParamField path="DESCRIPTION" type="string">
      Human-readable description (included in JSON publish mode).
    </ParamField>
  </Accordion>
</AccordionGroup>

### Publish Modes

**VALUE\_ONLY** (default) — publishes just the scaled value:

```
12345
```

**JSON** — metadata wrapper when explicitly set:

```json wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "tag_name": "SafetyPressure",
  "value": 8.456,
  "unit": "bar",
  "quality": "GOOD",
  "timestamp": "2025-12-17T10:30:45.123Z",
  "description": "Critical safety pressure sensor"
}
```

***

## Event-Based Operations

For on-demand tag reads and writes (not continuous polling), add an `ADD EVENT` block. Publish any message to `SOURCE_TOPIC` to trigger the operation; results appear on `DESTINATION_TOPIC`.

### Query Parameters

| Parameter   | Description                 | Example                                      |
| ----------- | --------------------------- | -------------------------------------------- |
| `operation` | `READ` or `WRITE`           | `READ`                                       |
| `variable`  | PLC tag name                | `Program:MainProgram.Counter`, `MainCounter` |
| `data_type` | Logix data type             | `DINT`, `REAL`, `BOOL`                       |
| `value`     | Value to write (WRITE only) | `42`, `75.0`                                 |

### Read Example

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
ADD EVENT ReadOnDemand
    WITH SOURCE_TOPIC "ab/commands/read"
    WITH DESTINATION_TOPIC "ab/responses/read"
    WITH QUERY "{operation: READ, variable: Program:MainProgram.Counter, data_type: DINT}"
```

### Write Example

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
ADD EVENT WriteSetpoint
    WITH SOURCE_TOPIC "ab/commands/write"
    WITH DESTINATION_TOPIC "ab/responses/write"
    WITH QUERY "{operation: WRITE, variable: TIC100.SP, data_type: REAL, value: 150.0}"
```

***

## Examples

<Tabs>
  <Tab title="Multiple data types">
    Monitor BOOL, DINT, and REAL tags in one mapping:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE ProductionLine WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.30"
            WITH DEVICE_FAMILY 0
        ADD MAPPING MachineMonitor
            WITH EVERY 1 SECOND
            ADD TAG MachineRunning
                WITH ADDRESS "MachineStatus.Running"
                WITH DATA_TYPE "BOOL"
                WITH SOURCE_TOPIC "machine/status/running"
            ADD TAG ProductCount
                WITH ADDRESS "ProductionCounters.TotalCount"
                WITH DATA_TYPE "DINT"
                WITH SOURCE_TOPIC "machine/production/total"
            ADD TAG LineSpeed
                WITH ADDRESS "LineSpeed"
                WITH DATA_TYPE "REAL"
                WITH UNIT "units/min"
                WITH SOURCE_TOPIC "machine/speed"
    ```
  </Tab>

  <Tab title="UDT members">
    Read User-Defined Type structure members:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE UDTAccess WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.40"
            WITH DEVICE_FAMILY 0
        ADD MAPPING ValveControl
            WITH EVERY 500 MILLISECONDS
            ADD TAG Valve1Position
                WITH ADDRESS "Valve1.Position"
                WITH DATA_TYPE "INT"
                WITH UNIT "%"
                WITH SOURCE_TOPIC "valves/valve1/position"
            ADD TAG Valve1Status
                WITH ADDRESS "Valve1.Status"
                WITH DATA_TYPE "BOOL"
                WITH SOURCE_TOPIC "valves/valve1/status"
    ```
  </Tab>

  <Tab title="Array elements">
    Read specific array indices:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE ArrayData WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.50"
            WITH DEVICE_FAMILY 0
        ADD MAPPING ArrayMonitor
            WITH EVERY 1 SECOND
            ADD TAG Zone1Temp
                WITH ADDRESS "ZoneTemperatures[0]"
                WITH DATA_TYPE "REAL"
                WITH UNIT "°C"
                WITH SOURCE_TOPIC "zones/zone1/temperature"
            ADD TAG Zone2Temp
                WITH ADDRESS "ZoneTemperatures[1]"
                WITH DATA_TYPE "REAL"
                WITH UNIT "°C"
                WITH SOURCE_TOPIC "zones/zone2/temperature"
    ```
  </Tab>

  <Tab title="Control loop">
    Read process value and write setpoint from MQTT:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE ControlLoop WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.100"
            WITH DEVICE_FAMILY 0
        ADD MAPPING TempControl
            WITH EVERY 200 MILLISECONDS
            ADD TAG PV
                WITH ADDRESS "TIC100.PV"
                WITH DATA_TYPE "REAL"
                WITH SOURCE_TOPIC "control/tic100/pv"
                WITH UNIT "°F"
            ADD TAG SP
                WITH ADDRESS "TIC100.SP"
                WITH DATA_TYPE "REAL"
                WITH SOURCE_TOPIC "control/tic100/sp"
                WITH UNIT "°F"
                WITH WRITABLE "true"
                WITH DESTINATION_TOPIC "control/tic100/sp/set"
                WITH MIN_VALUE 32
                WITH MAX_VALUE 212
    ```
  </Tab>

  <Tab title="Scaled analog">
    Scale a 4–20 mA sensor to engineering units:

    ```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE ROUTE AnalogSensors WITH TYPE ALLEN_BRADLEY
        ADD ALLEN_BRADLEY_CONFIG
            WITH IP "192.168.1.80"
            WITH DEVICE_FAMILY 0
        ADD MAPPING AnalogData
            WITH EVERY 500 MILLISECONDS
            ADD TAG Pressure
                WITH ADDRESS "AI_Pressure"
                WITH DATA_TYPE "REAL"
                WITH UNIT "bar"
                WITH DECIMAL_PLACES 3
                WITH DEADBAND 0.01
                WITH SOURCE_TOPIC "sensors/pressure"
    ```
  </Tab>
</Tabs>

***

## Best Practices

<AccordionGroup>
  <Accordion title="Choose the correct device family">
    Use `DEVICE_FAMILY 0` for ControlLogix and CompactLogix (most common), `4` for Micro800, and `5` for MicroLogix. Legacy PLC5/SLC500 families (`1`/`2`) only for existing installations.
  </Accordion>

  <Accordion title="Program scope">
    Controller-scoped tags use the name alone (`GlobalCounter`). Program-scoped tags need the full prefix: `Program:MainProgram.LocalCounter`.
  </Accordion>

  <Accordion title="PATH vs SLOT">
    Set the CPU slot in `PATH` (`"1,0"` for backplane 1, slot 0). `SLOT` is kept for legacy parity but libplctag routes via `PATH`.
  </Accordion>

  <Accordion title="Writable tags">
    Use `WRITABLE "true"` with `MIN_VALUE` / `MAX_VALUE` on setpoints. Ensure the PLC is in Remote Run mode for writes to succeed.
  </Accordion>

  <Accordion title="Deadbands and polling">
    Use `DEADBAND` on noisy analog values. Match `EVERY` to how fast the value changes — 500 ms for critical data, 1–5 s for slow status.
  </Accordion>
</AccordionGroup>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connection failed">
    * Verify IP with `ping`
    * Confirm port 44818 is open
    * Ensure PLC is powered on and in **RUN** mode
    * Check `DEVICE_FAMILY` matches your controller type
    * Increase `TIMEOUT` on slow networks
    * Remember: `-checkRouteConnection` does not probe the PLC — use a polling TAG to verify
  </Accordion>

  <Accordion title="Tag not found">
    * Tag names are **case-sensitive** — match Studio 5000 exactly
    * Program-scoped tags need `Program:ProgramName.TagName` (not `ProgramName:Tag`)
    * Verify the tag exists in Controller Tags or Program Tags in Studio 5000
    * For UDTs, include the member: `Valve1.Status` not `Valve1`
    * For arrays, include the index: `Temps[0]` not `Temps`
  </Accordion>

  <Accordion title="Path errors">
    * Use `PATH "1,0"` for standard backplane routing (backplane, slot)
    * For Micro800, omit `PATH` or leave it unset
    * Multi-hop paths use comma-separated segments: `"1,2,2,1"` through bridge modules
  </Accordion>

  <Accordion title="Micro800 issues">
    * Set `DEVICE_FAMILY 4`
    * Use Micro800 I/O tag names (`_IO_EM_DI_00`, `_IO_EM_AI_00`)
    * STRING uses 1-byte length prefix (not ControlLogix 4-byte format)
  </Accordion>

  <Accordion title="Write operations fail">
    * Set `WRITABLE "true"` and provide `DESTINATION_TOPIC`
    * PLC must be in **Remote Run** mode
    * Verify `DATA_TYPE` matches the PLC tag definition
    * Check value is within `MIN_VALUE` / `MAX_VALUE` if set
  </Accordion>

  <Accordion title="Data type mismatch">
    * Match PLC types exactly: DINT → `DINT`, REAL → `REAL`, BOOL → `BOOL`
    * `TIME` tags publish as `T#...` duration strings on MQTT
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="EtherNet/IP Route" icon="ethernet" href="./ethernetip">
    Explicit CIP Class/Instance/Attribute addressing for assembly objects and legacy devices.
  </Card>

  <Card title="Industrial Routes Overview" icon="network-wired" href="./overview">
    Compare OT routes and choose the right protocol for your devices.
  </Card>
</CardGroup>
