Skip to content
Get started

Modbus Controller Output

The modbus_controller platform creates an output from a modbus_controller. The goal is to write a value to a modbus register on a device.

  • address (Required, int): start address of the first register in a range (can be decimal or hexadecimal).

  • value_type (Optional, default U_WORD): data type of the modbus register data. The default data type for modbus is a 16 bit integer in big endian format (MSB first). This option applies only to register_type: holding; it is not a valid option with register_type: coil.

    • 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)
    • FP32 (32 bit IEEE 754 floating point from 2 registers)
    • FP32_R (32 bit IEEE 754 floating point - same as FP32 but 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).

  • register_type (Optional):

    • coil : Write Coil - Write the ON/OFF status of a discrete coil in the device with Function Code 5 or 15. This will create a binary output.
    • holding : Write Holding Registers - write contents of holding registers in the device with Function Code 6 or 16. This will create a float output.
  • multiply (Optional, float): multiply the incoming value with this factor before writing it to the device. Ignored if write_lambda is defined. Only valid for register_type: holding.

  • 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.

  • write_lambda (Optional, lambda): Lambda is evaluated before the modbus write command is created. The value is passed in as float x (or bool x for register_type: coil).

    Parameters passed into the lambda

    • x (float or bool): the new value being set — a float for register_type: holding, or a bool for register_type: coil

    • item (ModbusFloatOutput * / ModbusBinaryOutput *): 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 output’s own register type. Also a SensorItem subclass, so the configured address, offset, bitmask, etc. are accessible.

    • payload: Deprecated, removed in 2027.3.0 - use item instead. An empty buffer to fill (push_back/clear/assign - not the full std::vector API); if filled, the return value is ignored and the payload is sent instead. Its element type, and what the bytes mean, depend on register_type (each is that output type’s historical buffer meaning, preserved as-is):

      • for register_type: holding : RegisterValues &payload - add 16-bit raw modbus register words. The write covers exactly the registers you add, so the payload must not be wider than the register count implied by value_type (1 for the word types, 2 for the dword/float types, 4 for the qword types) or the write is dropped with an error.
      • for register_type: coil : PduBuffer &payload - add the bytes of a full modbus request frame - the leading device-address byte followed by the PDU (function code + data); the CRC is added automatically. Unlike custom_pdu, the device-address byte is part of this payload.

    Possible return values for the lambda:

    • return <FLOATING_POINT_NUMBER / BOOL>; the value to be written to the device.
    • return {}; if the lambda handled (or deliberately skipped) the write itself, for example via item->write_*().
  • offset (Optional, int): Offset from start address in bytes (only required for uncommon response encodings). If more than one register is written in a command this value is used to find the start of this datapoint relative to start address. The component calculates the size of the range based on offset and size of the value type.

  • id (Optional, ID): Manually specify the ID used for code generation.

All other options from Output.

output:
- platform: modbus_controller
modbus_controller_id: modbus1
address: 2048
register_type: holding
value_type: U_WORD
multiply: 1000

The same with lambda:

output:
- platform: modbus_controller
modbus_controller_id: modbus1
address: 2048
value_type: U_WORD
write_lambda: |-
ESP_LOGD("main","Modbus Output incoming value = %f",x);
return x * 1000 ;