mirror of
https://github.com/esphome/esphome.git
synced 2026-02-01 09:17:34 -07:00
Compare commits
8 Commits
json_web_s
...
parition_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df2936f686 | ||
|
|
ab0ca3006a | ||
|
|
4634eb3ce4 | ||
|
|
f19bbbd1c5 | ||
|
|
0f136a888c | ||
|
|
6feaa8dd13 | ||
|
|
4c3931363f | ||
|
|
9a2fc8aa51 |
@@ -76,9 +76,9 @@ StateClass Sensor::get_state_class() {
|
|||||||
|
|
||||||
void Sensor::publish_state(float state) {
|
void Sensor::publish_state(float state) {
|
||||||
this->raw_state = state;
|
this->raw_state = state;
|
||||||
if (this->raw_callback_) {
|
|
||||||
this->raw_callback_->call(state);
|
// Call raw callbacks (before filters)
|
||||||
}
|
this->callbacks_.call_first(this->raw_count_, state);
|
||||||
|
|
||||||
ESP_LOGV(TAG, "'%s': Received new state %f", this->name_.c_str(), state);
|
ESP_LOGV(TAG, "'%s': Received new state %f", this->name_.c_str(), state);
|
||||||
|
|
||||||
@@ -89,12 +89,12 @@ void Sensor::publish_state(float state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sensor::add_on_state_callback(std::function<void(float)> &&callback) { this->callback_.add(std::move(callback)); }
|
void Sensor::add_on_state_callback(std::function<void(float)> &&callback) {
|
||||||
|
this->callbacks_.add_second(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
void Sensor::add_on_raw_state_callback(std::function<void(float)> &&callback) {
|
void Sensor::add_on_raw_state_callback(std::function<void(float)> &&callback) {
|
||||||
if (!this->raw_callback_) {
|
this->callbacks_.add_first(std::move(callback), &this->raw_count_);
|
||||||
this->raw_callback_ = make_unique<CallbackManager<void(float)>>();
|
|
||||||
}
|
|
||||||
this->raw_callback_->add(std::move(callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sensor::add_filter(Filter *filter) {
|
void Sensor::add_filter(Filter *filter) {
|
||||||
@@ -134,7 +134,10 @@ void Sensor::internal_send_state_to_frontend(float state) {
|
|||||||
this->state = state;
|
this->state = state;
|
||||||
ESP_LOGD(TAG, "'%s': Sending state %.5f %s with %d decimals of accuracy", this->get_name().c_str(), 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->get_unit_of_measurement_ref().c_str(), this->get_accuracy_decimals());
|
||||||
this->callback_.call(state);
|
|
||||||
|
// Call filtered callbacks (after filters)
|
||||||
|
this->callbacks_.call_second(this->raw_count_, state);
|
||||||
|
|
||||||
#if defined(USE_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
#if defined(USE_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||||
ControllerRegistry::notify_sensor_update(this);
|
ControllerRegistry::notify_sensor_update(this);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -125,8 +125,7 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
|
|||||||
void internal_send_state_to_frontend(float state);
|
void internal_send_state_to_frontend(float state);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<CallbackManager<void(float)>> raw_callback_; ///< Storage for raw state callbacks (lazy allocated).
|
PartitionedCallbackManager<void(float)> callbacks_;
|
||||||
CallbackManager<void(float)> callback_; ///< Storage for filtered state callbacks.
|
|
||||||
|
|
||||||
Filter *filter_list_{nullptr}; ///< Store all active filters.
|
Filter *filter_list_{nullptr}; ///< Store all active filters.
|
||||||
|
|
||||||
@@ -141,6 +140,8 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
|
|||||||
uint8_t force_update : 1;
|
uint8_t force_update : 1;
|
||||||
uint8_t reserved : 5; // Reserved for future use
|
uint8_t reserved : 5; // Reserved for future use
|
||||||
} sensor_flags_{};
|
} sensor_flags_{};
|
||||||
|
|
||||||
|
uint8_t raw_count_{0}; ///< Number of raw callbacks (partition point in callbacks_ vector)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sensor
|
} // namespace sensor
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ void TextSensor::publish_state(const std::string &state) {
|
|||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
this->raw_state = state;
|
this->raw_state = state;
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
if (this->raw_callback_) {
|
|
||||||
this->raw_callback_->call(state);
|
// Call raw callbacks (before filters)
|
||||||
}
|
this->callbacks_.call_first(this->raw_count_, state);
|
||||||
|
|
||||||
ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), state.c_str());
|
ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), state.c_str());
|
||||||
|
|
||||||
@@ -74,13 +74,11 @@ void TextSensor::clear_filters() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextSensor::add_on_state_callback(std::function<void(std::string)> callback) {
|
void TextSensor::add_on_state_callback(std::function<void(std::string)> callback) {
|
||||||
this->callback_.add(std::move(callback));
|
this->callbacks_.add_second(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextSensor::add_on_raw_state_callback(std::function<void(std::string)> callback) {
|
void TextSensor::add_on_raw_state_callback(std::function<void(std::string)> callback) {
|
||||||
if (!this->raw_callback_) {
|
this->callbacks_.add_first(std::move(callback), &this->raw_count_);
|
||||||
this->raw_callback_ = make_unique<CallbackManager<void(std::string)>>();
|
|
||||||
}
|
|
||||||
this->raw_callback_->add(std::move(callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TextSensor::get_state() const { return this->state; }
|
std::string TextSensor::get_state() const { return this->state; }
|
||||||
@@ -95,7 +93,10 @@ void TextSensor::internal_send_state_to_frontend(const std::string &state) {
|
|||||||
this->state = state;
|
this->state = state;
|
||||||
this->set_has_state(true);
|
this->set_has_state(true);
|
||||||
ESP_LOGD(TAG, "'%s': Sending state '%s'", this->name_.c_str(), state.c_str());
|
ESP_LOGD(TAG, "'%s': Sending state '%s'", this->name_.c_str(), state.c_str());
|
||||||
this->callback_.call(state);
|
|
||||||
|
// Call filtered callbacks (after filters)
|
||||||
|
this->callbacks_.call_second(this->raw_count_, state);
|
||||||
|
|
||||||
#if defined(USE_TEXT_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
#if defined(USE_TEXT_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||||
ControllerRegistry::notify_text_sensor_update(this);
|
ControllerRegistry::notify_text_sensor_update(this);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -65,11 +65,11 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass {
|
|||||||
void internal_send_state_to_frontend(const std::string &state);
|
void internal_send_state_to_frontend(const std::string &state);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<CallbackManager<void(std::string)>>
|
PartitionedCallbackManager<void(std::string)> callbacks_;
|
||||||
raw_callback_; ///< Storage for raw state callbacks (lazy allocated).
|
|
||||||
CallbackManager<void(std::string)> callback_; ///< Storage for filtered state callbacks.
|
|
||||||
|
|
||||||
Filter *filter_list_{nullptr}; ///< Store all active filters.
|
Filter *filter_list_{nullptr}; ///< Store all active filters.
|
||||||
|
|
||||||
|
uint8_t raw_count_{0}; ///< Number of raw callbacks (partition point in callbacks_ vector)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace text_sensor
|
} // namespace text_sensor
|
||||||
|
|||||||
@@ -926,6 +926,73 @@ template<typename... Ts> class CallbackManager<void(Ts...)> {
|
|||||||
std::vector<std::function<void(Ts...)>> callbacks_;
|
std::vector<std::function<void(Ts...)>> callbacks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename... X> class PartitionedCallbackManager;
|
||||||
|
|
||||||
|
/** Helper class for callbacks partitioned into two sections.
|
||||||
|
*
|
||||||
|
* Uses a single vector partitioned into two sections: [first_0, ..., first_m-1, second_0, ..., second_n-1]
|
||||||
|
* The partition point is tracked externally by the caller (typically stored in the entity class for optimal alignment).
|
||||||
|
*
|
||||||
|
* Memory efficient: Only stores a single pointer (4 bytes on 32-bit platforms, 8 bytes on 64-bit platforms).
|
||||||
|
* The partition count lives in the entity class where it can be packed with other small fields to avoid padding waste.
|
||||||
|
*
|
||||||
|
* Design rationale: The asymmetric API (add_first takes first_count*, while call_first/call_second take it by value)
|
||||||
|
* is intentional - add_first must increment the count, while call methods only read it. This avoids storing first_count
|
||||||
|
* internally, saving memory per instance.
|
||||||
|
*
|
||||||
|
* @tparam Ts The arguments for the callbacks, wrapped in void().
|
||||||
|
*/
|
||||||
|
template<typename... Ts> class PartitionedCallbackManager<void(Ts...)> {
|
||||||
|
public:
|
||||||
|
/// Add a callback to the first partition.
|
||||||
|
void add_first(std::function<void(Ts...)> &&callback, uint8_t *first_count) {
|
||||||
|
if (!this->callbacks_) {
|
||||||
|
this->callbacks_ = make_unique<std::vector<std::function<void(Ts...)>>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to first partition: append then rotate into position
|
||||||
|
this->callbacks_->push_back(std::move(callback));
|
||||||
|
// Avoid potential underflow: rewrite comparison to not subtract from size()
|
||||||
|
if (*first_count + 1 < this->callbacks_->size()) {
|
||||||
|
// Use std::rotate to maintain registration order in second partition
|
||||||
|
std::rotate(this->callbacks_->begin() + *first_count, this->callbacks_->end() - 1, this->callbacks_->end());
|
||||||
|
}
|
||||||
|
(*first_count)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a callback to the second partition.
|
||||||
|
void add_second(std::function<void(Ts...)> &&callback) {
|
||||||
|
if (!this->callbacks_) {
|
||||||
|
this->callbacks_ = make_unique<std::vector<std::function<void(Ts...)>>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to second partition: just append (already at end after first partition)
|
||||||
|
this->callbacks_->push_back(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call all callbacks in the first partition.
|
||||||
|
void call_first(uint8_t first_count, Ts... args) {
|
||||||
|
if (this->callbacks_) {
|
||||||
|
for (size_t i = 0; i < first_count; i++) {
|
||||||
|
(*this->callbacks_)[i](args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call all callbacks in the second partition.
|
||||||
|
void call_second(uint8_t first_count, Ts... args) {
|
||||||
|
if (this->callbacks_) {
|
||||||
|
for (size_t i = first_count; i < this->callbacks_->size(); i++) {
|
||||||
|
(*this->callbacks_)[i](args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Partitioned callback storage: [first_0, ..., first_m-1, second_0, ..., second_n-1]
|
||||||
|
std::unique_ptr<std::vector<std::function<void(Ts...)>>> callbacks_;
|
||||||
|
};
|
||||||
|
|
||||||
/// Helper class to deduplicate items in a series of values.
|
/// Helper class to deduplicate items in a series of values.
|
||||||
template<typename T> class Deduplicator {
|
template<typename T> class Deduplicator {
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user