mirror of
https://github.com/esphome/esphome.git
synced 2025-11-09 19:41:49 +00:00
Compare commits
7 Commits
controller
...
abbwelcome
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40f0be2d0f | ||
|
|
ff04a6da4b | ||
|
|
772340cdc3 | ||
|
|
d29882e4ad | ||
|
|
a239460724 | ||
|
|
b61027607f | ||
|
|
f55c872180 |
@@ -1,9 +1,7 @@
|
||||
#include "alarm_control_panel.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "alarm_control_panel.h"
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -36,9 +34,6 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) {
|
||||
LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state)));
|
||||
this->current_state_ = state;
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_ALARM_CONTROL_PANEL) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_alarm_control_panel_update(this);
|
||||
#endif
|
||||
if (state == ACP_STATE_TRIGGERED) {
|
||||
this->triggered_callback_.call();
|
||||
} else if (state == ACP_STATE_ARMING) {
|
||||
|
||||
@@ -244,9 +244,6 @@ async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
|
||||
# Track controller registration for StaticVector sizing
|
||||
CORE.register_controller()
|
||||
|
||||
cg.add(var.set_port(config[CONF_PORT]))
|
||||
if config[CONF_PASSWORD]:
|
||||
cg.add_define("USE_API_PASSWORD")
|
||||
|
||||
@@ -1294,11 +1294,11 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
void APIConnection::send_event(event::Event *event, const char *event_type) {
|
||||
void APIConnection::send_event(event::Event *event, const std::string &event_type) {
|
||||
this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
|
||||
EventResponse::ESTIMATED_SIZE);
|
||||
}
|
||||
uint16_t APIConnection::try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn,
|
||||
uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn,
|
||||
uint32_t remaining_size, bool is_single) {
|
||||
EventResponse resp;
|
||||
resp.set_event_type(StringRef(event_type));
|
||||
@@ -1648,7 +1648,9 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c
|
||||
// O(n) but optimized for RAM and not performance.
|
||||
for (auto &item : items) {
|
||||
if (item.entity == entity && item.message_type == message_type) {
|
||||
// Replace with new creator
|
||||
// Clean up old creator before replacing
|
||||
item.creator.cleanup(message_type);
|
||||
// Move assign the new creator
|
||||
item.creator = std::move(creator);
|
||||
return;
|
||||
}
|
||||
@@ -1818,7 +1820,7 @@ void APIConnection::process_batch_() {
|
||||
|
||||
// Handle remaining items more efficiently
|
||||
if (items_processed < this->deferred_batch_.size()) {
|
||||
// Remove processed items from the beginning
|
||||
// Remove processed items from the beginning with proper cleanup
|
||||
this->deferred_batch_.remove_front(items_processed);
|
||||
// Reschedule for remaining items
|
||||
this->schedule_batch_();
|
||||
@@ -1831,10 +1833,10 @@ void APIConnection::process_batch_() {
|
||||
uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||
bool is_single, uint8_t message_type) const {
|
||||
#ifdef USE_EVENT
|
||||
// Special case: EventResponse uses const char * pointer
|
||||
// Special case: EventResponse uses string pointer
|
||||
if (message_type == EventResponse::MESSAGE_TYPE) {
|
||||
auto *e = static_cast<event::Event *>(entity);
|
||||
return APIConnection::try_send_event_response(e, data_.const_char_ptr, conn, remaining_size, is_single);
|
||||
return APIConnection::try_send_event_response(e, *data_.string_ptr, conn, remaining_size, is_single);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ class APIConnection final : public APIServerConnection {
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
void send_event(event::Event *event, const char *event_type);
|
||||
void send_event(event::Event *event, const std::string &event_type);
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
@@ -450,7 +450,7 @@ class APIConnection final : public APIServerConnection {
|
||||
bool is_single);
|
||||
#endif
|
||||
#ifdef USE_EVENT
|
||||
static uint16_t try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn,
|
||||
static uint16_t try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn,
|
||||
uint32_t remaining_size, bool is_single);
|
||||
static uint16_t try_send_event_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single);
|
||||
#endif
|
||||
@@ -508,8 +508,10 @@ class APIConnection final : public APIServerConnection {
|
||||
// Constructor for function pointer
|
||||
MessageCreator(MessageCreatorPtr ptr) { data_.function_ptr = ptr; }
|
||||
|
||||
// Constructor for const char * (Event types - no allocation needed)
|
||||
explicit MessageCreator(const char *str_value) { data_.const_char_ptr = str_value; }
|
||||
// Constructor for string state capture
|
||||
explicit MessageCreator(const std::string &str_value) { data_.string_ptr = new std::string(str_value); }
|
||||
|
||||
// No destructor - cleanup must be called explicitly with message_type
|
||||
|
||||
// Delete copy operations - MessageCreator should only be moved
|
||||
MessageCreator(const MessageCreator &other) = delete;
|
||||
@@ -521,6 +523,8 @@ class APIConnection final : public APIServerConnection {
|
||||
// Move assignment
|
||||
MessageCreator &operator=(MessageCreator &&other) noexcept {
|
||||
if (this != &other) {
|
||||
// IMPORTANT: Caller must ensure cleanup() was called if this contains a string!
|
||||
// In our usage, this happens in add_item() deduplication and vector::erase()
|
||||
data_ = other.data_;
|
||||
other.data_.function_ptr = nullptr;
|
||||
}
|
||||
@@ -531,10 +535,20 @@ class APIConnection final : public APIServerConnection {
|
||||
uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single,
|
||||
uint8_t message_type) const;
|
||||
|
||||
// Manual cleanup method - must be called before destruction for string types
|
||||
void cleanup(uint8_t message_type) {
|
||||
#ifdef USE_EVENT
|
||||
if (message_type == EventResponse::MESSAGE_TYPE && data_.string_ptr != nullptr) {
|
||||
delete data_.string_ptr;
|
||||
data_.string_ptr = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
union Data {
|
||||
MessageCreatorPtr function_ptr;
|
||||
const char *const_char_ptr;
|
||||
std::string *string_ptr;
|
||||
} data_; // 4 bytes on 32-bit, 8 bytes on 64-bit - same as before
|
||||
};
|
||||
|
||||
@@ -554,24 +568,42 @@ class APIConnection final : public APIServerConnection {
|
||||
std::vector<BatchItem> items;
|
||||
uint32_t batch_start_time{0};
|
||||
|
||||
private:
|
||||
// Helper to cleanup items from the beginning
|
||||
void cleanup_items_(size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
items[i].creator.cleanup(items[i].message_type);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DeferredBatch() {
|
||||
// Pre-allocate capacity for typical batch sizes to avoid reallocation
|
||||
items.reserve(8);
|
||||
}
|
||||
|
||||
~DeferredBatch() {
|
||||
// Ensure cleanup of any remaining items
|
||||
clear();
|
||||
}
|
||||
|
||||
// Add item to the batch
|
||||
void add_item(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size);
|
||||
// Add item to the front of the batch (for high priority messages like ping)
|
||||
void add_item_front(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size);
|
||||
|
||||
// Clear all items
|
||||
// Clear all items with proper cleanup
|
||||
void clear() {
|
||||
cleanup_items_(items.size());
|
||||
items.clear();
|
||||
batch_start_time = 0;
|
||||
}
|
||||
|
||||
// Remove processed items from the front
|
||||
void remove_front(size_t count) { items.erase(items.begin(), items.begin() + count); }
|
||||
// Remove processed items from the front with proper cleanup
|
||||
void remove_front(size_t count) {
|
||||
cleanup_items_(count);
|
||||
items.erase(items.begin(), items.begin() + count);
|
||||
}
|
||||
|
||||
bool empty() const { return items.empty(); }
|
||||
size_t size() const { return items.size(); }
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/util.h"
|
||||
@@ -35,7 +34,7 @@ APIServer::APIServer() {
|
||||
}
|
||||
|
||||
void APIServer::setup() {
|
||||
ControllerRegistry::register_controller(this);
|
||||
this->setup_controller();
|
||||
|
||||
#ifdef USE_API_NOISE
|
||||
uint32_t hash = 88491486UL;
|
||||
@@ -270,7 +269,7 @@ bool APIServer::check_password(const uint8_t *password_data, size_t password_len
|
||||
|
||||
void APIServer::handle_disconnect(APIConnection *conn) {}
|
||||
|
||||
// Macro for controller update dispatch
|
||||
// Macro for entities without extra parameters
|
||||
#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()) \
|
||||
@@ -279,6 +278,15 @@ 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
|
||||
@@ -296,15 +304,15 @@ API_DISPATCH_UPDATE(light::LightState, light)
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
API_DISPATCH_UPDATE(sensor::Sensor, sensor)
|
||||
API_DISPATCH_UPDATE_IGNORE_PARAMS(sensor::Sensor, sensor, float state)
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
API_DISPATCH_UPDATE(switch_::Switch, switch)
|
||||
API_DISPATCH_UPDATE_IGNORE_PARAMS(switch_::Switch, switch, bool state)
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
API_DISPATCH_UPDATE(text_sensor::TextSensor, text_sensor)
|
||||
API_DISPATCH_UPDATE_IGNORE_PARAMS(text_sensor::TextSensor, text_sensor, const std::string &state)
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
@@ -312,7 +320,7 @@ API_DISPATCH_UPDATE(climate::Climate, climate)
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
API_DISPATCH_UPDATE(number::Number, number)
|
||||
API_DISPATCH_UPDATE_IGNORE_PARAMS(number::Number, number, float state)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATE
|
||||
@@ -328,11 +336,11 @@ API_DISPATCH_UPDATE(datetime::DateTimeEntity, datetime)
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
API_DISPATCH_UPDATE(text::Text, text)
|
||||
API_DISPATCH_UPDATE_IGNORE_PARAMS(text::Text, text, const std::string &state)
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
API_DISPATCH_UPDATE(select::Select, select)
|
||||
API_DISPATCH_UPDATE_IGNORE_PARAMS(select::Select, select, const std::string &state, size_t index)
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
@@ -348,13 +356,12 @@ API_DISPATCH_UPDATE(media_player::MediaPlayer, media_player)
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
// Event is a special case - unlike other entities with simple state fields,
|
||||
// events store their state in a member accessed via obj->get_last_event_type()
|
||||
void APIServer::on_event(event::Event *obj) {
|
||||
// Event is a special case - it's the only entity that passes extra parameters to the send method
|
||||
void APIServer::on_event(event::Event *obj, const std::string &event_type) {
|
||||
if (obj->is_internal())
|
||||
return;
|
||||
for (auto &c : this->clients_)
|
||||
c->send_event(obj, obj->get_last_event_type());
|
||||
c->send_event(obj, event_type);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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) override;
|
||||
void on_sensor_update(sensor::Sensor *obj, float state) override;
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
void on_switch_update(switch_::Switch *obj) override;
|
||||
void on_switch_update(switch_::Switch *obj, bool state) override;
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
void on_text_sensor_update(text_sensor::TextSensor *obj) override;
|
||||
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override;
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
void on_climate_update(climate::Climate *obj) override;
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
void on_number_update(number::Number *obj) override;
|
||||
void on_number_update(number::Number *obj, float state) 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) override;
|
||||
void on_text_update(text::Text *obj, const std::string &state) override;
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
void on_select_update(select::Select *obj) override;
|
||||
void on_select_update(select::Select *obj, const std::string &state, size_t index) override;
|
||||
#endif
|
||||
#ifdef USE_LOCK
|
||||
void on_lock_update(lock::Lock *obj) override;
|
||||
@@ -141,7 +141,7 @@ class APIServer : public Component, public Controller {
|
||||
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override;
|
||||
#endif
|
||||
#ifdef USE_EVENT
|
||||
void on_event(event::Event *obj) override;
|
||||
void on_event(event::Event *obj, const std::string &event_type) override;
|
||||
#endif
|
||||
#ifdef USE_UPDATE
|
||||
void on_update(update::UpdateEntity *obj) override;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "binary_sensor.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -39,9 +37,6 @@ void BinarySensor::send_state_internal(bool new_state) {
|
||||
// Note that set_state_ de-dups and will only trigger callbacks if the state has actually changed
|
||||
if (this->set_state_(new_state)) {
|
||||
ESP_LOGD(TAG, "'%s': New state is %s", this->get_name().c_str(), ONOFF(new_state));
|
||||
#if defined(USE_BINARY_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_binary_sensor_update(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "climate.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/macros.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -465,9 +463,6 @@ void Climate::publish_state() {
|
||||
|
||||
// Send state to frontend
|
||||
this->state_callback_.call(*this);
|
||||
#if defined(USE_CLIMATE) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_climate_update(this);
|
||||
#endif
|
||||
// Save state
|
||||
this->save_state_();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#include "cover.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -173,9 +169,6 @@ void Cover::publish_state(bool save) {
|
||||
ESP_LOGD(TAG, " Current Operation: %s", cover_operation_to_str(this->current_operation));
|
||||
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_COVER) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_cover_update(this);
|
||||
#endif
|
||||
|
||||
if (save) {
|
||||
CoverRestoreState restore{};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "date_entity.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#ifdef USE_DATETIME_DATE
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
@@ -33,9 +32,6 @@ void DateEntity::publish_state() {
|
||||
this->set_has_state(true);
|
||||
ESP_LOGD(TAG, "'%s': Sending date %d-%d-%d", this->get_name().c_str(), this->year_, this->month_, this->day_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_DATE) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_date_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
DateCall DateEntity::make_call() { return DateCall(this); }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "datetime_entity.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
@@ -49,9 +48,6 @@ void DateTimeEntity::publish_state() {
|
||||
ESP_LOGD(TAG, "'%s': Sending datetime %04u-%02u-%02u %02d:%02d:%02d", this->get_name().c_str(), this->year_,
|
||||
this->month_, this->day_, this->hour_, this->minute_, this->second_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_DATETIME) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_datetime_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
DateTimeCall DateTimeEntity::make_call() { return DateTimeCall(this); }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "time_entity.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#ifdef USE_DATETIME_TIME
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
@@ -30,9 +29,6 @@ void TimeEntity::publish_state() {
|
||||
ESP_LOGD(TAG, "'%s': Sending time %02d:%02d:%02d", this->get_name().c_str(), this->hour_, this->minute_,
|
||||
this->second_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_TIME) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_time_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
TimeCall TimeEntity::make_call() { return TimeCall(this); }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "event.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -24,9 +23,6 @@ void Event::trigger(const std::string &event_type) {
|
||||
this->last_event_type_ = found;
|
||||
ESP_LOGD(TAG, "'%s' Triggered event '%s'", this->get_name().c_str(), this->last_event_type_);
|
||||
this->event_callback_.call(event_type);
|
||||
#if defined(USE_EVENT) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_event(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Event::set_event_types(const FixedVector<const char *> &event_types) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "fan.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -183,9 +181,6 @@ void Fan::publish_state() {
|
||||
ESP_LOGD(TAG, " Preset Mode: %s", preset);
|
||||
}
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_FAN) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_fan_update(this);
|
||||
#endif
|
||||
this->save_state_();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <climits>
|
||||
#include "abstract_aqi_calculator.h"
|
||||
// https://www.airnow.gov/sites/default/files/2020-05/aqi-technical-assistance-document-sept2018.pdf
|
||||
// https://document.airnow.gov/technical-assistance-document-for-the-reporting-of-daily-air-quailty.pdf
|
||||
|
||||
namespace esphome {
|
||||
namespace hm3301 {
|
||||
@@ -16,16 +16,15 @@ class AQICalculator : public AbstractAQICalculator {
|
||||
}
|
||||
|
||||
protected:
|
||||
static const int AMOUNT_OF_LEVELS = 7;
|
||||
static const int AMOUNT_OF_LEVELS = 6;
|
||||
|
||||
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200},
|
||||
{201, 300}, {301, 400}, {401, 500}};
|
||||
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
|
||||
|
||||
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150},
|
||||
{151, 250}, {251, 350}, {351, 500}};
|
||||
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 9}, {10, 35}, {36, 55},
|
||||
{56, 125}, {126, 225}, {226, INT_MAX}};
|
||||
|
||||
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254}, {255, 354},
|
||||
{355, 424}, {425, 504}, {505, 604}};
|
||||
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254},
|
||||
{255, 354}, {355, 424}, {425, INT_MAX}};
|
||||
|
||||
int calculate_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
|
||||
int grid_index = get_grid_index_(value, array);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "light_state.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include "light_output.h"
|
||||
#include "light_state.h"
|
||||
#include "transformers.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -138,12 +137,7 @@ void LightState::loop() {
|
||||
|
||||
float LightState::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; }
|
||||
|
||||
void LightState::publish_state() {
|
||||
this->remote_values_callback_.call();
|
||||
#if defined(USE_LIGHT) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_light_update(this);
|
||||
#endif
|
||||
}
|
||||
void LightState::publish_state() { this->remote_values_callback_.call(); }
|
||||
|
||||
LightOutput *LightState::get_output() const { return this->output_; }
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "lock.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -55,9 +53,6 @@ void Lock::publish_state(LockState state) {
|
||||
this->rtc_.save(&this->state);
|
||||
ESP_LOGD(TAG, "'%s': Sending state %s", this->name_.c_str(), lock_state_to_string(state));
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_LOCK) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_lock_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Lock::add_on_state_callback(std::function<void()> &&callback) { this->state_callback_.add(std::move(callback)); }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "media_player.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -149,12 +148,7 @@ void MediaPlayer::add_on_state_callback(std::function<void()> &&callback) {
|
||||
this->state_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void MediaPlayer::publish_state() {
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_MEDIA_PLAYER) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_media_player_update(this);
|
||||
#endif
|
||||
}
|
||||
void MediaPlayer::publish_state() { this->state_callback_.call(); }
|
||||
|
||||
} // namespace media_player
|
||||
} // namespace esphome
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "number.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -34,9 +32,6 @@ void Number::publish_state(float state) {
|
||||
this->state = state;
|
||||
ESP_LOGD(TAG, "'%s': Sending state %f", this->get_name().c_str(), state);
|
||||
this->state_callback_.call(state);
|
||||
#if defined(USE_NUMBER) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_number_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Number::add_on_state_callback(std::function<void(float)> &&callback) {
|
||||
|
||||
@@ -39,7 +39,7 @@ from esphome.const import (
|
||||
CONF_WAND_ID,
|
||||
CONF_ZERO,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
from esphome.core import ID, coroutine
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||
from esphome.util import Registry, SimpleRegistry
|
||||
|
||||
@@ -2104,7 +2104,9 @@ async def abbwelcome_action(var, config, args):
|
||||
)
|
||||
cg.add(var.set_data_template(template_))
|
||||
else:
|
||||
cg.add(var.set_data_static(data_))
|
||||
arr_id = ID(f"{var.base}_data", is_declaration=True, type=cg.uint8)
|
||||
arr = cg.static_const_array(arr_id, cg.ArrayInitializer(*data_))
|
||||
cg.add(var.set_data_static(arr, len(data_)))
|
||||
|
||||
|
||||
# Mirage
|
||||
|
||||
@@ -214,10 +214,13 @@ template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterAction
|
||||
TEMPLATABLE_VALUE(uint8_t, message_type)
|
||||
TEMPLATABLE_VALUE(uint8_t, message_id)
|
||||
TEMPLATABLE_VALUE(bool, auto_message_id)
|
||||
void set_data_static(std::vector<uint8_t> data) { data_static_ = std::move(data); }
|
||||
void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) {
|
||||
this->data_func_ = func;
|
||||
has_data_func_ = true;
|
||||
void set_data_template(std::vector<uint8_t> (*func)(Ts...)) {
|
||||
this->data_.func = func;
|
||||
this->len_ = -1; // Sentinel value indicates template mode
|
||||
}
|
||||
void set_data_static(const uint8_t *data, size_t len) {
|
||||
this->data_.data = data;
|
||||
this->len_ = len; // Length >= 0 indicates static mode
|
||||
}
|
||||
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||
ABBWelcomeData data;
|
||||
@@ -228,19 +231,25 @@ template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterAction
|
||||
data.set_message_type(this->message_type_.value(x...));
|
||||
data.set_message_id(this->message_id_.value(x...));
|
||||
data.auto_message_id = this->auto_message_id_.value(x...);
|
||||
if (has_data_func_) {
|
||||
data.set_data(this->data_func_(x...));
|
||||
std::vector<uint8_t> data_vec;
|
||||
if (this->len_ >= 0) {
|
||||
// Static mode: copy from flash to vector
|
||||
data_vec.assign(this->data_.data, this->data_.data + this->len_);
|
||||
} else {
|
||||
data.set_data(this->data_static_);
|
||||
// Template mode: call function
|
||||
data_vec = this->data_.func(x...);
|
||||
}
|
||||
data.set_data(data_vec);
|
||||
data.finalize();
|
||||
ABBWelcomeProtocol().encode(dst, data);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
|
||||
std::vector<uint8_t> data_static_{};
|
||||
bool has_data_func_{false};
|
||||
ssize_t len_{-1}; // -1 = template mode, >=0 = static mode with length
|
||||
union Data {
|
||||
std::vector<uint8_t> (*func)(Ts...); // Function pointer (stateless lambdas)
|
||||
const uint8_t *data; // Pointer to static data in flash
|
||||
} data_;
|
||||
};
|
||||
|
||||
} // namespace remote_base
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "select.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cstring>
|
||||
|
||||
@@ -35,9 +33,6 @@ void Select::publish_state(size_t index) {
|
||||
ESP_LOGD(TAG, "'%s': Sending state %s (index %zu)", this->get_name().c_str(), option, index);
|
||||
// Callback signature requires std::string, create temporary for compatibility
|
||||
this->state_callback_.call(std::string(option), index);
|
||||
#if defined(USE_SELECT) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_select_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *Select::current_option() const { return this->has_state() ? this->option_at(this->active_index_) : ""; }
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "sensor.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -133,9 +131,6 @@ void Sensor::internal_send_state_to_frontend(float state) {
|
||||
ESP_LOGD(TAG, "'%s': Sending state %.5f %s with %d decimals of accuracy", this->get_name().c_str(), state,
|
||||
this->get_unit_of_measurement_ref().c_str(), this->get_accuracy_decimals());
|
||||
this->callback_.call(state);
|
||||
#if defined(USE_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_sensor_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace sensor
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "switch.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -64,9 +62,6 @@ void Switch::publish_state(bool state) {
|
||||
|
||||
ESP_LOGD(TAG, "'%s': Sending state %s", this->name_.c_str(), ONOFF(this->state));
|
||||
this->state_callback_.call(this->state);
|
||||
#if defined(USE_SWITCH) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_switch_update(this);
|
||||
#endif
|
||||
}
|
||||
bool Switch::assumed_state() { return false; }
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "text.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -18,9 +16,6 @@ void Text::publish_state(const std::string &state) {
|
||||
ESP_LOGD(TAG, "'%s': Sending state %s", this->get_name().c_str(), state.c_str());
|
||||
}
|
||||
this->state_callback_.call(state);
|
||||
#if defined(USE_TEXT) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_text_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Text::add_on_state_callback(std::function<void(std::string)> &&callback) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "text_sensor.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -86,9 +84,6 @@ void TextSensor::internal_send_state_to_frontend(const std::string &state) {
|
||||
this->set_has_state(true);
|
||||
ESP_LOGD(TAG, "'%s': Sending state '%s'", this->name_.c_str(), state.c_str());
|
||||
this->callback_.call(state);
|
||||
#if defined(USE_TEXT_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_text_sensor_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace text_sensor
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "update_entity.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -33,9 +32,6 @@ void UpdateEntity::publish_state() {
|
||||
|
||||
this->set_has_state(true);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_UPDATE) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_update(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace update
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "valve.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <strings.h>
|
||||
|
||||
@@ -149,9 +147,6 @@ void Valve::publish_state(bool save) {
|
||||
ESP_LOGD(TAG, " Current Operation: %s", valve_operation_to_str(this->current_operation));
|
||||
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_VALVE) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_valve_update(this);
|
||||
#endif
|
||||
|
||||
if (save) {
|
||||
ValveRestoreState restore{};
|
||||
|
||||
@@ -289,9 +289,6 @@ async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], paren)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
# Track controller registration for StaticVector sizing
|
||||
CORE.register_controller()
|
||||
|
||||
version = config[CONF_VERSION]
|
||||
|
||||
cg.add(paren.set_port(config[CONF_PORT]))
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#include "esphome/components/json/json_util.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/controller_registry.h"
|
||||
#include "esphome/core/entity_base.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -296,7 +294,7 @@ std::string WebServer::get_config_json() {
|
||||
}
|
||||
|
||||
void WebServer::setup() {
|
||||
ControllerRegistry::register_controller(this);
|
||||
this->setup_controller(this->include_internal_);
|
||||
this->base_->init();
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
@@ -432,9 +430,7 @@ static JsonDetail get_request_detail(AsyncWebServerRequest *request) {
|
||||
}
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
void WebServer::on_sensor_update(sensor::Sensor *obj) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_sensor_update(sensor::Sensor *obj, float state) {
|
||||
this->events_.deferrable_send_state(obj, "state", sensor_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
@@ -477,9 +473,7 @@ 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) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) {
|
||||
this->events_.deferrable_send_state(obj, "state", text_sensor_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
@@ -519,9 +513,7 @@ std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std:
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
void WebServer::on_switch_update(switch_::Switch *obj) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_switch_update(switch_::Switch *obj, bool state) {
|
||||
this->events_.deferrable_send_state(obj, "state", switch_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
@@ -633,8 +625,6 @@ 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) {
|
||||
@@ -674,8 +664,6 @@ 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) {
|
||||
@@ -750,8 +738,6 @@ 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) {
|
||||
@@ -825,8 +811,6 @@ 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) {
|
||||
@@ -911,9 +895,7 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
void WebServer::on_number_update(number::Number *obj) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_number_update(number::Number *obj, float state) {
|
||||
this->events_.deferrable_send_state(obj, "state", number_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
@@ -979,8 +961,6 @@ 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) {
|
||||
@@ -1036,8 +1016,6 @@ 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) {
|
||||
@@ -1092,8 +1070,6 @@ 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) {
|
||||
@@ -1148,9 +1124,7 @@ 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) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_text_update(text::Text *obj, const std::string &state) {
|
||||
this->events_.deferrable_send_state(obj, "state", text_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
@@ -1204,9 +1178,7 @@ 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) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_select_update(select::Select *obj, const std::string &state, size_t index) {
|
||||
this->events_.deferrable_send_state(obj, "state", select_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
@@ -1265,8 +1237,6 @@ 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) {
|
||||
@@ -1408,8 +1378,6 @@ 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) {
|
||||
@@ -1481,8 +1449,6 @@ 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) {
|
||||
@@ -1564,8 +1530,6 @@ 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) {
|
||||
@@ -1643,9 +1607,7 @@ std::string WebServer::alarm_control_panel_json(alarm_control_panel::AlarmContro
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
void WebServer::on_event(event::Event *obj) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
void WebServer::on_event(event::Event *obj, const std::string &event_type) {
|
||||
this->events_.deferrable_send_state(obj, "state", event_state_json_generator);
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
void on_sensor_update(sensor::Sensor *obj) override;
|
||||
void on_sensor_update(sensor::Sensor *obj, float state) 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) override;
|
||||
void on_switch_update(switch_::Switch *obj, bool state) 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) override;
|
||||
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) 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) override;
|
||||
void on_number_update(number::Number *obj, float state) 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) override;
|
||||
void on_text_update(text::Text *obj, const std::string &state) 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) override;
|
||||
void on_select_update(select::Select *obj, const std::string &state, size_t index) override;
|
||||
/// Handle a select request under '/select/<id>'.
|
||||
void handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match);
|
||||
|
||||
@@ -462,7 +462,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
void on_event(event::Event *obj) override;
|
||||
void on_event(event::Event *obj, const std::string &event_type) override;
|
||||
|
||||
static std::string event_state_json_generator(WebServer *web_server, void *source);
|
||||
static std::string event_all_json_generator(WebServer *web_server, void *source);
|
||||
|
||||
@@ -48,9 +48,6 @@ if TYPE_CHECKING:
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Key for tracking controller count in CORE.data for ControllerRegistry StaticVector sizing
|
||||
KEY_CONTROLLER_REGISTRY_COUNT = "controller_registry_count"
|
||||
|
||||
|
||||
class EsphomeError(Exception):
|
||||
"""General ESPHome exception occurred."""
|
||||
@@ -913,11 +910,6 @@ class EsphomeCore:
|
||||
"""
|
||||
self.platform_counts[platform_name] += 1
|
||||
|
||||
def register_controller(self) -> None:
|
||||
"""Track registration of a Controller for ControllerRegistry StaticVector sizing."""
|
||||
controller_count = self.data.setdefault(KEY_CONTROLLER_REGISTRY_COUNT, 0)
|
||||
self.data[KEY_CONTROLLER_REGISTRY_COUNT] = controller_count + 1
|
||||
|
||||
@property
|
||||
def cpp_main_section(self):
|
||||
from esphome.cpp_generator import statement
|
||||
|
||||
@@ -40,12 +40,7 @@ from esphome.const import (
|
||||
PlatformFramework,
|
||||
__version__ as ESPHOME_VERSION,
|
||||
)
|
||||
from esphome.core import (
|
||||
CORE,
|
||||
KEY_CONTROLLER_REGISTRY_COUNT,
|
||||
CoroPriority,
|
||||
coroutine_with_priority,
|
||||
)
|
||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
||||
from esphome.helpers import (
|
||||
copy_file_if_changed,
|
||||
fnv1a_32bit_hash,
|
||||
@@ -467,15 +462,6 @@ async def _add_platform_defines() -> None:
|
||||
cg.add_define(f"USE_{platform_name.upper()}")
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _add_controller_registry_define() -> None:
|
||||
# Generate StaticVector size for ControllerRegistry
|
||||
controller_count = CORE.data.get(KEY_CONTROLLER_REGISTRY_COUNT, 0)
|
||||
if controller_count > 0:
|
||||
cg.add_define("USE_CONTROLLER_REGISTRY")
|
||||
cg.add_define("CONTROLLER_REGISTRY_MAX", controller_count)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.CORE)
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
cg.add_global(cg.global_ns.namespace("esphome").using)
|
||||
@@ -497,7 +483,6 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("ESPHOME_COMPONENT_COUNT", len(CORE.component_ids))
|
||||
|
||||
CORE.add_job(_add_platform_defines)
|
||||
CORE.add_job(_add_controller_registry_define)
|
||||
|
||||
CORE.add_job(_add_automations, config)
|
||||
|
||||
|
||||
134
esphome/core/controller.cpp
Normal file
134
esphome/core/controller.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#include "controller.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
void Controller::setup_controller(bool include_internal) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors()) {
|
||||
if (include_internal || !obj->is_internal()) {
|
||||
obj->add_full_state_callback(
|
||||
[this, obj](optional<bool> previous, optional<bool> state) { this->on_binary_sensor_update(obj); });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
for (auto *obj : App.get_fans()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_fan_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
for (auto *obj : App.get_lights()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_new_remote_values_callback([this, obj]() { this->on_light_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
for (auto *obj : App.get_sensors()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](float state) { this->on_sensor_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
for (auto *obj : App.get_switches()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](bool state) { this->on_switch_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_COVER
|
||||
for (auto *obj : App.get_covers()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_cover_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
for (auto *obj : App.get_text_sensors()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](const std::string &state) { this->on_text_sensor_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
for (auto *obj : App.get_climates()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](climate::Climate & /*unused*/) { this->on_climate_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
for (auto *obj : App.get_numbers()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](float state) { this->on_number_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATE
|
||||
for (auto *obj : App.get_dates()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_date_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_DATETIME_TIME
|
||||
for (auto *obj : App.get_times()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_time_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
for (auto *obj : App.get_datetimes()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_datetime_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEXT
|
||||
for (auto *obj : App.get_texts()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](const std::string &state) { this->on_text_update(obj, state); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
for (auto *obj : App.get_selects()) {
|
||||
if (include_internal || !obj->is_internal()) {
|
||||
obj->add_on_state_callback(
|
||||
[this, obj](const std::string &state, size_t index) { this->on_select_update(obj, state, index); });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LOCK
|
||||
for (auto *obj : App.get_locks()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_lock_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_VALVE
|
||||
for (auto *obj : App.get_valves()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_valve_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
for (auto *obj : App.get_media_players()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_media_player_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
for (auto *obj : App.get_alarm_control_panels()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_alarm_control_panel_update(obj); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_EVENT
|
||||
for (auto *obj : App.get_events()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_event_callback([this, obj](const std::string &event_type) { this->on_event(obj, event_type); });
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_UPDATE
|
||||
for (auto *obj : App.get_updates()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj]() { this->on_update(obj); });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace esphome
|
||||
@@ -69,6 +69,7 @@ namespace esphome {
|
||||
|
||||
class Controller {
|
||||
public:
|
||||
void setup_controller(bool include_internal = false);
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
virtual void on_binary_sensor_update(binary_sensor::BinarySensor *obj){};
|
||||
#endif
|
||||
@@ -79,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){};
|
||||
virtual void on_sensor_update(sensor::Sensor *obj, float state){};
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
virtual void on_switch_update(switch_::Switch *obj){};
|
||||
virtual void on_switch_update(switch_::Switch *obj, bool state){};
|
||||
#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){};
|
||||
virtual void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state){};
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
virtual void on_climate_update(climate::Climate *obj){};
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
virtual void on_number_update(number::Number *obj){};
|
||||
virtual void on_number_update(number::Number *obj, float state){};
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATE
|
||||
virtual void on_date_update(datetime::DateEntity *obj){};
|
||||
@@ -106,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){};
|
||||
virtual void on_text_update(text::Text *obj, const std::string &state){};
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
virtual void on_select_update(select::Select *obj){};
|
||||
virtual void on_select_update(select::Select *obj, const std::string &state, size_t index){};
|
||||
#endif
|
||||
#ifdef USE_LOCK
|
||||
virtual void on_lock_update(lock::Lock *obj){};
|
||||
@@ -124,7 +125,7 @@ class Controller {
|
||||
virtual void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj){};
|
||||
#endif
|
||||
#ifdef USE_EVENT
|
||||
virtual void on_event(event::Event *obj){};
|
||||
virtual void on_event(event::Event *obj, const std::string &event_type){};
|
||||
#endif
|
||||
#ifdef USE_UPDATE
|
||||
virtual void on_update(update::UpdateEntity *obj){};
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
#include "esphome/core/controller_registry.h"
|
||||
|
||||
#ifdef USE_CONTROLLER_REGISTRY
|
||||
|
||||
#include "esphome/core/controller.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
StaticVector<Controller *, CONTROLLER_REGISTRY_MAX> ControllerRegistry::controllers;
|
||||
|
||||
void ControllerRegistry::register_controller(Controller *controller) { controllers.push_back(controller); }
|
||||
|
||||
// Macro for standard registry notification dispatch - calls on_<entity_name>_update()
|
||||
#define CONTROLLER_REGISTRY_NOTIFY(entity_type, entity_name) \
|
||||
void ControllerRegistry::notify_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
|
||||
for (auto *controller : controllers) { \
|
||||
controller->on_##entity_name##_update(obj); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Macro for entities where controller method has no "_update" suffix (Event, Update)
|
||||
#define CONTROLLER_REGISTRY_NOTIFY_NO_UPDATE_SUFFIX(entity_type, entity_name) \
|
||||
void ControllerRegistry::notify_##entity_name(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
|
||||
for (auto *controller : controllers) { \
|
||||
controller->on_##entity_name(obj); \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
CONTROLLER_REGISTRY_NOTIFY(binary_sensor::BinarySensor, binary_sensor)
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
CONTROLLER_REGISTRY_NOTIFY(fan::Fan, fan)
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
CONTROLLER_REGISTRY_NOTIFY(light::LightState, light)
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
CONTROLLER_REGISTRY_NOTIFY(sensor::Sensor, sensor)
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
CONTROLLER_REGISTRY_NOTIFY(switch_::Switch, switch)
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
CONTROLLER_REGISTRY_NOTIFY(cover::Cover, cover)
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
CONTROLLER_REGISTRY_NOTIFY(text_sensor::TextSensor, text_sensor)
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
CONTROLLER_REGISTRY_NOTIFY(climate::Climate, climate)
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
CONTROLLER_REGISTRY_NOTIFY(number::Number, number)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATE
|
||||
CONTROLLER_REGISTRY_NOTIFY(datetime::DateEntity, date)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_TIME
|
||||
CONTROLLER_REGISTRY_NOTIFY(datetime::TimeEntity, time)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
CONTROLLER_REGISTRY_NOTIFY(datetime::DateTimeEntity, datetime)
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
CONTROLLER_REGISTRY_NOTIFY(text::Text, text)
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
CONTROLLER_REGISTRY_NOTIFY(select::Select, select)
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
CONTROLLER_REGISTRY_NOTIFY(lock::Lock, lock)
|
||||
#endif
|
||||
|
||||
#ifdef USE_VALVE
|
||||
CONTROLLER_REGISTRY_NOTIFY(valve::Valve, valve)
|
||||
#endif
|
||||
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
CONTROLLER_REGISTRY_NOTIFY(media_player::MediaPlayer, media_player)
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
CONTROLLER_REGISTRY_NOTIFY(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
CONTROLLER_REGISTRY_NOTIFY_NO_UPDATE_SUFFIX(event::Event, event)
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
CONTROLLER_REGISTRY_NOTIFY_NO_UPDATE_SUFFIX(update::UpdateEntity, update)
|
||||
#endif
|
||||
|
||||
#undef CONTROLLER_REGISTRY_NOTIFY
|
||||
#undef CONTROLLER_REGISTRY_NOTIFY_NO_UPDATE_SUFFIX
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_CONTROLLER_REGISTRY
|
||||
@@ -1,245 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_CONTROLLER_REGISTRY
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
// 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 controller callbacks (32 bytes overhead per entity),
|
||||
* entities call ControllerRegistry::notify_*_update() which iterates the small list
|
||||
* of registered controllers (typically 2: API and WebServer).
|
||||
*
|
||||
* Controllers read state directly from entities using existing accessors (obj->state, etc.)
|
||||
* rather than receiving it as callback parameters that were being ignored anyway.
|
||||
*
|
||||
* Memory savings: 32 bytes per entity (2 controllers × 16 bytes std::function overhead)
|
||||
* Typical config (25 entities): ~780 bytes saved
|
||||
* Large config (80 entities): ~2,540 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);
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
static void notify_binary_sensor_update(binary_sensor::BinarySensor *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
static void notify_fan_update(fan::Fan *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
static void notify_light_update(light::LightState *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENSOR
|
||||
static void notify_sensor_update(sensor::Sensor *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
static void notify_switch_update(switch_::Switch *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
static void notify_cover_update(cover::Cover *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
static void notify_text_sensor_update(text_sensor::TextSensor *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
static void notify_climate_update(climate::Climate *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
static void notify_number_update(number::Number *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATE
|
||||
static void notify_date_update(datetime::DateEntity *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_TIME
|
||||
static void notify_time_update(datetime::TimeEntity *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
static void notify_datetime_update(datetime::DateTimeEntity *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
static void notify_text_update(text::Text *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
static void notify_select_update(select::Select *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
static void notify_lock_update(lock::Lock *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_VALVE
|
||||
static void notify_valve_update(valve::Valve *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
static void notify_media_player_update(media_player::MediaPlayer *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
static void notify_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
static void notify_event(event::Event *obj);
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
static void notify_update(update::UpdateEntity *obj);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static StaticVector<Controller *, CONTROLLER_REGISTRY_MAX> controllers;
|
||||
};
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_CONTROLLER_REGISTRY
|
||||
@@ -28,7 +28,6 @@
|
||||
#define USE_BUTTON
|
||||
#define USE_CAMERA
|
||||
#define USE_CLIMATE
|
||||
#define USE_CONTROLLER_REGISTRY
|
||||
#define USE_COVER
|
||||
#define USE_DATETIME
|
||||
#define USE_DATETIME_DATE
|
||||
@@ -297,7 +296,6 @@
|
||||
#define USE_DASHBOARD_IMPORT
|
||||
|
||||
// Default counts for static analysis
|
||||
#define CONTROLLER_REGISTRY_MAX 2
|
||||
#define ESPHOME_COMPONENT_COUNT 50
|
||||
#define ESPHOME_DEVICE_COUNT 10
|
||||
#define ESPHOME_AREA_COUNT 10
|
||||
|
||||
@@ -12,7 +12,7 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
||||
esptool==5.1.0
|
||||
click==8.1.7
|
||||
esphome-dashboard==20251013.0
|
||||
aioesphomeapi==42.6.0
|
||||
aioesphomeapi==42.7.0
|
||||
zeroconf==0.148.0
|
||||
puremagic==1.30
|
||||
ruamel.yaml==0.18.16 # dashboard_import
|
||||
|
||||
@@ -178,14 +178,6 @@ api:
|
||||
- logger.log: "Skipped loops"
|
||||
- logger.log: "After combined test"
|
||||
|
||||
event:
|
||||
- platform: template
|
||||
name: Test Event
|
||||
id: test_event
|
||||
event_types:
|
||||
- single_click
|
||||
- double_click
|
||||
|
||||
globals:
|
||||
- id: api_continuation_test_counter
|
||||
type: int
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
number:
|
||||
- platform: template
|
||||
id: test_number
|
||||
optimistic: true
|
||||
min_value: 0
|
||||
max_value: 255
|
||||
step: 1
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: Beo4 audio mute
|
||||
@@ -217,6 +225,23 @@ button:
|
||||
command: 0xEC
|
||||
rc_code_1: 0x0D
|
||||
rc_code_2: 0x0D
|
||||
- platform: template
|
||||
name: ABBWelcome static
|
||||
on_press:
|
||||
remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x01
|
||||
data: [0x10, 0x20, 0x30]
|
||||
- platform: template
|
||||
name: ABBWelcome lambda
|
||||
on_press:
|
||||
remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x01
|
||||
data: !lambda |-
|
||||
return {(uint8_t)id(test_number).state, 0x20, 0x30};
|
||||
- platform: template
|
||||
name: Digital Write
|
||||
on_press:
|
||||
|
||||
Reference in New Issue
Block a user