diff --git a/esphome/components/modbus_client/__init__.py b/esphome/components/modbus_client/__init__.py index a4f6ef585ac..015ebaa3f16 100644 --- a/esphome/components/modbus_client/__init__.py +++ b/esphome/components/modbus_client/__init__.py @@ -487,7 +487,6 @@ async def write_multiple_registers_to_code(config, action_id, template_arg, args templ = await cg.templatable(values, args, cg.std_vector.template(cg.uint16)) cg.add(var.set_values_template(templ)) else: - # Shared flash table; play() sends without allocating (ESP8266 copies it to the stack first). arr = cg.shared_progmem_array( "modbus_client_registers", cg.uint16, cg.ArrayInitializer(*values) ) @@ -583,7 +582,6 @@ async def read_write_multiple_registers_to_code(config, action_id, template_arg, templ = await cg.templatable(values, args, cg.std_vector.template(cg.uint16)) cg.add(var.set_values_template(templ)) else: - # Shared flash table; play() sends without allocating (ESP8266 copies it to the stack first). arr = cg.shared_progmem_array( "modbus_client_registers", cg.uint16, cg.ArrayInitializer(*values) ) diff --git a/esphome/components/modbus_client/modbus_client.h b/esphome/components/modbus_client/modbus_client.h index 9972ad47584..902506ca1ac 100644 --- a/esphome/components/modbus_client/modbus_client.h +++ b/esphome/components/modbus_client/modbus_client.h @@ -153,16 +153,6 @@ class ModbusClientSendAction : public ClientActionBase, Trigger, std::span> response_trigger_; }; -/// Typed actions: these do NOT override the raw on_response, so the base ModbusClientDevice default runs -/// the shared dispatch (validation gate + decode) and the typed callbacks below fire directly on the -/// action. A reply the gate diverts (not a standard-conformant transaction) fires the on_custom_response -/// trigger with the raw request/response PDUs, so non-standard replies stay handleable; the spans are only -/// valid for the duration of the trigger. (For a typed-built request the gate can only divert on the -/// response, never with an exception status - real device exceptions arrive via on_error, which -/// ClientActionBase already routes straight to its trigger, so the typed callbacks below only ever see a -/// success status.) Each typed callback still checks succeeded() before firing its trigger: that branch -/// is unreachable today, and is kept so a future change to that interception cannot silently deliver an -/// exception as a successful reply. /// Calls fn with a RAM-readable span of a static values table. On ESP8266 the table is in PROGMEM, which the /// PDU builders cannot read directly, so it is copied to the stack first; the schema caps len at MAX. template void with_static_values(const T *data, size_t len, F &&fn) { @@ -175,6 +165,16 @@ template void with_static_values(const T *da #endif } +/// Typed actions: these do NOT override the raw on_response, so the base ModbusClientDevice default runs +/// the shared dispatch (validation gate + decode) and the typed callbacks below fire directly on the +/// action. A reply the gate diverts (not a standard-conformant transaction) fires the on_custom_response +/// trigger with the raw request/response PDUs, so non-standard replies stay handleable; the spans are only +/// valid for the duration of the trigger. (For a typed-built request the gate can only divert on the +/// response, never with an exception status - real device exceptions arrive via on_error, which +/// ClientActionBase already routes straight to its trigger, so the typed callbacks below only ever see a +/// success status.) Each typed callback still checks succeeded() before firing its trigger: that branch +/// is unreachable today, and is kept so a future change to that interception cannot silently deliver an +/// exception as a successful reply. template class TypedClientActionBase : public ClientActionBase { public: Trigger, std::span> *get_custom_response_trigger() {