Skip to content

Modbus

The panel is a Modbus master: it cyclically reads — and writes — the registers of connected devices into the tag table. Two transports are supported, and both can run at once.

Transport Physical layer When to use it
RTU The board's RS485 terminals I/O modules, inverters, sensors on a cable
TCP Ethernet or Wi-Fi Meters with a LAN module, RTU↔TCP gateways, anything in the cabinet with a network port

The panel can also be a slave, so a supervisory system can read from it. That is further down the page.

A tag with a Modbus source

Every Modbus tag carries: unit (the device address), fc (coil, discrete, holding or input), address (0-based — not the 3xxxx/4xxxx notation), word_order (the order of the two words in a 32-bit value) and optionally transport: tcp with ip and port.

  • Without transport — or with transport: rtu — the tag goes over RS485.
  • f32 and u32 tags are read from two registers. The word order differs from one manufacturer to the next and is the most common source of nonsense values. Importing from the catalogue sets it correctly for you.
  • Scaling is value = raw × gain + offset. Analogue tags need a deadband: without one, a noisy value redraws the screen for no reason.
tags:
  - name: voltage_l1
    datatype: f32
    source: { modbus: { transport: tcp, ip: 192.168.0.50, port: 502,
                        unit: 1, fc: input, address: 0, word_order: big } }

Limits and behaviour

Limit Value Why
Distinct TCP targets (IP:port) per project 4 roughly 6–8 kB of RAM per connection on an ESP32-S3
Tags in total 512 product limit
  • Tags pointing at the same IP:port share one connection — twenty tags from one meter is still one target. Different unit values on the same IP (an RTU↔TCP gateway with several devices behind it) are also one target.
  • The editor enforces the limit both on import and at compile time. A project over the limit is rejected on your desk, not discovered as a stuttering panel on a machine.
  • When a target drops out, tags hold their last value, one event goes into the diagnostic buffer on the way down and one on the way back. The panel reconnects by itself with a one-second backoff, and polling of the other targets continues.
  • The poller runs outside the PLC cycle, so a slow or unreachable Modbus device can never extend the logic cycle.

The device catalogue

Think of it as an EDS file for Modbus: the directory devices/modbus/ holds one file per device — manufacturer, model, datasheet, word_order — plus the register map: address, function code, data type, scale, unit and description. The catalogue is curated by inovaea and signed like every other catalogue.

In the editor: open the Modbus RTU master or Modbus TCP master page → Add Modbus device… → pick from the catalogue → tick the registers you want → choose the transport (RS485, or TCP with an IP address) → Import tags. The tags arrive prefixed with the model name (sdm630_voltage_l1), with the right data type, word order and scaling.

The first entries are the Eastron SDM120 (single-phase meter) and SDM630 (three-phase meter).

A device that is not in the catalogue

You do not have to write the YAML by hand:

  1. Add Modbus device… → in the right-hand pane, with nothing selected, fill in vendor and modelNew device. This creates devices/modbus/<vendor>_<model>.yaml with one example register.
  2. In the device window → the Registers tab → turn on Edit register map. The row under the table adds registers (name, address, class, data type, unit); the x on a row deletes one.
  3. Save to catalog writes the map back to the .yaml file.

The file is the single source of truth — the project only stores a path to it, so the entry exists on disk immediately rather than when the project is saved.

Rule Why
File named <vendor>_<model>.yaml, lower-case ASCII the catalogue is version-controlled and has to be readable on every operating system
uid: 0x0000 on customer entries the numbered space belongs to the curator, otherwise identifiers collide
One register per line the parser reads line by line; a flow map wrapped onto two lines loses everything after the first
Renaming a model creates a new file the old one may be in use in another project, so it is never deleted

The manual route is still there: copy devices/modbus/_template.yaml and fill in the register map from the device manual.

Modbus slave — the panel answers

The panel is not only a master. It can be a slave, so a supervisory SCADA system, a PLC or Home Assistant can read its state and send setpoints. The panel still runs completely without them — the supervisory system is a window out, not a condition of running.

modbus_slave:
  rtu: false        # answer on the RS485 line
  tcp: true         # answer over TCP
  unit: 9           # the panel's unit ID
  port: 502
  word_order: big   # word order of 32-bit values
  tags:
    - { tag: boiler_temp }                     # 4x 0-1, read only
    - { tag: setpoint_temp, writable: true }   # 4x 2-3
    - { tag: pump }                            # 0x 0, bit

In the editor: RS485 → Modbus RTU slave, or Ethernet → Modbus TCP slave. The page shows exactly the map the integrator will read — both the protocol address and the number as it appears in a manual.

How addresses are assigned

Automatically, in list order: bool tags become coils (0x) from 0, everything else becomes holding registers (4x) from 0, where i32, u32 and f32 occupy two registers each. The address is written into the package explicitly, so reordering the tags in the editor does not shift the map. The order can be changed with the arrow buttons — it is part of the configuration, not cosmetics.

A write is a command

A tag without writable answers a write with exception 0x02; it never silently succeeds. The same rule as for WebSocket and MQTT: what may be written is decided by the panel, not by whoever is asking.

Other deliberate decisions:

  • FC6 (write single register) against a 32-bit value is refused — half a value written is worse than a refusal.
  • FC16 validates the whole range before writing anything. A half-executed write would leave the machine in an undefined state.
  • Reading a range that lies even partly outside the map returns an exception. Zeros would send the integrator looking for a fault at their end.
  • A broadcast (address 0) on RTU is executed but not answered, as the standard requires; otherwise two slaves would transmit at once.

Traps

Trap What to do
Master and slave on the same RS485 line a line has one master — the build refuses it and the editor shows it in red on the page
Wrong word order word_order has to match what the SCADA system expects — the same trap as on the master side
Several SCADA clients at once the TCP slave serves one connection; each additional one would cost 6–8 kB of RAM the S3 does not have spare

Diagnostics: the serial command VUI! prints mbslv=<requests>,<exceptions>. A rising exception count means the SCADA system is reading outside the map or trying to write a tag it has no right to.

Common traps

Trap What to do
Nonsense f32 values swap word_order (big ↔ little)
Address off by one the manufacturer's documentation counts from 1, or uses the 3xxxx notation — here the address is always the 0-based protocol address
Device does not answer over RTU check baud rate, parity, the A/B wires and the line termination
TCP target behind NAT or on another segment the panel and the device belong on the same isolated machine network