controller registry phase1/2

This commit is contained in:
J. Nick Koston
2025-11-07 15:32:46 -06:00
parent 79d1a558af
commit 295fe8da04
7 changed files with 509 additions and 42 deletions

View File

@@ -4,6 +4,7 @@
#include "api_connection.h"
#include "esphome/components/network/util.h"
#include "esphome/core/application.h"
#include "esphome/core/controller_registry.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
@@ -34,7 +35,7 @@ APIServer::APIServer() {
}
void APIServer::setup() {
this->setup_controller();
ControllerRegistry::register_controller(this);
#ifdef USE_API_NOISE
uint32_t hash = 88491486UL;
@@ -269,7 +270,7 @@ bool APIServer::check_password(const uint8_t *password_data, size_t password_len
void APIServer::handle_disconnect(APIConnection *conn) {}
// Macro for entities without extra parameters
// Macro for controller update dispatch
#define API_DISPATCH_UPDATE(entity_type, entity_name) \
void APIServer::on_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
if (obj->is_internal()) \
@@ -278,15 +279,6 @@ void APIServer::handle_disconnect(APIConnection *conn) {}
c->send_##entity_name##_state(obj); \
}
// Macro for entities with extra parameters (but parameters not used in send)
#define API_DISPATCH_UPDATE_IGNORE_PARAMS(entity_type, entity_name, ...) \
void APIServer::on_##entity_name##_update(entity_type *obj, __VA_ARGS__) { /* NOLINT(bugprone-macro-parentheses) */ \
if (obj->is_internal()) \
return; \
for (auto &c : this->clients_) \
c->send_##entity_name##_state(obj); \
}
#ifdef USE_BINARY_SENSOR
API_DISPATCH_UPDATE(binary_sensor::BinarySensor, binary_sensor)
#endif
@@ -304,15 +296,15 @@ API_DISPATCH_UPDATE(light::LightState, light)
#endif
#ifdef USE_SENSOR
API_DISPATCH_UPDATE_IGNORE_PARAMS(sensor::Sensor, sensor, float state)
API_DISPATCH_UPDATE(sensor::Sensor, sensor)
#endif
#ifdef USE_SWITCH
API_DISPATCH_UPDATE_IGNORE_PARAMS(switch_::Switch, switch, bool state)
API_DISPATCH_UPDATE(switch_::Switch, switch)
#endif
#ifdef USE_TEXT_SENSOR
API_DISPATCH_UPDATE_IGNORE_PARAMS(text_sensor::TextSensor, text_sensor, const std::string &state)
API_DISPATCH_UPDATE(text_sensor::TextSensor, text_sensor)
#endif
#ifdef USE_CLIMATE
@@ -320,7 +312,7 @@ API_DISPATCH_UPDATE(climate::Climate, climate)
#endif
#ifdef USE_NUMBER
API_DISPATCH_UPDATE_IGNORE_PARAMS(number::Number, number, float state)
API_DISPATCH_UPDATE(number::Number, number)
#endif
#ifdef USE_DATETIME_DATE
@@ -336,11 +328,11 @@ API_DISPATCH_UPDATE(datetime::DateTimeEntity, datetime)
#endif
#ifdef USE_TEXT
API_DISPATCH_UPDATE_IGNORE_PARAMS(text::Text, text, const std::string &state)
API_DISPATCH_UPDATE(text::Text, text)
#endif
#ifdef USE_SELECT
API_DISPATCH_UPDATE_IGNORE_PARAMS(select::Select, select, const std::string &state, size_t index)
API_DISPATCH_UPDATE(select::Select, select)
#endif
#ifdef USE_LOCK

View File

