Rela AIRela AI Docs
Use Cases

Heterogeneous fleet — 3 PLC brands under one VPN tunnel (Modbus TCP)

A bakery has a Schneider mixer, a Carel proofer and a WAGO oven. All speak Modbus TCP but with different quirks. How to wire them in a single Rela AI tenant without losing hours debugging byte order.

Heterogeneous fleet — 3 PLC brands, one VPN tunnel

Modbus TCP is the lingua franca of industrial automation: virtually every PLC brand speaks it. But "speaks Modbus" does not mean "speaks the same Modbus" — every manufacturer has its own quirks for byte order, addressing convention and concurrent connection limits. This case shows how Rela AI handles a mixed fleet without forcing the customer to normalize anything on the PLC side.

Executive summary

The game changer: a single Rela tenant treats PLCs from different brands as if they came from the same vendor. The AHI, the AI agent, the alarm rules and KPIs run on unified events — heterogeneity is captured in each source's configuration and never leaks into the predictive pipeline.

BeforeAfter
Each brand demands a different SCADA integration3 Modbus sources in Rela, one click each
Operators learn 3 different SCADAs (one per brand)Single dashboard, same language for the 3 machines
Duplicated rules per brand: one for Schneider ovens, another for WAGO ovensOne rule "oven temperature > 280" — tag_enrichment discriminates
When a probe drifts on one brand, no cross-learning happensThe ML anomaly detector learns per-asset patterns regardless of brand

What is it for?

  • Watch machines from different brands already on the floor without replacing anything.
  • Centralize the alarm inbox: a single screen, a single AI agent, common escalation.
  • Apply deterministic rules and predictive maintenance to the assets that matter most, not just to the ones already in a homogeneous SCADA.
  • Understand brand differences (byte order, addressing) once during configuration and forget about them afterward.

Before you start — why you configure the peer yourself

Even with a multi-brand fleet, the access model does not change: the customer creates their own WireGuard peer; Rela never receives corporate VPN credentials.

Three critical reasons (the full 9 are in Why a dedicated tunnel):

  1. Least privilege: your corporate VPN opens the entire network (ERP, mail, SharePoint, OT). Rela only needs the subnet of the 3 PLCs. A breach on the Rela side hits one OT subnet, not the whole company.
  2. Seconds to revoke: you delete the peer in your router whenever you want, no ticket nor coordination with us. The private key lives on your hardware and never leaves it.
  3. Compliance (IEC 62443, NIST SP 800-82, SOC 2, ISO 27001): all require IT/OT separation via dedicated tunnel. Sharing corporate credentials is a direct findable in any audit.

The dedicated-peer model works identically for 1, 3 or N PLCs behind the same LAN — the physical site decides the number of tunnels, not the machines. Sharing credentials falls outside the self-service model and escalates to enterprise custom deployment.

How it works

flowchart LR
  M["Schneider M340<br/>Mixer<br/>192.168.10.55"] --> R[("Customer router<br/>WireGuard + DNAT")]
  C["Carel pCO5 plus<br/>Proofing chamber<br/>192.168.10.50"] --> R
  W["WAGO 750-881<br/>Rotary oven<br/>192.168.10.65"] --> R
  R -- "1 single tunnel" --> CONC[("Rela VPN<br/>concentrator")]
  CONC --> WORKER[("Cloud Run worker<br/>3 modbus_listener tasks")]
  WORKER --> PIPE[("Unified pipeline<br/>_machine_events")]
  PIPE --> AGENT[("AI agent<br/>Plant Watcher")]
  PIPE --> MAST[Asset Mixer]
  PIPE --> CAST[Asset Proofer]
  PIPE --> WAST[Asset Oven]

The trick: the 3 listener tasks run on the same worker. Each decodes per its own configuration (byte order specific per register), but all emit to the same _machine_events. The AI agent and rules don't know — and don't care — that they come from different brands.

Parameters / Configuration

