Industrial Protocols (Modbus, S7, EtherNet/IP)
Connect the agent directly to PLCs and VFDs via Modbus TCP, S7comm (Siemens S7-1200/1500) and EtherNet/IP (Allen-Bradley). Read and write with no gateways.
Native Industrial Protocols
In addition to HTTP / MQTT / OPC UA, Rela AI natively speaks the three most widespread shop-floor protocols: Modbus TCP, S7comm (Siemens), and EtherNet/IP (CIP, Allen-Bradley). The agent can read variables and execute writes on PLCs without an intermediate gateway translating to HTTP or MQTT.
What it's for
A big chunk of the installed industrial base has no OPC UA server. Until recently, integrating a Siemens S7-1200 or an Allen-Bradley PLC with an assistant required a gateway (HMS Anybus, Moxa, etc.) or an intermediate OPC UA server. Now:
- The agent reads registers / data blocks / tags directly.
- The agent writes to coils, holding registers, DB words, CIP tags (full half-duplex).
- The industrial event listener ingests value changes and turns them into
MachineEventwithout HTTP URL.
That cuts three things at once: integration cost (no gateway), latency (one hop less), and failure surface (fewer intermediate systems).
How it works
flowchart LR
PLC[PLC / SCADA] -->|Modbus TCP / S7 / CIP / OPC UA| L[Persistent listener<br/>worker WORKER_MODE=true]
L --> FM[Field mapping<br/>+ normalisation]
FM --> P[Predictive pipeline<br/>anomaly / energy / prognostics]
A[AI agent] -->|synchronous dispatcher| PLCTwo paths: worker persistent listeners read continuously and publish events to the pipeline; synchronous dispatchers let agent tools write back to the PLC. Each protocol ships with its canonical library (pymodbus 3.8+, snap7, pycomm3, asyncua) and its gotchas (see the relaai-api CLAUDE.md for protocol-specific kwargs).
Supported protocols
| Protocol | Typical devices | Read | Write | Library |
|---|---|---|---|---|
| HTTP / REST | ERPs, CMMS, generic APIs | ✅ | ✅ | httpx |
| MQTT | IoT brokers, gateways | ✅ (subscribe) | ✅ (publish) | aiomqtt |
| OPC UA (incl. Reverse Connect) | SCADA, PLCs with OPC UA server, Pub/Sub | ✅ | ✅ | asyncua |
| Modbus TCP | PLCs, VFDs, meters | ✅ holding/input/coil/discrete | ✅ write_register / write_coil | pymodbus ≥ 3.8 |
| S7comm | Siemens S7-1200, S7-1500, S7-300/400 | ✅ DB / M / I / Q | ✅ DB write with type-aware codec | python-snap7 |
| EtherNet/IP (CIP) | Allen-Bradley ControlLogix / CompactLogix | ✅ tag read | ✅ tag write | pycomm3 |
Modbus TCP
Read (listener)
Source of type modbus pointing to PLC IP:port with register list.
protocol: modbus
modbus_host: 10.10.2.15
modbus_port: 502
modbus_unit_id: 1
poll_interval_s: 5
registers:
- address: 40001
count: 2
register_type: holding
field_name: tank_level
- address: 0
count: 1
register_type: discrete
field_name: pump_runningSupported register_type: holding, input, coil, discrete.
Write (tool action)
Action tool with protocol: modbus. Params (address, value) can come from the agent payload or be pre-configured.
tool_type: action
config:
protocol: modbus
modbus_host: 10.10.2.15
modbus_port: 502
modbus_unit_id: 1
modbus_operation: holding # or "coil"
action_defaults:
address: 40100Dispatcher validates modbus_host, address, value, opens async connection, executes write_register or write_coil (device_id kwarg, pymodbus 3.8+ API), closes, returns {success, written, address, value, type, duration_ms}.
Writes to holding registers change PLC behavior. Use only with agents whose prompt includes safety restrictions and explicit confirmation, and consider restricting address via action_defaults instead of exposing it to the agent.
S7comm (Siemens)
Read (listener)
Source of type s7:
protocol: s7
s7_host: 10.10.2.40
s7_rack: 0
s7_slot: 1
poll_interval_s: 10
variables:
- area: DB
db_number: 20
offset: 0
data_type: real
field_name: pressure
- area: M
offset: 100
bit: 0
data_type: bool
field_name: alarm_bitSupported area: DB, M, I, Q.
Write (tool action)
tool_type: action
config:
protocol: s7
s7_host: 10.10.2.40
s7_rack: 0
s7_slot: 1
action_defaults:
db_number: 20
offset: 0
data_type: realDispatcher uses snap7.util to encode value by data_type (int, dint, real, bool, byte, word, dword, string), opens connection, writes to DB, closes.
Encoders (_s7_encode_value):
data_type | Bytes | Encoder |
|---|---|---|
bool | 1 | set_bool |
byte | 1 | set_byte |
int | 2 | set_int |
word | 2 | set_word |
dint | 4 | set_dint |
dword | 4 | set_dword |
real | 4 | set_real |
string | N | set_string |
EtherNet/IP (CIP)
Read (listener)
Source of type ethernet_ip (Allen-Bradley Logix family):
protocol: ethernet_ip
cip_host: 10.10.3.22
poll_interval_s: 5
tags:
- tag_name: Program:MainProgram.Temperature
field_name: temperature
- tag_name: TankLevelPercent
field_name: tank_levelWrite (tool action)
tool_type: action
config:
protocol: ethernet_ip
cip_host: 10.10.3.22Agent provides tag_name + value. Dispatcher uses pycomm3.LogixDriver; if tag doesn't exist or type mismatches, pycomm3 returns error and the tool responds {success: false, error}.
OPC UA Reverse Connect
For PLCs behind strict firewalls that don't allow inbound connections: OPC UA Reverse Connect — the PLC initiates the TCP connection to the server. Configure as source type opcua_reverse with opcua_reverse_listen_port and optional accepted certificates.
Security considerations
- Network isolation: industrial listeners and dispatchers must run in a worker with access to the industrial VLAN, separate from the SaaS management plane.
- Write permissions: pre-configure
address/db_number/tag_nameviaaction_defaultswhen possible, so the agent can't target arbitrary registers. - Human confirmation: agents with write actions should include "confirm before execute" in the prompt.
- Rate limiting: avoid tools that allow bulk writes in a single agent turn.
- Audit: every write is logged with
host,address/db/tag,value,actor(agent), andduration_ms. See Audit Trail.
Persistent listeners and orchestration
MQTT, OPC UA, Modbus, S7, and EtherNet/IP need persistent connections (not a one-shot HTTP call). Rela AI manages them in a separate service (rela-ai-worker on Cloud Run) that:
- Scans all enabled sources on startup.
- Starts an
asyncio.Taskper source. - Implements auto-reconnect with exponential backoff (1s → 60s).
- Publishes connection status (
connecting,connected,disconnected,error) in real time via Ably. - Stops and restarts listeners automatically when a source is created/updated/deleted.
The web API (main service) does not run listeners. Only the worker does. Scaling the frontend never launches N parallel PLC connections.
Dashboard testing
Before enabling a source or write tool, from the configuration screen:
- Test connection — opens a test socket to host/port and validates credentials.
- Test read — attempts to read one configured register and shows value.
- Test write — prompts for a value, writes it, reads it back to confirm.
Runs synchronously from the worker; feedback is immediate.
Key benefits
- Three additional native industrial protocols without gateway.
- Full half-duplex: continuous read + on-demand write.
- Reconnectable listeners with backoff, supervised by dedicated worker.
- Test-validated dispatchers (see
tests/tools/test_tool_dispatch_service.py). - Real-time status via Ably.
- Rate limiting + audit trail + human confirmation as defense in depth for writes.
External Connections
External connection tools allow the agent to communicate with systems outside Rela AI: other systems' APIs, IoT devices via MQTT, and industrial machinery via OPC UA.
VPN Connectivity — Setup and Configuration
Create a dedicated WireGuard tunnel between your plant and Rela AI, download the config tailored to your equipment, and verify the PLC reaches the platform.