Skip to main content

Modbus

The Modbus page lets you discover Modbus devices on the network, scan for active data points, and map those points to GEM zones for monitoring and control.

Prerequisites

Before using this page, create a Modbus device in System > Devices with the driver set to modbus. If no Modbus device exists, the page displays a yellow warning message directing you to create one first.

If multiple Modbus devices exist, a device selector appears at the top of the page to choose which one to work with.

Tabs

The page has seven tabs: Register Browser, Watch List, Trending, Diagnostics, Zone Mapping, Network Tools, and Settings. The legacy Network Scan and Point Discovery flows are now consolidated under Network Tools and Register Browser respectively.

Register Browser — Discovery

The Register Browser includes a Discover button that walks the four Modbus address spaces (coils, discrete inputs, holding registers, input registers) from address 0 and reports which addresses are actually mapped on the device. Useful for sparsely-documented devices where the manual doesn't list the full register map.

  • Read-only — never writes to the device
  • Walks one register at a time, expands to 16-at-a-time chunked reads once it finds a contiguous block of 4+
  • Bails per-space after a configurable run of consecutive gaps (default 32) — most small devices have a low-address mapped band and nothing above
  • "Scan to" controls the upper bound (default 256). Raise if you suspect mapped addresses higher up.
  • Bails on transport errors (timeout, port closed, ENETUNREACH) so a dead bus doesn't burn the whole probe budget

Results are grouped by space and show contiguous blocks with sample values. Click Load → on a block to populate the reader form and read that range immediately.


Network Scan Tab

The Network Scan tab finds Modbus devices (slaves) on the bus by sending test reads to a range of unit IDs.

Scan Configuration

FieldRangeDefaultDescription
Start Unit ID1 - 2541First Modbus unit address to scan.
End Unit ID1 - 254254Last Modbus unit address to scan.
Timeout (ms)100 - 5000500How long to wait for each unit to respond.

Running a Scan

  1. Set the start and end unit IDs and timeout.
  2. Click Scan Network. The button changes to "Scanning..." while active.
  3. The page title updates to show scan progress (e.g., "Scanning 50/254").
  4. Click Cancel to stop the scan early. A message reports how many devices were found so far.
  5. When complete, a results table appears showing discovered devices.

Scan Results

The results table displays:

ColumnDescription
Unit IDThe Modbus slave address that responded.
StatusConnection status (online).
Test ValueThe value read from holding register 40001 on that unit.

:::warning Device ignores unit_id Many TCP-only Modbus devices (Brainboxes ED-series, Wago I/O, etc.) have no upstream RS-485 bus to route to, so they answer every unit_id with the same payload. When the driver detects 5 consecutive identical responses it aborts the scan early and emits a single warning row in the results table — unit_ids are effectively meaningless on that device, pick any. :::


Point Discovery Tab

The Point Discovery tab reads specific register ranges on a Modbus unit to find active data points.

Discovery Configuration

FieldDefaultDescription
Unit ID1The Modbus slave address to scan for points.
Coils (0x)1 - 100Start and end addresses for coil discovery.
Discrete Inputs (1x)10001 - 10100Start and end addresses for discrete input discovery.
Holding Registers (4x)400001 - 400100Start and end addresses for holding register discovery (Kohler extended format).
Input Registers (3x)300001 - 300100Start and end addresses for input register discovery (Kohler extended format).
note

Address ranges use the Kohler extended format where the prefix digit indicates the register type (0x = coils, 1x = discrete inputs, 3x = input registers, 4x = holding registers). The driver handles the address conversion automatically.

Running Discovery

  1. Set the unit ID and adjust register ranges as needed.
  2. Click Discover Points. The button changes to "Discovering..." while active.
  3. Click Cancel to stop discovery early.
  4. When complete, a results table shows all points that returned valid data.

Discovery Results

The results table displays:

ColumnDescription
TypeRegister type with Modbus designation: Coil (0x), Discrete Input (1x), Holding Register (4x), or Input Register (3x).
AddressThe register address.
Current ValueThe value currently stored at that address.

Each row has a link icon in the toolbox column. Click it to select that point for zone mapping.

Mapping a Point to a Zone

When you click the link icon on a discovered point, a mapping bar appears above the table with these fields:

FieldDescription
Point TypeThe type of Modbus mapping to create. See Point Types below.
SubsystemThe GEM subsystem the target zone belongs to (e.g., climate, lighting).
ZoneThe specific zone to map this point to. The list updates based on the selected subsystem.

Click Map to create the mapping. The point's address is stored as a zone attribute with a prefix indicating the register type:

PrefixRegister Type
c_Coil
i_Discrete Input
hr_Holding Register
ir_Input Register

Point Types

The following mapping types are available:

Point TypeDescription
modbus_setpoint_readRead setpoint value
modbus_setpoint_writeWrite setpoint value
modbus_temperature_readRead temperature sensor
modbus_humidity_readRead humidity sensor
modbus_humidity_writeWrite humidity value
modbus_fan_mode_readRead fan mode setting
modbus_fan_mode_writeWrite fan mode setting
modbus_system_mode_readRead system mode (heat/cool/auto)
modbus_system_mode_writeWrite system mode
modbus_occupancy_mode_readRead occupancy mode
modbus_occupancy_mode_writeWrite occupancy mode
tip

If a point is already mapped to a zone, clicking its link icon will auto-populate the subsystem, zone, and point type fields with the existing mapping.


Zone Mappings Tab

The Zone Mappings tab shows all existing Modbus point-to-zone mappings across the system.

Mappings Table

ColumnDescription
ZoneThe zone name the point is mapped to.
AttributeThe Modbus point type attribute name (e.g., modbus_temperature_read).
Modbus AddressThe register address with prefix (e.g., hr_400001).
QualityData quality indicator, if available.

Each row has a delete icon to remove the mapping (the zone attribute is deleted).

If no mappings exist, the tab displays "No mapped Modbus points found."


Zone Mapping Tab

The Zone Mapping tab links a register selected in the Register Browser to a zone attribute. Selecting a register in the browser switches to this tab automatically.

Mapping Fields

FieldDescription
SubsystemFilter for the Zone dropdown.
ZoneThe target zone for this mapping.
Point TypeThe Modbus point name (e.g., temperature, setpoint, system_mode). Stored as modbus_<point>_read / modbus_<point>_write.
Data TypeUINT16, INT16, UINT32, INT32, FLOAT32, FLOAT64, Bits, or String. Adopted automatically when the source register declares one.
Byte Orderbig_endian, little_endian, big_endian_swap, little_endian_swap. Adopted from the source register when set.
ScaleMultiplier applied to the decoded value. Defaults to 1.
OffsetAdded after scaling. Defaults to 0.
Poll Interval (ms)Optional per-mapping override of the device-wide polling rate. Leave blank to inherit. Stored as the companion attribute modbus_<point>_poll_interval.

Test Read

Click Test Read before saving to issue a one-shot read against the selected register using the chosen data type and byte order. The result panel shows:

  • Raw — Raw register words returned by the device
  • Decoded — Value after data-type / byte-order interpretation
  • Scaled — Value after applying scale and offset (only shown when scale ≠ 1 or offset ≠ 0)

Useful for confirming the right data type / byte order before committing the mapping. Selecting a different register clears the result.

Click Map Point to persist the mapping. Test reads do not modify any attributes.


Network Tools Tab

The Network Tools tab consolidates network discovery, raw protocol access, and register-map import/export.

Network Scan

Sends test reads to a range of unit IDs to find Modbus slaves on the bus.

FieldRangeDefaultDescription
Start Unit ID1 - 2541First Modbus unit address to scan.
End Unit ID1 - 254254Last Modbus unit address to scan.
Timeout (ms)100 - 5000500How long to wait for each unit to respond.
Test Register40001Register read on each unit to detect a response.