Byte order per brand (the most common gotcha)

modbus_byte_order is configured per register, not per source — because some PLCs mix conventions depending on firmware or DB. Realistic defaults:

Brand / firmwareDefault float32Default 32-bit intNotes
Schneider Modicon M340 / M580big_endian_swap (CDAB)big_endian (ABCD)Word-swap is a Modicon historical quirk. Verify with mbpoll
Carel pCO5+ / pCOWebbig_endian (ABCD)big_endianCarel standard
WAGO 750-881big_endian (ABCD)big_endianConfigurable; default ABCD
Siemens S7 with Modbus modulebig_endian (ABCD)big_endianNative S7 big-endian
Allen-Bradley via Modbus gatewaylittle_endian (DCBA)little_endianInverse of Schneider
Omron CJ/CPbig_endian (ABCD)big_endianStandard

Operational tip: when in doubt, read a register with a known value (e.g., setpoint = 25.0) using all 4 byte orders and pick the one returning the right number. Takes 5 minutes and saves days of debugging.

Addressing convention

Rela uses the 0-based wire Modbus address (the one pymodbus sends). Quick conversion from vendor docs:

Vendor doc saysUse in Rela
Modicon 40101 (5-digit)address 100, FC 3
Modicon 30015address 14, FC 4
Carel "register 1"address 0, FC 3
WAGO "%MW100"address 100, FC 3
Siemens DB1.DBW0 over Modbusdepends on TIA mapping

Concurrent connection limits

PLCConcurrent connectionsImplication
Schneider M3408Comfortable for Rela + SCADA + HMI
Schneider M58016Plenty
Carel pCOWeb4Critical: SCADA + Rela + HMI + tablet already saturate
WAGO 750-8814-8 (firmware)Verify before adding clients
Siemens S7 with CM 12411-3Very tight — Rela may be the only client

Modbus mapping for the fleet (executable summary)

Mixer — Schneider Modicon M340 (10.200.7.55:502, unit_id 1)

RegisterAddressFCTypeByte orderUnit
motor_torque1003float32big_endian_swap%
motor_speed1023float32big_endian_swaprpm
motor_temperature1043float32big_endian_swap°C
mixing_time_seconds1063uint16big_endians
motor_running501bool0/1
alarm_overpressure601bool0/1

Proofing chamber — Carel pCO5+ (10.200.7.50:502, unit_id 1)

RegisterAddressFCTypeByte orderUnit
measured_temperature23float32big_endian°C
measured_humidity43float32big_endian%
cycle_phase103uint16big_endian1-5
door_open12bool0/1
probe_t_alarm202bool0/1

Rotary oven — WAGO 750-881 (10.200.7.65:502, unit_id 1)

RegisterAddressFCTypeByte orderUnit
chamber_temperature2003float32big_endian°C
deck_temperature2023float32big_endian°C
fan_speed2043uint16big_endian%
batch_count2063uint32big_endianpieces
door_open102bool0/1
alarm_overheat112bool0/1

How to use it

Step 1 — Create the VPN tunnel (just one, same as homogeneous fleets)

Sidebar -> Settings -> Connectivity -> label Bakery - Production -> download .conf -> import on router.

Step 2 — DNAT the 3 IPs on the router

/ip firewall nat
add chain=dstnat dst-address=10.200.7.55 dst-port=502 \
    protocol=tcp action=dst-nat to-addresses=192.168.10.55 to-ports=502
add chain=dstnat dst-address=10.200.7.50 dst-port=502 \
    protocol=tcp action=dst-nat to-addresses=192.168.10.50 to-ports=502
add chain=dstnat dst-address=10.200.7.65 dst-port=502 \
    protocol=tcp action=dst-nat to-addresses=192.168.10.65 to-ports=502

/ip firewall filter
add action=accept chain=forward in-interface=rela-vpn src-address=10.200.0.0/16

Step 3 — Create the 3 assets

