Skip to content

Per-register Modbus units - #70

Open
asmundg wants to merge 1 commit into
tjhowse:masterfrom
asmundg:upstream-per-register-units
Open

asmundg wants to merge 1 commit into
tjhowse:masterfrom
asmundg:upstream-per-register-units

Conversation

@asmundg

@asmundg asmundg commented Sep 25, 2026 •

Copy link
Copy Markdown

Adds an optional unit field to each register, so a single modbus4mqtt instance can read and write registers on more than one Modbus unit over one connection. This helps with gateways, and with controllers that expose separate buses as separate units. For example, the Carlo Gavazzi BH8-CTRLX smart-house controller gives the controller and each extension module its own Modbus ID (CTRLX manual, section 3.4.2.3, PDF).

Registers without unit keep using the connection's device_address, so existing configs behave as before.

registers:
  - pub_topic: "bus0/input"
    address: 17
  - pub_topic: "bus1/input"
    address: 17
    unit: 2

Changes

  • modbus_interface keeps separate input and holding tables for each unit. poll() reads and flushes writes one unit at a time, and each read and write passes its unit as device_id.
  • add_monitor_register, get_value and set_value take an optional unit argument, and modbus4mqtt.py passes the register's unit through.
  • The README documents the new field.

Testing

  • New test test_registers_poll_and_write_on_their_own_unit: polls the same address on two units and checks each unit's value, then checks that a write goes to the right unit.
  • All 39 tests pass. The 3 errors in tests/test_modbus_server.py also occur on master without this change.
  • This runs daily against a BH8-CTRLX with one extension module: the controller's bus on unit 1 and the module's bus on unit 2.

This PR is independent of #71. The two touch adjacent lines in modbus4mqtt.py and the README option table, so whichever merges second needs a small rebase.

🤖 Generated with Claude Code

A register can name its own unit with the new `unit` option. Registers
on every unit share one connection, so a single instance reaches every
device behind a gateway or a controller that exposes several units.
The Carlo Gavazzi BH8-CTRLX, for example, gives the controller and each
extension module its own Modbus ID.
Registers without `unit` use the connection's device_address as before.

Each unit gets its own input and holding tables. poll() reads and
flushes writes per unit, and every read and write passes its unit as
device_id.
@asmundg
asmundg force-pushed the upstream-per-register-units branch from 6276217 to 7b77e5e Compare September 25, 2026 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant