Rela AIRela AI Docs
Tools

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 MachineEvent without 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| PLC

Two 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

ProtocolTypical devicesReadWriteLibrary
HTTP / RESTERPs, CMMS, generic APIshttpx
MQTTIoT brokers, gateways✅ (subscribe)✅ (publish)aiomqtt
OPC UA (incl. Reverse Connect)SCADA, PLCs with OPC UA server, Pub/Subasyncua
Modbus TCPPLCs, VFDs, meters✅ holding/input/coil/discrete✅ write_register / write_coilpymodbus ≥ 3.8
S7commSiemens S7-1200, S7-1500, S7-300/400✅ DB / M / I / Q✅ DB write with type-aware codecpython-snap7
EtherNet/IP (CIP)Allen-Bradley ControlLogix / CompactLogix✅ tag read✅ tag writepycomm3

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_running

Supported 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: 40100

Dispatcher 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_bit

Supported 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: real

Dispatcher 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_typeBytesEncoder
bool1set_bool
byte1set_byte
int2set_int
word2set_word
dint4set_dint
dword4set_dword
real4set_real
stringNset_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_level

Write (tool action)

tool_type: action
config:
  protocol: ethernet_ip
  cip_host: 10.10.3.22

Agent 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_name via action_defaults when 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), and duration_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.Task per 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:

  1. Test connection — opens a test socket to host/port and validates credentials.
  2. Test read — attempts to read one configured register and shows value.
  3. 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.

On this page