FieldMixerProoferOven
NameSpiral MixerProofing Chamber 1Rotary Oven 1
Asset codeMIX-01PRF-01OVN-01
Asset typemixerfermentation_chamberrotary_oven
Criticalitymediumhighhigh
PlantBakery CentralBakery CentralBakery Central
AreaProductionProductionProduction

Step 4 — Single AI agent

Sidebar -> Alarms -> Machine agents -> + New.

Name:         Plant Watcher
Model:        gemini-3.1-pro-preview
Auto-task:    yes -> Department "Maintenance"
Auto-notify:  yes -> Plant manager WhatsApp
Escalation:   yes (5 min / 15 min / 30 min)

A single agent covers the 3 brands. Rules filter by tag_enrichment.machine_type when specialization is needed.

Step 5 — Create the 3 Modbus sources with brand-specific config

Sidebar -> Alarms -> Sources -> + New source, repeat 3 times.

Source 1: Schneider mixer

Source ID:    mixer-schneider
Agent:        Plant Watcher
Protocol:     Modbus TCP
Modbus host:  10.200.7.55
Modbus port:  502
Unit ID:      1

Registers:
  - motor_torque         addr=100  fc=3  type=float32  byte_order=big_endian_swap  unit="%"
  - motor_speed          addr=102  fc=3  type=float32  byte_order=big_endian_swap  unit="rpm"
  - motor_temperature    addr=104  fc=3  type=float32  byte_order=big_endian_swap  unit="°C"
  - alarm_overpressure   addr=60   fc=1  type=bool     emit=bit_flip

Field mapping:
  tag_enrichment:
    machine_type: mixer
    brand: schneider
    model: modicon-m340

Source 2: Carel proofer

Source ID:    proofer-carel
Agent:        Plant Watcher
Protocol:     Modbus TCP
Modbus host:  10.200.7.50
Modbus port:  502
Unit ID:      1

Registers:
  - measured_temperature  addr=2   fc=3  type=float32  byte_order=big_endian  unit="°C"
  - measured_humidity     addr=4   fc=3  type=float32  byte_order=big_endian  unit="%"
  - door_open             addr=1   fc=2  type=bool     emit=bit_flip

Field mapping:
  tag_enrichment:
    machine_type: proofer
    brand: carel
    model: pco5plus

Source 3: WAGO oven

Source ID:    oven-wago
Agent:        Plant Watcher
Protocol:     Modbus TCP
Modbus host:  10.200.7.65
Modbus port:  502
Unit ID:      1

Registers:
  - chamber_temperature   addr=200  fc=3  type=float32  byte_order=big_endian  unit="°C"
  - deck_temperature      addr=202  fc=3  type=float32  byte_order=big_endian  unit="°C"
  - fan_speed             addr=204  fc=3  type=uint16   unit="%"
  - alarm_overheat        addr=11   fc=2  type=bool     emit=bit_flip

Field mapping:
  tag_enrichment:
    machine_type: oven
    brand: wago
    model: 750-881

Sidebar -> Assets -> edit each one -> add the corresponding event_source_ids.

Step 7 — One rule that covers multiple brands

Sidebar -> Alarms -> Rules -> + New rule.

Name:         Oven overheat
Source:       (empty — applies globally)
Conditions:
  - field: machine_type
    operator: eq
    value: oven
  - field: chamber_temperature
    operator: gt
    value: 280
Recurrence:
  count_threshold: 3
  window_minutes: 2
Actions:
  - change_severity: critical
  - create_task:
      title: "Oven overheat"
      priority: urgent
      department_id: <Maintenance>
  - trigger_escalation

Why it matters: this rule applies to ALL ovens in the tenant (today WAGO 750-881; tomorrow if you add a Schneider or Siemens). Discrimination comes from tag_enrichment.machine_type, not source_id. Reusable and duplication-free.

Real use cases

One alarm logic for 3 different brands

