Skip to content
Get started

Modbus Controller Select

The modbus_controller Select platform allows you to create a Select from modbus registers.

  • address (Required, int): The start address of the first or only register of the Select (can be decimal or hexadecimal). Note that only Holding registers are supported.

  • optionsmap (Required, Map[str, int]): Provide a mapping from options (str) of this Select to values (int) of the modbus register and vice versa. All options and all values have to be unique.

  • value_type (Optional): The data type of the modbus data. Defaults to U_WORD.

    • U_WORD (unsigned 16 bit integer from 1 register = 16bit)
    • S_WORD (signed 16 bit integer from 1 register = 16bit)
    • U_WORD_S (unsigned 16 bit integer from 1 register with bytes swapped within the register = 16bit)
    • S_WORD_S (signed 16 bit integer from 1 register with bytes swapped within the register = 16bit)
    • U_DWORD (unsigned 32 bit integer from 2 registers = 32bit)
    • S_DWORD (signed 32 bit integer from 2 registers = 32bit)
    • U_DWORD_R (unsigned 32 bit integer from 2 registers low word first)
    • S_DWORD_R (signed 32 bit integer from 2 registers low word first)
    • U_QWORD (unsigned 64 bit integer from 4 registers = 64bit)
    • S_QWORD (signed 64 bit integer from 4 registers = 64bit)
    • U_QWORD_R (unsigned 64 bit integer from 4 registers low word first)
    • S_QWORD_R (signed 64 bit integer from 4 registers low word first)

WARNING

U_WORD_S and S_WORD_S are a rare, non-standard configuration: the two bytes within one 16-bit register are reversed (LSB first on the wire within that register). Modbus registers are big-endian (MSB first) per the specification. The _S suffix is not the same as _R (word order reversed / low word first across multiple registers).

  • skip_updates (Optional, int): Deprecated and no longer has any effect — every register range is polled on each update_interval. The key is still accepted (logging a config-time warning) and will be removed in 2027.3.0. To poll some registers less often, place those sensors on a second modbus_controller with the same address: and a slower update_interval:.

  • reuse_previous_range (Optional, boolean or auto): How this item relates to the register range built just before it (same register type, ascending address order). auto (default) joins when the addresses are adjacent and the item’s position in the reply is exact; true joins unconditionally, reading across address gaps; false always starts a new range here (later items may still extend it). See Register ranges. Replaces the deprecated force_new_range and register_count options, which will be removed in 2027.3.0 — the linked section covers migration.

  • lambda (Optional, lambda): Lambda to be evaluated every update interval to get the current option of the select.

    Parameters passed into lambda

    • x (int64_t ): The parsed integer value of the modbus data.

    • data (std::span<const uint8_t>): span containing the complete raw modbus response bytes for this select. Note: because the response contains data for all registers in the same range you have to use data[item->offset] to get the first response byte for your select.

    • item (ModbusSelect *): The select entity, a SensorItem subclass, so the configured address, offset, bitmask, etc. are accessible.

    Possible return values for the lambda:

    • return <std::string>; The new option for this Select.
    • return {}; Use default mapping (see optionsmap ).
  • write_lambda (Optional, lambda): Lambda to be evaluated on every update of the Select, before the new value is written to the modbus registers.

  • use_write_multiple (Optional, boolean): By default the modbus command Function Code 6 (Preset Single Registers) is used for setting the holding register if only one register is set. If your device only supports Function Code 16 (Preset Multiple Registers) set this option to true.

  • optimistic (Optional, boolean): Whether to operate in optimistic mode - when in this mode, any command sent to the Modbus Select will immediately update the reported state. Defaults to false.

  • All other options from Select.

# example
lambda: |-
ESP_LOGD("Reg1000", "Received value %lld", x);
ESP_LOGD("Reg1000", "Parsed from bytes 0x%x;0x%x", data[item->offset], data[item->offset + 1]);
if (x > 3) {
return std::string("Three");
}
  • x (const std::string& ): The option value to set for this Select.
  • value (int64_t ): The mapping value of x using optionsmap.
  • item (ModbusSelect *): The entity as its own modbus device: the write helpers and queue_pdu() are available - for example item->write_single_register(0x1234, 42) or item->queue_pdu(...) - regardless of the select’s own register type. Also a SensorItem subclass, so the configured address, offset, bitmask, etc. are accessible.
  • payload (RegisterValues &payload): Deprecated, removed in 2027.3.0 - use item instead. An empty buffer; the lambda can add (push_back/clear/assign - not the full std::vector API) the 16 bit register words to write in place of the mapping value. Unlike the number platform’s buffer, this is data words only - no device address or function code.

Possible return values for the lambda:

  • return <int64_t>; the value which should be written to the configured modbus registers. If there were data written to payload this value is ignored.
  • return {}; if the lambda handled (or deliberately skipped) the write itself, for example via item->write_*().
# example
write_lambda: |-
ESP_LOGD("Reg1000", "Set option to %s (%lld)", x.c_str(), value);
// re-use default option value from optionsmap
if (value == 0) {
return value;
}
// return own option value
if (x == "One") {
return 2;
}
// "Two" needs a vendor trigger register instead of the mapped write:
// drive it directly through the entity
if (x == "Two") {
item->write_single_register(0x2000, 1);
// the lambda must return something - return empty, the write is already done
return {};
}
// {} without an item-> write = skip this update entirely; nothing is sent
return {};
# Example configuration entry
select:
- platform: modbus_controller
name: "Modbus Select Register 1000"
address: 1000
value_type: U_WORD
optionsmap:
"Zero": 0
"One": 1
"Two": 2
"Three": 3