diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 58828c131d..e8dacf51bc 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -380,12 +380,19 @@ async def homeassistant_service_to_code( var = cg.new_Pvariable(action_id, template_arg, serv, False) templ = await cg.templatable(config[CONF_ACTION], args, None) cg.add(var.set_service(templ)) + + # Initialize FixedVectors with exact sizes from config + cg.add(var.init_data(len(config[CONF_DATA]))) for key, value in config[CONF_DATA].items(): templ = await cg.templatable(value, args, None) cg.add(var.add_data(key, templ)) + + cg.add(var.init_data_template(len(config[CONF_DATA_TEMPLATE]))) for key, value in config[CONF_DATA_TEMPLATE].items(): templ = await cg.templatable(value, args, None) cg.add(var.add_data_template(key, templ)) + + cg.add(var.init_variables(len(config[CONF_VARIABLES]))) for key, value in config[CONF_VARIABLES].items(): templ = await cg.templatable(value, args, None) cg.add(var.add_variable(key, templ)) @@ -458,15 +465,23 @@ async def homeassistant_event_to_code(config, action_id, template_arg, args): var = cg.new_Pvariable(action_id, template_arg, serv, True) templ = await cg.templatable(config[CONF_EVENT], args, None) cg.add(var.set_service(templ)) + + # Initialize FixedVectors with exact sizes from config + cg.add(var.init_data(len(config[CONF_DATA]))) for key, value in config[CONF_DATA].items(): templ = await cg.templatable(value, args, None) cg.add(var.add_data(key, templ)) + + cg.add(var.init_data_template(len(config[CONF_DATA_TEMPLATE]))) for key, value in config[CONF_DATA_TEMPLATE].items(): templ = await cg.templatable(value, args, None) cg.add(var.add_data_template(key, templ)) + + cg.add(var.init_variables(len(config[CONF_VARIABLES]))) for key, value in config[CONF_VARIABLES].items(): templ = await cg.templatable(value, args, None) cg.add(var.add_variable(key, templ)) + return var @@ -489,6 +504,8 @@ async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, arg serv = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg, serv, True) cg.add(var.set_service("esphome.tag_scanned")) + # Initialize FixedVector with exact size (1 data field) + cg.add(var.init_data(1)) templ = await cg.templatable(config[CONF_TAG], args, cg.std_string) cg.add(var.add_data("tag_id", templ)) return var diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index 46e89cb39f..4adda47b71 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -41,10 +41,14 @@ template class TemplatableStringValue : public TemplatableValue class TemplatableKeyValuePair { public: + // Default constructor needed for FixedVector::emplace_back() + TemplatableKeyValuePair() = default; + // Keys are always string literals from YAML dictionary keys (e.g., "code", "event") // and never templatable values or lambdas. Only the value parameter can be a lambda/template. // Using pass-by-value with std::move allows optimal performance for both lvalues and rvalues. template TemplatableKeyValuePair(std::string key, T value) : key(std::move(key)), value(value) {} + std::string key; TemplatableStringValue value; }; @@ -93,15 +97,28 @@ template class HomeAssistantServiceCallAction : public Action void set_service(T service) { this->service_ = service; } + // Initialize FixedVector members - called from Python codegen with compile-time known sizes + void init_data(size_t count) { this->data_.init(count); } + void init_data_template(size_t count) { this->data_template_.init(count); } + void init_variables(size_t count) { this->variables_.init(count); } + // Keys are always string literals from the Python code generation (e.g., cg.add(var.add_data("tag_id", templ))). // The value parameter can be a lambda/template, but keys are never templatable. // Using pass-by-value allows the compiler to optimize for both lvalues and rvalues. - template void add_data(std::string key, T value) { this->data_.emplace_back(std::move(key), value); } + template void add_data(std::string key, T value) { + auto &kv = this->data_.emplace_back(); + kv.key = std::move(key); + kv.value = value; + } template void add_data_template(std::string key, T value) { - this->data_template_.emplace_back(std::move(key), value); + auto &kv = this->data_template_.emplace_back(); + kv.key = std::move(key); + kv.value = value; } template void add_variable(std::string key, T value) { - this->variables_.emplace_back(std::move(key), value); + auto &kv = this->variables_.emplace_back(); + kv.key = std::move(key); + kv.value = value; } #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES @@ -186,9 +203,9 @@ template class HomeAssistantServiceCallAction : public Action service_{}; - std::vector> data_; - std::vector> data_template_; - std::vector> variables_; + FixedVector> data_; + FixedVector> data_template_; + FixedVector> variables_; #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON TemplatableStringValue response_template_{""};