Operator leaves the oven door open and door_open on the WAGO flips to 1. Same logic as the door_open event on the Carel proofer in proofer-fleet-modbus — but the oven has its own bit_flip and its own asset. The agent sends two WhatsApps (one per machine), not one mixed.

Cross-brand predictive maintenance

The mixer motor (Schneider) shows motor_temperature drifting +3°C consistently for 7 days. AHI drops from A to C. The ML detector learned the normal pattern of THAT mixer (not the average of Schneider mixers in general — the model is per-asset). Generates a PM task "Check motor cooling" 2 weeks before projected failure.

The same would happen if the brand changed to Siemens or ABB — the model is per-asset, not per-brand. No prior training, no migration.

Cross-brand benchmarking

/dashboard/operational shows the 3 assets side by side:

  • Mixer MIX-01: AHI 92 (A), last failure 180 days ago, RUL 90 days.
  • Proofer PRF-01: AHI 78 (B), 2 critical alarms in last 7 days, RUL 30 days.
  • Oven OVN-01: AHI 85 (B), usage 1,200 hours/month, RUL 120 days.

The manager sees this and decides to prioritize the proofer even though it's a different brand. Without Rela they would be comparing 3 incompatible SCADA dashboards.

Limitations and assumptions

  • Each brand demands its Modbus manual. No magic. Addresses, byte orders and FCs come from the manufacturer manual or are discovered with mbpoll from the LAN before configuring.
  • If a brand exposes the data via a non-Modbus protocol the PLC speaks natively (typical: Siemens speaks S7comm natively, Allen-Bradley speaks EtherNet/IP CIP), it is better to use THAT protocol in Rela instead of forcing Modbus for compatibility. Native listeners extract richer metadata (data type without ambiguity, status codes, source timestamps).
  • Saturated concurrent connections: if the customer already has SCADA + HMI polling a PLC with max_connections=4 (typical Carel), adding Rela can drop the oldest connection. Coordinate the rollout with the automation team.
  • Mixing brands multiplies config failure vectors. Troubleshooting without methodology costs days. That is why this doc has the byte_order matrix — it is the first thing to verify when readings look odd.

Troubleshooting

SymptomLikely causeFix
Mixer shows motor_speed = 1.4e-39 (absurd value)byte_order wrong: you tried big_endian and the M340 wanted big_endian_swapSwitch the register byte_order to big_endian_swap and verify with mbpoll -t 4 -1 -r 102 -c 2 -F
Carel disconnected but Schneider and WAGO are fineCarel pCOWeb saturated: 4 connections takenClose one client (duplicate HMI, duplicate SCADA) or upgrade to pCOWeb Pro
Oven emitting events every 30 min instead of 10 smin_interval too high, or outdated WAGO firmwareLower min_interval to 10 s; if it persists, update WAGO firmware
3 sources green but machine_type does not appear in eventstag_enrichment not applied (source missing field_mapping in config)Edit source and add the field_mapping.tag_enrichment block
Rules using field: machine_type do not firetag_enrichment is on the source but the rule evaluates before the injectionVerify pipeline order in logs: field_mapping runs before event_rules_engine

Key benefits

  • 1 tenant, 1 VPN, N brands: any combination of Modbus TCP PLCs lands in the same dashboard with no organizational overhead.
  • Rules that scale with the plant: tag_enrichment lets you write 1 rule per machine type instead of 1 per brand; adding a new brand does not require duplicating rules.
  • Brand-agnostic predictive maintenance: the ML model learns patterns per asset, not per brand. Replacing a PLC on a machine (tech upgrade) does not require retraining.
  • Pedagogical onboarding: the byte_order matrix and addressing convention are documented in this case so the implementation team does not learn the gotchas at the worst time (customer in production).
  • Cross-brand benchmarking: see AHI and RUL of heterogeneous machines side by side in the same dashboard — impossible with per-brand SCADAs.

See also

On this page