1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-31 23:21:54 +00:00

[api] Register user services with initializer_list (#11545)

This commit is contained in:
J. Nick Koston
2025-10-27 15:07:31 -05:00
committed by GitHub
parent 00f22e5c36
commit e26b5874d7
4 changed files with 28 additions and 1 deletions

View File

@@ -258,6 +258,10 @@ async def to_code(config):
if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]: if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]:
cg.add_define("USE_API_SERVICES") cg.add_define("USE_API_SERVICES")
# Set USE_API_CUSTOM_SERVICES if external components need dynamic service registration
if config[CONF_CUSTOM_SERVICES]:
cg.add_define("USE_API_CUSTOM_SERVICES")
if config[CONF_HOMEASSISTANT_SERVICES]: if config[CONF_HOMEASSISTANT_SERVICES]:
cg.add_define("USE_API_HOMEASSISTANT_SERVICES") cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
@@ -265,6 +269,8 @@ async def to_code(config):
cg.add_define("USE_API_HOMEASSISTANT_STATES") cg.add_define("USE_API_HOMEASSISTANT_STATES")
if actions := config.get(CONF_ACTIONS, []): 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: for conf in actions:
template_args = [] template_args = []
func_args = [] func_args = []
@@ -278,8 +284,10 @@ async def to_code(config):
trigger = cg.new_Pvariable( trigger = cg.new_Pvariable(
conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names 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) 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: if CONF_ON_CLIENT_CONNECTED in config:
cg.add_define("USE_API_CLIENT_CONNECTED_TRIGGER") cg.add_define("USE_API_CLIENT_CONNECTED_TRIGGER")

View File

@@ -125,8 +125,14 @@ class APIServer : public Component, public Controller {
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES #endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
#endif // USE_API_HOMEASSISTANT_SERVICES #endif // USE_API_HOMEASSISTANT_SERVICES
#ifdef USE_API_SERVICES #ifdef USE_API_SERVICES
void initialize_user_services(std::initializer_list<UserServiceDescriptor *> services) {
this->user_services_.assign(services);
}
#ifdef USE_API_CUSTOM_SERVICES
// Only compile push_back method when custom_services: true (external components)
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); } void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
#endif #endif
#endif
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
void request_time(); void request_time();
#endif #endif

View File

@@ -53,8 +53,14 @@ class CustomAPIDevice {
template<typename T, typename... Ts> template<typename T, typename... Ts>
void register_service(void (T::*callback)(Ts...), const std::string &name, void register_service(void (T::*callback)(Ts...), const std::string &name,
const std::array<std::string, sizeof...(Ts)> &arg_names) { const std::array<std::string, sizeof...(Ts)> &arg_names) {
#ifdef USE_API_CUSTOM_SERVICES
auto *service = new CustomAPIDeviceService<T, Ts...>(name, arg_names, (T *) this, callback); // NOLINT auto *service = new CustomAPIDeviceService<T, Ts...>(name, arg_names, (T *) this, callback); // NOLINT
global_api_server->register_user_service(service); global_api_server->register_user_service(service);
#else
static_assert(
sizeof(T) == 0,
"register_service() requires 'custom_services: true' in the 'api:' section of your YAML configuration");
#endif
} }
#else #else
template<typename T, typename... Ts> template<typename T, typename... Ts>
@@ -86,8 +92,14 @@ class CustomAPIDevice {
*/ */
#ifdef USE_API_SERVICES #ifdef USE_API_SERVICES
template<typename T> void register_service(void (T::*callback)(), const std::string &name) { template<typename T> void register_service(void (T::*callback)(), const std::string &name) {
#ifdef USE_API_CUSTOM_SERVICES
auto *service = new CustomAPIDeviceService<T>(name, {}, (T *) this, callback); // NOLINT auto *service = new CustomAPIDeviceService<T>(name, {}, (T *) this, callback); // NOLINT
global_api_server->register_user_service(service); global_api_server->register_user_service(service);
#else
static_assert(
sizeof(T) == 0,
"register_service() requires 'custom_services: true' in the 'api:' section of your YAML configuration");
#endif
} }
#else #else
template<typename T> void register_service(void (T::*callback)(), const std::string &name) { template<typename T> void register_service(void (T::*callback)(), const std::string &name) {

View File

@@ -123,6 +123,7 @@
#define USE_API_NOISE #define USE_API_NOISE
#define USE_API_PLAINTEXT #define USE_API_PLAINTEXT
#define USE_API_SERVICES #define USE_API_SERVICES
#define USE_API_CUSTOM_SERVICES
#define API_MAX_SEND_QUEUE 8 #define API_MAX_SEND_QUEUE 8
#define USE_MD5 #define USE_MD5
#define USE_SHA256 #define USE_SHA256