Device Identification

Sends FC 43 (Read Device Identification) to a chosen unit ID. Returns vendor name, product code, revision, and any extended object IDs the device exposes. If the device doesn't support FC 43, a notice is shown.

Raw FC Inspector

Sends a raw Modbus function code and shows the parsed response alongside a hex view. Useful for vendor-specific gear and FCs the higher-level browser doesn't wrap.

Function CodeWrappedInputs
1 — Read Coilsyesaddress, length
2 — Read Discrete Inputsyesaddress, length
3 — Read Holding Registersyesaddress, length
4 — Read Input Registersyesaddress, length
5 — Write Single Coilyesaddress, ON/OFF
6 — Write Single Registeryesaddress, integer
15 — Write Multiple Coilsyesaddress, comma-separated booleans
16 — Write Multiple Registersyesaddress, comma-separated integers
17 — Report Server IDyes
22 — Mask Write Registeryesaddress, AND mask, OR mask
43 — Read Device Identificationyesread code (1-4), object ID
65-72, 100-110 — User-Definedraw byteshex byte string (e.g. AA BB CC DD)
warning

FCs outside the listed set (e.g. FC 7, 8, 11) are not supported by the underlying library and return an explanatory error rather than hanging the connection.

The response panel shows the raw bytes (hex) followed by the parsed body. Errors render in a red panel with the function code that failed.

Register Map Templates

Saves a JSON array of register definitions on the device as the register_map attribute. The map drives Register Browser column hints, default data types, and address labels.

ActionDescription
LoadReads the saved register map from the device.
SaveValidates and stores the textarea contents back to the device.
Export JSONDownloads the textarea as modbus_register_map_<device>.json.
Export CSVDownloads the textarea as a CSV using the standard column order.
Import CSVParses a CSV file (header row required) and replaces the textarea with equivalent JSON. Click Save afterwards to persist.

CSV columns (header names, lowercase): address, name, description, data_type, byte_order, scale, offset, writable

The address column is required. writable accepts 1/true/yes/y (any case). scale, offset, and address are coerced to numbers when parseable. Empty cells are dropped from the row object.


Diagnostics Tab

Surfaces the Modbus driver's runtime counters and a recent communication log. Useful for narrowing down whether a problem is on the wire, in the device, or in GEM's coercion path.

Summary Cards

  • Reads / Writes — total + success / error counters since boot or last clear
  • Timeouts — count of timeouts (subset of errors)
  • Conn Drops — how many times the underlying TCP socket has closed
  • Client Recycles — how many times the driver has torn down and rebuilt the modbus client (the watchdog escalates here when consecutive errors cross the threshold AND no successful op has happened in ~2 min)
  • Last Success — relative time since the most recent successful read/write
  • Uptime — time since the diagnostics counters were last reset

A red Last Client Error card appears below the summary when the underlying TCP/RTU client has emitted a transport-level error (distinct from app-layer Modbus exceptions, which mean the device responded).

Communication Log

Last 200 entries. Each row shows command, function code, address, unit_id, the coerced wire value (so you can see exactly what was sent), duration, status, and any error. A Class:2 error in the error column means the device returned a Modbus exception — app-layer, not transport — so the socket is fine.

Per-installation Watchdog Tuning

op_failure_threshold (default 5) and op_staleness_ms (default 120000) are device attributes. Raise the threshold on long RS-485 segments where ~5 consecutive timeouts is normal; lower the staleness in latency-sensitive deployments where a wedged socket needs to be caught faster.

Value Coercion

Writes coerce stringified arguments at the driver boundary — 'false' from a saved macro is normalized to JS false before reaching the underlying library. Garbage values (e.g. 'maybe' for a coil) return an explicit error and do not send the write, so a typo never silently energizes a relay.


  • Devices - Creating the Modbus device
  • Zones - Zone configuration