@@ -72,19 +72,19 @@ class APIServer : public Component, public Controller {
void on_light_update(light::LightState *obj) override;
#endif
#ifdef USE_SENSOR
void on_sensor_update(sensor::Sensor *obj, float state) override;
void on_sensor_update(sensor::Sensor *obj) override;
#endif
#ifdef USE_SWITCH
void on_switch_update(switch_::Switch *obj, bool state) override;
void on_switch_update(switch_::Switch *obj) override;
#endif
#ifdef USE_TEXT_SENSOR
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override;
void on_text_sensor_update(text_sensor::TextSensor *obj) override;
#endif
#ifdef USE_CLIMATE
void on_climate_update(climate::Climate *obj) override;
#endif
#ifdef USE_NUMBER
void on_number_update(number::Number *obj, float state) override;
void on_number_update(number::Number *obj) override;
#endif
#ifdef USE_DATETIME_DATE
void on_date_update(datetime::DateEntity *obj) override;
@@ -96,10 +96,10 @@ class APIServer : public Component, public Controller {
void on_datetime_update(datetime::DateTimeEntity *obj) override;
#endif
#ifdef USE_TEXT
void on_text_update(text::Text *obj, const std::string &state) override;
void on_text_update(text::Text *obj) override;
#endif
#ifdef USE_SELECT
void on_select_update(select::Select *obj, const std::string &state, size_t index) override;
void on_select_update(select::Select *obj) override;
#endif
#ifdef USE_LOCK
void on_lock_update(lock::Lock *obj) override;

View File

@@ -3,6 +3,7 @@
#include "esphome/components/json/json_util.h"
#include "esphome/components/network/util.h"
#include "esphome/core/application.h"
#include "esphome/core/controller_registry.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
@@ -294,7 +295,7 @@ std::string WebServer::get_config_json() {
}
void WebServer::setup() {
this->setup_controller(this->include_internal_);
ControllerRegistry::register_controller(this);
this->base_->init();
#ifdef USE_LOGGER
@@ -430,7 +431,9 @@ static JsonDetail get_request_detail(AsyncWebServerRequest *request) {
}
#ifdef USE_SENSOR
void WebServer::on_sensor_update(sensor::Sensor *obj, float state) {
void WebServer::on_sensor_update(sensor::Sensor *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", sensor_state_json_generator);
}
void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -473,7 +476,9 @@ std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail
#endif
#ifdef USE_TEXT_SENSOR
void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) {
void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", text_sensor_state_json_generator);
}
void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -513,7 +518,9 @@ std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std:
#endif
#ifdef USE_SWITCH
void WebServer::on_switch_update(switch_::Switch *obj, bool state) {
void WebServer::on_switch_update(switch_::Switch *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", switch_state_json_generator);
}
void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -625,6 +632,8 @@ std::string WebServer::button_json(button::Button *obj, JsonDetail start_config)
#ifdef USE_BINARY_SENSOR
void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", binary_sensor_state_json_generator);
}
void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -664,6 +673,8 @@ std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool
#ifdef USE_FAN
void WebServer::on_fan_update(fan::Fan *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", fan_state_json_generator);
}
void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -738,6 +749,8 @@ std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) {
#ifdef USE_LIGHT
void WebServer::on_light_update(light::LightState *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", light_state_json_generator);
}
void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -811,6 +824,8 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi
#ifdef USE_COVER
void WebServer::on_cover_update(cover::Cover *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", cover_state_json_generator);
}
void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -895,7 +910,9 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
#endif
#ifdef USE_NUMBER
void WebServer::on_number_update(number::Number *obj, float state) {
void WebServer::on_number_update(number::Number *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", number_state_json_generator);
}
void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -961,6 +978,8 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail
#ifdef USE_DATETIME_DATE
void WebServer::on_date_update(datetime::DateEntity *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", date_state_json_generator);
}
void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1016,6 +1035,8 @@ std::string WebServer::date_json(datetime::DateEntity *obj, JsonDetail start_con
#ifdef USE_DATETIME_TIME
void WebServer::on_time_update(datetime::TimeEntity *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", time_state_json_generator);
}
void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1070,6 +1091,8 @@ std::string WebServer::time_json(datetime::TimeEntity *obj, JsonDetail start_con
#ifdef USE_DATETIME_DATETIME
void WebServer::on_datetime_update(datetime::DateTimeEntity *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", datetime_state_json_generator);
}
void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1124,7 +1147,9 @@ std::string WebServer::datetime_json(datetime::DateTimeEntity *obj, JsonDetail s
#endif // USE_DATETIME_DATETIME
#ifdef USE_TEXT
void WebServer::on_text_update(text::Text *obj, const std::string &state) {
void WebServer::on_text_update(text::Text *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", text_state_json_generator);
}
void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1178,7 +1203,9 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json
#endif
#ifdef USE_SELECT
void WebServer::on_select_update(select::Select *obj, const std::string &state, size_t index) {
void WebServer::on_select_update(select::Select *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", select_state_json_generator);
}
void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1237,6 +1264,8 @@ std::string WebServer::select_json(select::Select *obj, const char *value, JsonD
#ifdef USE_CLIMATE
void WebServer::on_climate_update(climate::Climate *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", climate_state_json_generator);
}
void WebServer::handle_climate_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1378,6 +1407,8 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
#ifdef USE_LOCK
void WebServer::on_lock_update(lock::Lock *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", lock_state_json_generator);
}
void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1449,6 +1480,8 @@ std::string WebServer::lock_json(lock::Lock *obj, lock::LockState value, JsonDet
#ifdef USE_VALVE
void WebServer::on_valve_update(valve::Valve *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", valve_state_json_generator);
}
void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMatch &match) {
@@ -1530,6 +1563,8 @@ std::string WebServer::valve_json(valve::Valve *obj, JsonDetail start_config) {
#ifdef USE_ALARM_CONTROL_PANEL
void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) {
if (!this->include_internal_ && obj->is_internal())
return;
this->events_.deferrable_send_state(obj, "state", alarm_control_panel_state_json_generator);
}
void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *request, const UrlMatch &match) {

View File

@@ -255,7 +255,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#endif
#ifdef USE_SENSOR
void on_sensor_update(sensor::Sensor *obj, float state) override;
void on_sensor_update(sensor::Sensor *obj) override;
/// Handle a sensor request under '/sensor/<id>'.
void handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match);
@@ -266,7 +266,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#endif
#ifdef USE_SWITCH
void on_switch_update(switch_::Switch *obj, bool state) override;
void on_switch_update(switch_::Switch *obj) override;
/// Handle a switch request under '/switch/<id>/</turn_on/turn_off/toggle>'.
void handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match);
@@ -324,7 +324,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#endif
#ifdef USE_TEXT_SENSOR
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override;
void on_text_sensor_update(text_sensor::TextSensor *obj) override;
/// Handle a text sensor request under '/text_sensor/<id>'.
void handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match);
@@ -348,7 +348,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#endif
#ifdef USE_NUMBER
void on_number_update(number::Number *obj, float state) override;
void on_number_update(number::Number *obj) override;
/// Handle a number request under '/number/<id>'.
void handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match);
@@ -392,7 +392,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#endif
#ifdef USE_TEXT
void on_text_update(text::Text *obj, const std::string &state) override;
void on_text_update(text::Text *obj) override;
/// Handle a text input request under '/text/<id>'.
void handle_text_request(AsyncWebServerRequest *request, const UrlMatch &match);
@@ -403,7 +403,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
#endif
#ifdef USE_SELECT
void on_select_update(select::Select *obj, const std::string &state, size_t index) override;
void on_select_update(select::Select *obj) override;
/// Handle a select request under '/select/<id>'.
void handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match);

View File

@@ -80,22 +80,22 @@ class Controller {
virtual void on_light_update(light::LightState *obj){};
#endif
#ifdef USE_SENSOR
virtual void on_sensor_update(sensor::Sensor *obj, float state){};
virtual void on_sensor_update(sensor::Sensor *obj){};
#endif
#ifdef USE_SWITCH
virtual void on_switch_update(switch_::Switch *obj, bool state){};
virtual void on_switch_update(switch_::Switch *obj){};
#endif
#ifdef USE_COVER
virtual void on_cover_update(cover::Cover *obj){};
#endif
#ifdef USE_TEXT_SENSOR
virtual void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state){};
virtual void on_text_sensor_update(text_sensor::TextSensor *obj){};
#endif
#ifdef USE_CLIMATE
virtual void on_climate_update(climate::Climate *obj){};
#endif
#ifdef USE_NUMBER
virtual void on_number_update(number::Number *obj, float state){};
virtual void on_number_update(number::Number *obj){};
#endif
#ifdef USE_DATETIME_DATE
virtual void on_date_update(datetime::DateEntity *obj){};
@@ -107,10 +107,10 @@ class Controller {
virtual void on_datetime_update(datetime::DateTimeEntity *obj){};
#endif
#ifdef USE_TEXT
virtual void on_text_update(text::Text *obj, const std::string &state){};
virtual void on_text_update(text::Text *obj){};
#endif
#ifdef USE_SELECT
virtual void on_select_update(select::Select *obj, const std::string &state, size_t index){};
virtual void on_select_update(select::Select *obj){};
#endif
#ifdef USE_LOCK
virtual void on_lock_update(lock::Lock *obj){};

View File

@@ -0,0 +1,177 @@
#include "esphome/core/controller_registry.h"
#include "esphome/core/controller.h"
namespace esphome {
std::vector<Controller *> ControllerRegistry::controllers_;
void ControllerRegistry::register_controller(Controller *controller) { controllers_.push_back(controller); }
void ControllerRegistry::unregister_controller(Controller *controller) {
auto it = std::find(controllers_.begin(), controllers_.end(), controller);
if (it != controllers_.end()) {
controllers_.erase(it);
}
}
#ifdef USE_BINARY_SENSOR
void ControllerRegistry::notify_binary_sensor_update(binary_sensor::BinarySensor *obj) {
for (auto *controller : controllers_) {
controller->on_binary_sensor_update(obj);
}
}
#endif
#ifdef USE_FAN
void ControllerRegistry::notify_fan_update(fan::Fan *obj) {
for (auto *controller : controllers_) {
controller->on_fan_update(obj);
}
}
#endif
#ifdef USE_LIGHT
void ControllerRegistry::notify_light_update(light::LightState *obj) {
for (auto *controller : controllers_) {
controller->on_light_update(obj);
}
}
#endif
#ifdef USE_SENSOR
void ControllerRegistry::notify_sensor_update(sensor::Sensor *obj) {
for (auto *controller : controllers_) {
controller->on_sensor_update(obj);
}
}
#endif
#ifdef USE_SWITCH
void ControllerRegistry::notify_switch_update(switch_::Switch *obj) {
for (auto *controller : controllers_) {
controller->on_switch_update(obj);
}
}
#endif
#ifdef USE_COVER
void ControllerRegistry::notify_cover_update(cover::Cover *obj) {
for (auto *controller : controllers_) {
controller->on_cover_update(obj);
}
}
#endif
#ifdef USE_TEXT_SENSOR
void ControllerRegistry::notify_text_sensor_update(text_sensor::TextSensor *obj) {
for (auto *controller : controllers_) {
controller->on_text_sensor_update(obj);
}
}
#endif
#ifdef USE_CLIMATE
void ControllerRegistry::notify_climate_update(climate::Climate *obj) {
for (auto *controller : controllers_) {
controller->on_climate_update(obj);
}
}
#endif
#ifdef USE_NUMBER
void ControllerRegistry::notify_number_update(number::Number *obj) {
for (auto *controller : controllers_) {
controller->on_number_update(obj);
}
}
#endif
#ifdef USE_DATETIME_DATE
void ControllerRegistry::notify_date_update(datetime::DateEntity *obj) {
for (auto *controller : controllers_) {
controller->on_date_update(obj);
}
}
#endif
#ifdef USE_DATETIME_TIME
void ControllerRegistry::notify_time_update(datetime::TimeEntity *obj) {
for (auto *controller : controllers_) {
controller->on_time_update(obj);
}
}
#endif
#ifdef USE_DATETIME_DATETIME
void ControllerRegistry::notify_datetime_update(datetime::DateTimeEntity *obj) {
for (auto *controller : controllers_) {
controller->on_datetime_update(obj);
}
}
#endif
#ifdef USE_TEXT
void ControllerRegistry::notify_text_update(text::Text *obj) {
for (auto *controller : controllers_) {
controller->on_text_update(obj);
}
}
#endif
#ifdef USE_SELECT
void ControllerRegistry::notify_select_update(select::Select *obj) {
for (auto *controller : controllers_) {
controller->on_select_update(obj);
}
}
#endif
#ifdef USE_LOCK
void ControllerRegistry::notify_lock_update(lock::Lock *obj) {
for (auto *controller : controllers_) {
controller->on_lock_update(obj);
}
}
#endif
#ifdef USE_VALVE
void ControllerRegistry::notify_valve_update(valve::Valve *obj) {
for (auto *controller : controllers_) {
controller->on_valve_update(obj);
}
}
#endif
#ifdef USE_MEDIA_PLAYER
void ControllerRegistry::notify_media_player_update(media_player::MediaPlayer *obj) {
for (auto *controller : controllers_) {
controller->on_media_player_update(obj);
}
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
void ControllerRegistry::notify_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) {
for (auto *controller : controllers_) {
controller->on_alarm_control_panel_update(obj);
}
}
#endif
#ifdef USE_EVENT
void ControllerRegistry::notify_event(event::Event *obj, const std::string &event_type) {
for (auto *controller : controllers_) {
controller->on_event(obj, event_type);
}
}
#endif
#ifdef USE_UPDATE
void ControllerRegistry::notify_update(update::UpdateEntity *obj) {
for (auto *controller : controllers_) {
controller->on_update(obj);
}
}
#endif
} // namespace esphome

View File

@@ -0,0 +1,263 @@
#pragma once
#include "esphome/core/defines.h"
#include <vector>
// Forward declarations
namespace esphome {
class Controller;
#ifdef USE_BINARY_SENSOR
namespace binary_sensor {
class BinarySensor;
}
#endif
#ifdef USE_FAN
namespace fan {
class Fan;
}
#endif
#ifdef USE_LIGHT
namespace light {
class LightState;
}
#endif
#ifdef USE_SENSOR
namespace sensor {
class Sensor;
}
#endif
#ifdef USE_SWITCH
namespace switch_ {
class Switch;
}
#endif
#ifdef USE_COVER
namespace cover {
class Cover;
}
#endif
#ifdef USE_TEXT_SENSOR
namespace text_sensor {
class TextSensor;
}
#endif
#ifdef USE_CLIMATE
namespace climate {
class Climate;
}
#endif
#ifdef USE_NUMBER
namespace number {
class Number;
}
#endif
#ifdef USE_DATETIME_DATE
namespace datetime {
class DateEntity;
}
#endif
#ifdef USE_DATETIME_TIME
namespace datetime {
class TimeEntity;
}
#endif
#ifdef USE_DATETIME_DATETIME
namespace datetime {
class DateTimeEntity;
}
#endif
#ifdef USE_TEXT
namespace text {
class Text;
}
#endif
#ifdef USE_SELECT
namespace select {
class Select;
}
#endif
#ifdef USE_LOCK
namespace lock {
class Lock;
}
#endif
#ifdef USE_VALVE
namespace valve {
class Valve;
}
#endif
#ifdef USE_MEDIA_PLAYER
namespace media_player {
class MediaPlayer;
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
namespace alarm_control_panel {
class AlarmControlPanel;
}
#endif
#ifdef USE_EVENT
namespace event {
class Event;
}
#endif
#ifdef USE_UPDATE
namespace update {
class UpdateEntity;
}
#endif
/** Global registry for Controllers to receive entity state updates.
*
* This singleton registry allows Controllers (APIServer, WebServer) to receive
* entity state change notifications without storing per-entity callbacks.
*
* Instead of each entity maintaining a list of controller callbacks (32 bytes overhead),
* entities call ControllerRegistry::notify_*_update() which iterates the small list
* of registered controllers (typically 2: API and WebServer).
*
* Memory savings: 32 bytes per entity (2 controllers × 16 bytes std::function overhead)
* For 80 entities: 2,560 bytes saved
*/
class ControllerRegistry {
public:
/** Register a controller to receive entity state updates.
*
* Controllers should call this in their setup() method.
* Typically only APIServer and WebServer register.
*/
static void register_controller(Controller *controller);
/** Unregister a controller (rarely used).
*
* Controllers are typically never unregistered in ESPHome's lifecycle,
* but this is provided for completeness and testing.
*/
static void unregister_controller(Controller *controller);
#ifdef USE_BINARY_SENSOR
/** Notify all controllers of a binary sensor state update. */
static void notify_binary_sensor_update(binary_sensor::BinarySensor *obj);
#endif
#ifdef USE_FAN
/** Notify all controllers of a fan state update. */
static void notify_fan_update(fan::Fan *obj);
#endif
#ifdef USE_LIGHT
/** Notify all controllers of a light state update. */
static void notify_light_update(light::LightState *obj);
#endif
#ifdef USE_SENSOR
/** Notify all controllers of a sensor state update. */
static void notify_sensor_update(sensor::Sensor *obj);
#endif
#ifdef USE_SWITCH
/** Notify all controllers of a switch state update. */
static void notify_switch_update(switch_::Switch *obj);
#endif
#ifdef USE_COVER
/** Notify all controllers of a cover state update. */
static void notify_cover_update(cover::Cover *obj);
#endif
#ifdef USE_TEXT_SENSOR
/** Notify all controllers of a text sensor state update. */
static void notify_text_sensor_update(text_sensor::TextSensor *obj);
#endif
#ifdef USE_CLIMATE
/** Notify all controllers of a climate state update. */
static void notify_climate_update(climate::Climate *obj);
#endif
#ifdef USE_NUMBER
/** Notify all controllers of a number state update. */
static void notify_number_update(number::Number *obj);
#endif
#ifdef USE_DATETIME_DATE
/** Notify all controllers of a date entity state update. */
static void notify_date_update(datetime::DateEntity *obj);
#endif
#ifdef USE_DATETIME_TIME
/** Notify all controllers of a time entity state update. */
static void notify_time_update(datetime::TimeEntity *obj);
#endif
#ifdef USE_DATETIME_DATETIME
/** Notify all controllers of a datetime entity state update. */
static void notify_datetime_update(datetime::DateTimeEntity *obj);
#endif
#ifdef USE_TEXT
/** Notify all controllers of a text entity state update. */
static void notify_text_update(text::Text *obj);
#endif
#ifdef USE_SELECT
/** Notify all controllers of a select entity state update. */
static void notify_select_update(select::Select *obj);
#endif
#ifdef USE_LOCK
/** Notify all controllers of a lock state update. */
static void notify_lock_update(lock::Lock *obj);
#endif
#ifdef USE_VALVE
/** Notify all controllers of a valve state update. */
static void notify_valve_update(valve::Valve *obj);
#endif
#ifdef USE_MEDIA_PLAYER
/** Notify all controllers of a media player state update. */
static void notify_media_player_update(media_player::MediaPlayer *obj);
#endif
#ifdef USE_ALARM_CONTROL_PANEL
/** Notify all controllers of an alarm control panel state update. */
static void notify_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj);
#endif
#ifdef USE_EVENT
/** Notify all controllers of an event trigger. */
static void notify_event(event::Event *obj, const std::string &event_type);
#endif
#ifdef USE_UPDATE
/** Notify all controllers of an update entity state update. */
static void notify_update(update::UpdateEntity *obj);
#endif
protected:
static std::vector<Controller *> controllers_;
};
} // namespace esphome