From 17c32391ae2fc9b89bfa535bc1ab17ed40340be1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 25 Oct 2025 16:16:53 -0700 Subject: [PATCH 1/2] merge --- esphome/codegen.py | 1 + esphome/components/api/__init__.py | 16 ++++--- esphome/components/api/api_server.h | 3 ++ esphome/components/api/user_services.cpp | 57 ++++++++++++++++++++++-- esphome/cpp_types.py | 1 + 5 files changed, 69 insertions(+), 9 deletions(-) diff --git a/esphome/codegen.py b/esphome/codegen.py index 6decd77c62..6d55c6023d 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -62,6 +62,7 @@ from esphome.cpp_types import ( # noqa: F401 EntityBase, EntityCategory, ESPTime, + FixedVector, GPIOPin, InternalGPIOPin, JsonObject, diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index e91e922204..ee35d7f904 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -71,10 +71,12 @@ SERVICE_ARG_NATIVE_TYPES = { "int": cg.int32, "float": float, "string": cg.std_string, - "bool[]": cg.std_vector.template(bool), - "int[]": cg.std_vector.template(cg.int32), - "float[]": cg.std_vector.template(float), - "string[]": cg.std_vector.template(cg.std_string), + "bool[]": cg.FixedVector.template(bool).operator("const").operator("ref"), + "int[]": cg.FixedVector.template(cg.int32).operator("const").operator("ref"), + "float[]": cg.FixedVector.template(float).operator("const").operator("ref"), + "string[]": cg.FixedVector.template(cg.std_string) + .operator("const") + .operator("ref"), } CONF_ENCRYPTION = "encryption" CONF_BATCH_DELAY = "batch_delay" @@ -265,6 +267,8 @@ async def to_code(config): cg.add_define("USE_API_HOMEASSISTANT_STATES") if actions := config.get(CONF_ACTIONS, []): + # Collect all triggers first, then register all at once with initializer_list + triggers: list[cg.Pvariable] = [] for conf in actions: template_args = [] func_args = [] @@ -278,8 +282,10 @@ async def to_code(config): trigger = cg.new_Pvariable( conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names ) - cg.add(var.register_user_service(trigger)) + triggers.append(trigger) await automation.build_automation(trigger, func_args, conf) + # Register all services at once - single allocation, no reallocations + cg.add(var.initialize_user_services(triggers)) if CONF_ON_CLIENT_CONNECTED in config: cg.add_define("USE_API_CLIENT_CONNECTED_TRIGGER") diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index e0e23301d0..523a77262d 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -125,6 +125,9 @@ class APIServer : public Component, public Controller { #endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES #endif // USE_API_HOMEASSISTANT_SERVICES #ifdef USE_API_SERVICES + void initialize_user_services(std::initializer_list services) { + this->user_services_.assign(services); + } void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } #endif #ifdef USE_HOMEASSISTANT_TIME diff --git a/esphome/components/api/user_services.cpp b/esphome/components/api/user_services.cpp index 3cbf2ab5f9..a4b83e96c1 100644 --- a/esphome/components/api/user_services.cpp +++ b/esphome/components/api/user_services.cpp @@ -11,23 +11,58 @@ template<> int32_t get_execute_arg_value(const ExecuteServiceArgument & } template<> float get_execute_arg_value(const ExecuteServiceArgument &arg) { return arg.float_; } template<> std::string get_execute_arg_value(const ExecuteServiceArgument &arg) { return arg.string_; } + +// Legacy std::vector versions for custom C++ code - optimized with reserve template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - return std::vector(arg.bool_array.begin(), arg.bool_array.end()); + std::vector result; + result.reserve(arg.bool_array.size()); + result.insert(result.end(), arg.bool_array.begin(), arg.bool_array.end()); + return result; } template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - return std::vector(arg.int_array.begin(), arg.int_array.end()); + std::vector result; + result.reserve(arg.int_array.size()); + result.insert(result.end(), arg.int_array.begin(), arg.int_array.end()); + return result; } template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - return std::vector(arg.float_array.begin(), arg.float_array.end()); + std::vector result; + result.reserve(arg.float_array.size()); + result.insert(result.end(), arg.float_array.begin(), arg.float_array.end()); + return result; } template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - return std::vector(arg.string_array.begin(), arg.string_array.end()); + std::vector result; + result.reserve(arg.string_array.size()); + result.insert(result.end(), arg.string_array.begin(), arg.string_array.end()); + return result; +} + +// New FixedVector const reference versions for YAML-generated services - zero-copy +template<> +const FixedVector &get_execute_arg_value &>(const ExecuteServiceArgument &arg) { + return arg.bool_array; +} +template<> +const FixedVector &get_execute_arg_value &>(const ExecuteServiceArgument &arg) { + return arg.int_array; +} +template<> +const FixedVector &get_execute_arg_value &>(const ExecuteServiceArgument &arg) { + return arg.float_array; +} +template<> +const FixedVector &get_execute_arg_value &>( + const ExecuteServiceArgument &arg) { + return arg.string_array; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_BOOL; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_INT; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_FLOAT; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_STRING; } + +// Legacy std::vector versions for custom C++ code template<> enums::ServiceArgType to_service_arg_type>() { return enums::SERVICE_ARG_TYPE_BOOL_ARRAY; } template<> enums::ServiceArgType to_service_arg_type>() { return enums::SERVICE_ARG_TYPE_INT_ARRAY; @@ -39,4 +74,18 @@ template<> enums::ServiceArgType to_service_arg_type>() return enums::SERVICE_ARG_TYPE_STRING_ARRAY; } +// New FixedVector const reference versions for YAML-generated services +template<> enums::ServiceArgType to_service_arg_type &>() { + return enums::SERVICE_ARG_TYPE_BOOL_ARRAY; +} +template<> enums::ServiceArgType to_service_arg_type &>() { + return enums::SERVICE_ARG_TYPE_INT_ARRAY; +} +template<> enums::ServiceArgType to_service_arg_type &>() { + return enums::SERVICE_ARG_TYPE_FLOAT_ARRAY; +} +template<> enums::ServiceArgType to_service_arg_type &>() { + return enums::SERVICE_ARG_TYPE_STRING_ARRAY; +} + } // namespace esphome::api diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py index a0dd62cb4e..0d1813f63b 100644 --- a/esphome/cpp_types.py +++ b/esphome/cpp_types.py @@ -23,6 +23,7 @@ size_t = global_ns.namespace("size_t") const_char_ptr = global_ns.namespace("const char *") NAN = global_ns.namespace("NAN") esphome_ns = global_ns # using namespace esphome; +FixedVector = esphome_ns.class_("FixedVector") App = esphome_ns.App EntityBase = esphome_ns.class_("EntityBase") Component = esphome_ns.class_("Component") From 6094875ae18cc630a7e23db1d508ef9d8a6866de Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 25 Oct 2025 16:19:35 -0700 Subject: [PATCH 2/2] revert --- esphome/codegen.py | 1 - esphome/components/api/__init__.py | 10 ++--- esphome/components/api/user_services.cpp | 57 ++---------------------- esphome/cpp_types.py | 1 - 4 files changed, 8 insertions(+), 61 deletions(-) diff --git a/esphome/codegen.py b/esphome/codegen.py index 6d55c6023d..6decd77c62 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -62,7 +62,6 @@ from esphome.cpp_types import ( # noqa: F401 EntityBase, EntityCategory, ESPTime, - FixedVector, GPIOPin, InternalGPIOPin, JsonObject, diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index ee35d7f904..cf95da1bf0 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -71,12 +71,10 @@ SERVICE_ARG_NATIVE_TYPES = { "int": cg.int32, "float": float, "string": cg.std_string, - "bool[]": cg.FixedVector.template(bool).operator("const").operator("ref"), - "int[]": cg.FixedVector.template(cg.int32).operator("const").operator("ref"), - "float[]": cg.FixedVector.template(float).operator("const").operator("ref"), - "string[]": cg.FixedVector.template(cg.std_string) - .operator("const") - .operator("ref"), + "bool[]": cg.std_vector.template(bool), + "int[]": cg.std_vector.template(cg.int32), + "float[]": cg.std_vector.template(float), + "string[]": cg.std_vector.template(cg.std_string), } CONF_ENCRYPTION = "encryption" CONF_BATCH_DELAY = "batch_delay" diff --git a/esphome/components/api/user_services.cpp b/esphome/components/api/user_services.cpp index a4b83e96c1..3cbf2ab5f9 100644 --- a/esphome/components/api/user_services.cpp +++ b/esphome/components/api/user_services.cpp @@ -11,58 +11,23 @@ template<> int32_t get_execute_arg_value(const ExecuteServiceArgument & } template<> float get_execute_arg_value(const ExecuteServiceArgument &arg) { return arg.float_; } template<> std::string get_execute_arg_value(const ExecuteServiceArgument &arg) { return arg.string_; } - -// Legacy std::vector versions for custom C++ code - optimized with reserve template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - std::vector result; - result.reserve(arg.bool_array.size()); - result.insert(result.end(), arg.bool_array.begin(), arg.bool_array.end()); - return result; + return std::vector(arg.bool_array.begin(), arg.bool_array.end()); } template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - std::vector result; - result.reserve(arg.int_array.size()); - result.insert(result.end(), arg.int_array.begin(), arg.int_array.end()); - return result; + return std::vector(arg.int_array.begin(), arg.int_array.end()); } template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - std::vector result; - result.reserve(arg.float_array.size()); - result.insert(result.end(), arg.float_array.begin(), arg.float_array.end()); - return result; + return std::vector(arg.float_array.begin(), arg.float_array.end()); } template<> std::vector get_execute_arg_value>(const ExecuteServiceArgument &arg) { - std::vector result; - result.reserve(arg.string_array.size()); - result.insert(result.end(), arg.string_array.begin(), arg.string_array.end()); - return result; -} - -// New FixedVector const reference versions for YAML-generated services - zero-copy -template<> -const FixedVector &get_execute_arg_value &>(const ExecuteServiceArgument &arg) { - return arg.bool_array; -} -template<> -const FixedVector &get_execute_arg_value &>(const ExecuteServiceArgument &arg) { - return arg.int_array; -} -template<> -const FixedVector &get_execute_arg_value &>(const ExecuteServiceArgument &arg) { - return arg.float_array; -} -template<> -const FixedVector &get_execute_arg_value &>( - const ExecuteServiceArgument &arg) { - return arg.string_array; + return std::vector(arg.string_array.begin(), arg.string_array.end()); } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_BOOL; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_INT; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_FLOAT; } template<> enums::ServiceArgType to_service_arg_type() { return enums::SERVICE_ARG_TYPE_STRING; } - -// Legacy std::vector versions for custom C++ code template<> enums::ServiceArgType to_service_arg_type>() { return enums::SERVICE_ARG_TYPE_BOOL_ARRAY; } template<> enums::ServiceArgType to_service_arg_type>() { return enums::SERVICE_ARG_TYPE_INT_ARRAY; @@ -74,18 +39,4 @@ template<> enums::ServiceArgType to_service_arg_type>() return enums::SERVICE_ARG_TYPE_STRING_ARRAY; } -// New FixedVector const reference versions for YAML-generated services -template<> enums::ServiceArgType to_service_arg_type &>() { - return enums::SERVICE_ARG_TYPE_BOOL_ARRAY; -} -template<> enums::ServiceArgType to_service_arg_type &>() { - return enums::SERVICE_ARG_TYPE_INT_ARRAY; -} -template<> enums::ServiceArgType to_service_arg_type &>() { - return enums::SERVICE_ARG_TYPE_FLOAT_ARRAY; -} -template<> enums::ServiceArgType to_service_arg_type &>() { - return enums::SERVICE_ARG_TYPE_STRING_ARRAY; -} - } // namespace esphome::api diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py index 0d1813f63b..a0dd62cb4e 100644 --- a/esphome/cpp_types.py +++ b/esphome/cpp_types.py @@ -23,7 +23,6 @@ size_t = global_ns.namespace("size_t") const_char_ptr = global_ns.namespace("const char *") NAN = global_ns.namespace("NAN") esphome_ns = global_ns # using namespace esphome; -FixedVector = esphome_ns.class_("FixedVector") App = esphome_ns.App EntityBase = esphome_ns.class_("EntityBase") Component = esphome_ns.class_("Component")