diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 5569567de1..8bbaa73e2e 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -620,7 +620,7 @@ async def delta_filter_to_code(config, filter_id): @FILTER_REGISTRY.register("or", OrFilter, validate_filters) async def or_filter_to_code(config, filter_id): filters = await build_filters(config) - return cg.new_Pvariable(filter_id, filters) + return cg.new_Pvariable(filter_id, cg.TemplateArguments(len(filters)), filters) @FILTER_REGISTRY.register( diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index eef5c6cade..2f284cdcf0 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -285,32 +285,20 @@ optional DeltaFilter::new_value(float value) { return {}; } -// OrFilter -OrFilter::OrFilter(std::initializer_list filters) : filters_(filters), phi_(this) {} -OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {} - -optional OrFilter::PhiNode::new_value(float value) { - if (!this->or_parent_->has_value_) { - this->or_parent_->output(value); - this->or_parent_->has_value_ = true; +// OrFilter helpers +void or_filter_initialize(Filter **filters, size_t count, Sensor *parent, Filter *phi) { + for (size_t i = 0; i < count; i++) { + filters[i]->initialize(parent, phi); } - - return {}; + phi->initialize(parent, nullptr); } -optional OrFilter::new_value(float value) { - this->has_value_ = false; - for (auto *filter : this->filters_) - filter->input(value); +optional or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value) { + has_value = false; + for (size_t i = 0; i < count; i++) + filters[i]->input(value); return {}; } -void OrFilter::initialize(Sensor *parent, Filter *next) { - Filter::initialize(parent, next); - for (auto *filter : this->filters_) { - filter->initialize(parent, &this->phi_); - } - this->phi_.initialize(parent, nullptr); -} // TimeoutFilterBase - shared loop logic void TimeoutFilterBase::loop() { diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 05ffa4cb6e..d7a56ccb28 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -498,26 +498,49 @@ class DeltaFilter : public Filter { float last_value_{NAN}; }; -class OrFilter : public Filter { +/// Non-template helpers for OrFilter (implementation in filter.cpp) +void or_filter_initialize(Filter **filters, size_t count, Sensor *parent, Filter *phi); +optional or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value); + +/// N is set by code generation to match the exact number of filters configured in YAML. +template class OrFilter : public Filter { public: - explicit OrFilter(std::initializer_list filters); + explicit OrFilter(std::initializer_list filters) { + size_t i = 0; + for (auto *f : filters) { + if (i >= N) + break; + this->filters_[i++] = f; + } + } - void initialize(Sensor *parent, Filter *next) override; + void initialize(Sensor *parent, Filter *next) override { + Filter::initialize(parent, next); + or_filter_initialize(this->filters_.data(), N, parent, &this->phi_); + } - optional new_value(float value) override; + optional new_value(float value) override { + return or_filter_new_value(this->filters_.data(), N, value, this->has_value_); + } protected: class PhiNode : public Filter { public: - PhiNode(OrFilter *or_parent); - optional new_value(float value) override; + PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {} + optional new_value(float value) override { + if (!this->or_parent_->has_value_) { + this->or_parent_->output(value); + this->or_parent_->has_value_ = true; + } + return {}; + } protected: OrFilter *or_parent_; }; - FixedVector filters_; - PhiNode phi_; + std::array filters_{}; + PhiNode phi_{this}; bool has_value_{false}; };