18class ModbusController;
26#pragma GCC diagnostic push
27#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
28using modbus::ModbusExceptionCode;
29using modbus::ModbusFunctionCode;
30using modbus::ModbusRegisterType;
31#pragma GCC diagnostic pop
42ESPDEPRECATED(
"Use modbus::helpers::get_data() instead. Removed in 2027.2.0",
"2026.8.0")
43T get_data(
std::span<const uint8_t>
data,
size_t buffer_offset) {
48ESPDEPRECATED(
"Use modbus::helpers::bit_from_packed() instead. Removed in 2027.2.0",
"2026.4.0")
49inline
bool coil_from_vector(
int coil, const
std::vector<uint8_t> &
data) {
54ESPDEPRECATED(
"Use modbus::helpers::bit_from_packed() instead. Removed in 2027.2.0",
"2026.8.0")
55inline
bool coil_from_vector(
int coil,
std::span<const uint8_t>
data) {
182using SensorSet = std::set<SensorItem *, SensorItemsComparator>;
205 void on_response(std::span<const uint8_t> request_pdu, std::span<const uint8_t> response_pdu)
override;
207 void on_sent(std::span<const uint8_t> request_pdu)
override;
208 void on_not_sent(std::span<const uint8_t> request_pdu)
override;
209 bool on_no_response(std::span<const uint8_t> request_pdu)
override;
225 using modbus::ModbusClientDevice::clear_tx_queue_for_device;
226 using modbus::ModbusClientDevice::queue_pdu;
227 using modbus::ModbusClientDevice::write_multiple_coils;
228 using modbus::ModbusClientDevice::write_multiple_registers;
229 using modbus::ModbusClientDevice::write_single_coil;
230 using modbus::ModbusClientDevice::write_single_register;
248 void on_response(std::span<const uint8_t> request_pdu, std::span<const uint8_t> response_pdu)
override;
286 return this->device_.queue_pdu(pdu,
options);
320 void on_response(std::span<const uint8_t> request_pdu, std::span<const uint8_t> response_pdu)
override;
329#pragma GCC diagnostic push
330#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
332 "One-shot writes go through the entity write helpers (WriterDevice) or the modbus_client actions, and "
333 "polling runs through PollingDevice. Removed in 2027.3.0",
341 RegisterRange &&
range);
349 ModbusCommandItem(
const ModbusCommandItem &other);
350 ModbusCommandItem(ModbusCommandItem &&other)
noexcept;
351 ModbusCommandItem &operator=(ModbusCommandItem &&) =
delete;
354 std::function<void(
EntityType register_type, uint16_t start_address, std::span<const uint8_t> data)> on_data_func;
363 bool pending_removal{
false};
366 void on_response(std::span<const uint8_t> request_pdu, std::span<const uint8_t> response_pdu)
override;
370 void on_not_sent(std::span<const uint8_t> request_pdu)
override;
372 void on_sent(std::span<const uint8_t> request_pdu)
override;
374 bool on_no_response(std::span<const uint8_t> request_pdu)
override;
376 uint16_t register_address()
const {
return this->start_address_; }
377 uint16_t register_count()
const {
return this->register_count_; }
378 EntityType register_type()
const {
return this->register_type_; }
385 bool send(modbus::CommandOptions
options = {});
397 static ModbusCommandItem create_read_command(
398 ModbusController *modbusdevice,
EntityType register_type, uint16_t start_address, uint16_t register_count,
399 std::function<
void(
EntityType register_type, uint16_t start_address, std::span<const uint8_t> data)> &&handler);
409 static ModbusCommandItem create_write_multiple_command(ModbusController *modbusdevice, uint16_t start_address,
410 uint16_t register_count,
const std::vector<uint16_t> &values);
419 static ModbusCommandItem create_write_single_command(ModbusController *modbusdevice, uint16_t start_address,
428 static ModbusCommandItem create_write_single_coil(ModbusController *modbusdevice, uint16_t
address,
bool value);
437 static ModbusCommandItem create_write_multiple_coils(ModbusController *modbusdevice, uint16_t start_address,
438 const std::vector<bool> &values);
446 static ModbusCommandItem create_custom_command(
447 ModbusController *modbusdevice,
const std::vector<uint8_t> &values,
448 std::function<
void(
EntityType register_type, uint16_t start_address, std::span<const uint8_t> data)> &&handler =
458 static ModbusCommandItem create_custom_command(
459 ModbusController *modbusdevice,
const std::vector<uint16_t> &values,
460 std::function<
void(
EntityType register_type, uint16_t start_address, std::span<const uint8_t> data)> &&handler =
465 uint16_t register_count) {
466 this->function_code_ = function_code;
467 this->register_type_ = register_type;
468 this->start_address_ = start_address;
469 this->register_count_ = register_count;
472 uint16_t start_address_{0};
473 uint16_t register_count_{0};
476 const SmallInlineBuffer<8> *custom_pdu_{
nullptr};
477 ModbusController *controller_{
nullptr};
479#pragma GCC diagnostic pop
484inline bool offline_retry_due(uint16_t update_counter, uint16_t module_offline_at, uint16_t offline_skip_updates) {
485 return static_cast<uint16_t
>(update_counter + 1 - module_offline_at) % (offline_skip_updates + 1) == 0;
505 void setup()
override;
513#pragma GCC diagnostic push
514#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
517 ESPDEPRECATED(
"Use the entity write helpers or the modbus_client actions instead. Removed in 2027.3.0",
"2026.9.0")
518 void queue_command(ModbusCommandItem command);
522 ESPDEPRECATED("Serves only ModbusCommandItem's own callbacks. Removed in 2027.3.0", "2026.9.0")
523 void unqueue_command(const ModbusCommandItem *command);
524#pragma GCC diagnostic pop
529 ESPDEPRECATED(
"Write acknowledgements are handled by the writing entity's own device. Removed in 2027.3.0",
533 void set_online(
bool online,
int function_code,
int register_address);
581#pragma GCC diagnostic push
582#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
584#pragma GCC diagnostic pop
624 float_value =
static_cast<float>(number);
633ESPDEPRECATED(
"Pass the offset explicitly: payload_to_float(data, item, item.offset). Removed in 2027.2.0",
"2026.8.0")
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
This class simplifies creating components that periodically check a state.
Small buffer optimization - stores data inline when small, heap-allocates for large data This avoids ...
void set(const uint8_t *src, size_t size)
Set buffer contents, allocating heap if needed.
Read-only view of Modbus-packed bits: bit 0 of byte 0 is the first bit (LSB first),...
The shared feedback half of a controller-owned hub device: online/offline tracking,...
ModbusController * controller_
void set_controller(ModbusController *controller)
ControllerDevice(ModbusController *controller)
void notify_online_(std::span< const uint8_t > request_pdu)
void on_error(std::span< const uint8_t > request_pdu, modbus::ExceptionCode exception_code) override
void on_sent(std::span< const uint8_t > request_pdu) override
ControllerDevice()=default
bool on_no_response(std::span< const uint8_t > request_pdu) override
void on_not_sent(std::span< const uint8_t > request_pdu) override
void on_response(std::span< const uint8_t > request_pdu, std::span< const uint8_t > response_pdu) override
bool dispatched_
Write-path state for WriterEntity's forwarders, packed into the base's tail padding.
modbus::CommandOptions write_options_
bool write_buffer_deprecated_warned_
void add_sensor_item(SensorItem *item)
Registers a sensor with the controller. Called by esphomes code generator.
uint8_t cmd_non_responses_
consecutive non-responses; drives can_send() and offline detection
void command_sent(int function_code, int register_address)
Fire the on_command_sent trigger (called when a command's frame reaches the wire).
uint8_t device_address() const
void set_offline_skip_updates(uint16_t offline_skip_updates)
called by esphome generated code to set the offline_skip_updates
std::list< std::unique_ptr< ModbusCommandItem > > one_shot_command_items_
Dynamically queued one-shot commands (writes, custom commands).
CallbackManager< void(int, int)> command_sent_callback_
Command sent callback.
void increment_non_response_count()
A command timed out; bump the consecutive-timeout counter used by can_send()/offline detection.
CallbackManager< void(int, int)> offline_callback_
Server offline callback.
void add_on_command_sent_callback(F &&callback)
Set callback for commands.
SensorSet sensorset_
Collection of all sensors for this component.
FixedVector< PollingDevice > polling_devices_
One persistent PollingDevice per register range.
uint8_t max_cmd_retries_
How many times we will retry a command if we get no response.
void set_read_options(modbus::CommandOptions options)
called by esphome generated code with the read-side command options applied to every poll
const modbus::CommandOptions & read_options() const
the read-side command options applied to every poll
bool can_send()
Whether more retries are allowed before the device is considered offline.
modbus::CommandOptions read_options_
read-side command options applied to every poll
ModbusController(modbus::ModbusClientHub *hub, uint8_t address)
void sweep_completed_one_shots_()
Erases one-shot commands flagged by unqueue_command().
uint8_t get_max_cmd_retries()
get how many times a command will be (re)sent if no response is received
void create_polling_commands_()
Group the registered sensors into contiguous ranges and create one PollingDevice per range.
uint16_t module_offline_at_
update_counter_ value at which the module went offline (for offline_skip_updates timing)
void set_max_cmd_retries(uint8_t max_cmd_retries)
called by esphome generated code to set the max_cmd_retries.
bool module_offline_
if module didn't respond the last command
ESPDEPRECATED("Write acknowledgements are handled by the writing entity's own device. Removed in 2027.3.0", "2026.9.0") void on_write_register_response(EntityType register_type
Handles a write command acknowledgement (used by write command on_data_func handlers).
uint16_t offline_skip_updates_
how many updates to skip if module is offline
modbus::ModbusClientHub * hub() const
The hub and modbus address this controller talks to.
bool get_module_offline()
get if the module is offline, didn't respond the last command
ESPDEPRECATED("Use the entity write helpers or the modbus_client actions instead. Removed in 2027.3.0", "2026.9.0") void queue_command(ModbusCommandItem command)
Queues a one-shot modbus command (writes, custom commands); taken by value, so std::move to avoid a c...
void set_online(bool online, int function_code, int register_address)
Update the online/offline state after a response or a run of timeouts, firing the callbacks.
uint16_t update_counter_
counts update() cycles; drives the offline-retry cadence
uint16_t std::span< const uint8_t > data
void add_on_online_callback(F &&callback)
Set callback for online changes.
void add_on_offline_callback(F &&callback)
Set callback for offline changes.
void dump_config() override
modbus::ModbusClientHub * hub_
The hub this controller's commands/entities send through, and the modbus address they target.
CallbackManager< void(int, int)> online_callback_
Server online callback.
A persistent hub device that polls one register range - the read-side mirror of WriterDevice.
uint16_t register_address() const
void on_response(std::span< const uint8_t > request_pdu, std::span< const uint8_t > response_pdu) override
EntityType register_type() const
uint16_t register_count() const
bool queue(modbus::CommandOptions options={})
Queue this range's read (or its sensor's custom PDU) on the hub. False = refused, no callback follows...
PollingDevice(ModbusController &controller, RegisterRange &&range)
virtual void parse_and_publish(std::span< const uint8_t > data)=0
Parse this sensor's slice out of its range's response and publish it.
modbus::EntityType register_type
RangeReuse reuse_previous_range
void set_address(uint16_t address)
Sets the configured address, and points the range base at it.
void set_offset_from_start_address(uint8_t offset)
Records the offset as configured, and seeds the resolved position with it.
virtual uint16_t entity_count() const
Entities this item spans: one bit for bit-addressed types, ceil(bytes / 2) registers for RAW with a r...
SensorValueType sensor_value_type
void set_register_size(uint8_t register_size)
uint16_t range_start_address
First register of the range this sensor is polled in; equals start_address for an unpolled item.
void set_custom_pdu(std::initializer_list< uint8_t > pdu)
SmallInlineBuffer< 8 > custom_pdu
uint8_t offset
Position of this sensor's data within its range's response - a byte offset for registers,...
uint8_t offset_from_start_address
The offset exactly as configured: measured from this sensor's own start_address, where offset is meas...
bool addresses_bits() const
Coils and discrete inputs address individual bits; every other type addresses 16-bit registers.
uint16_t write_address() const
Address a write entity (switch/number/select) targets, derived from its resolved position within the ...
virtual size_t get_register_size() const
Bytes this item's registers occupy in a response: one per bit for bit-addressed types; response_size ...
bool operator()(const SensorItem *lhs, const SensorItem *rhs) const
The write side of a ControllerDevice, owned by the writer entities through WriterEntity,...
void on_response(std::span< const uint8_t > request_pdu, std::span< const uint8_t > response_pdu) override
void set_write_options(modbus::CommandOptions options)
modbus::CommandOptions write_options() const
void on_error(std::span< const uint8_t > request_pdu, modbus::ExceptionCode exception_code) override
void warn_write_buffer_deprecated(const LogString *platform, uint16_t address)
Warn once per entity that filling the write_lambda buffer parameter is deprecated (the entity is now ...
bool send_raw_frame_deprecated(std::span< const uint8_t > frame)
Send a legacy raw frame (address + function code + data) to the frame's own address.
Gives a writer entity the write API of the WriterDevice it owns.
void set_write_options(modbus::CommandOptions options)
bool write_multiple_coils(uint16_t address, modbus::PackedBits bits)
void warn_write_buffer_deprecated_(const LogString *platform, uint16_t address)
bool queue_pdu(std::span< const uint8_t > pdu, modbus::CommandOptions options)
bool dispatched() const
Whether the lambda called a request helper since the last clear_dispatched_().
void set_controller_(ModbusController *controller)
bool write_single_coil(uint16_t address, bool value)
bool write_single_register(uint16_t address, uint16_t value)
bool send_raw_frame_deprecated_(std::span< const uint8_t > frame)
void clear_tx_queue_for_device()
bool queue_pdu(std::span< const uint8_t > pdu)
bool write_multiple_coils(uint16_t address, std::span< const bool > values)
bool write_multiple_registers(uint16_t address, std::span< const uint16_t > values)
bool value_type_is_float(SensorValueType v)
T get_data(const uint8_t *data, size_t buffer_offset)
Extract data from modbus response buffer.
constexpr uint16_t register_width_for(SensorValueType v)
Number of 16-bit registers a value of this type occupies (RAW counts as one register).
bool bit_from_packed(int bit, std::span< const uint8_t > data)
Extract coil data from modbus response buffer Responses for coil are packed into bytes .
bool is_entity_type_binary(EntityType type)
Coils and discrete inputs are the bit-addressed entity tables; the other types are 16-bit registers.
std::optional< int64_t > payload_to_number(const uint8_t *data, size_t size, SensorValueType sensor_value_type, uint8_t offset, uint32_t bitmask)
Convert a raw response payload to a number.
const std::vector< uint8_t > & data
std::set< SensorItem *, SensorItemsComparator > SensorSet
ESPDEPRECATED("Use modbus::helpers::get_data() instead. Removed in 2027.2.0", "2026.8.0") T get_data(std
RangeReuse
How an item relates to the register range built just before it (same register type,...
float payload_to_float(std::span< const uint8_t > data, const SensorItem &item, uint8_t offset)
Convert vector<uint8_t> response payload to float.
class ESPDEPRECATED("One-shot writes go through the entity write helpers (WriterDevice) or the modbus_client actions, and " "polling runs through PollingDevice. Removed in 2027.3.0", "2026.9.0") ModbusCommandItem bool offline_retry_due(uint16_t update_counter, uint16_t module_offline_at, uint16_t offline_skip_updates)
A single modbus command.
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.
const SmallInlineBuffer< 8 > * custom_pdu
A custom range polls this PDU, referenced from the sensor that opened the range.
modbus::EntityType register_type