diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index cb74a41119..4b2e9dc019 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -160,6 +160,7 @@ SlidingWindowMovingAverageFilter = sensor_ns.class_( ExponentialMovingAverageFilter = sensor_ns.class_( "ExponentialMovingAverageFilter", Filter ) +ThrottleAverageFilter = sensor_ns.class_("ThrottleAverageFilter", Filter, cg.Component) LambdaFilter = sensor_ns.class_("LambdaFilter", Filter) OffsetFilter = sensor_ns.class_("OffsetFilter", Filter) MultiplyFilter = sensor_ns.class_("MultiplyFilter", Filter) @@ -381,6 +382,15 @@ async def exponential_moving_average_filter_to_code(config, filter_id): return cg.new_Pvariable(filter_id, config[CONF_ALPHA], config[CONF_SEND_EVERY]) +@FILTER_REGISTRY.register( + "throttle_average", ThrottleAverageFilter, cv.positive_time_period_milliseconds +) +async def throttle_average_filter_to_code(config, filter_id): + var = cg.new_Pvariable(filter_id, config) + await cg.register_component(var, {}) + return var + + @FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda) async def lambda_filter_to_code(config, filter_id): lambda_ = await cg.process_lambda( diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 63801e7996..321e3a4a4f 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -187,6 +187,31 @@ optional ExponentialMovingAverageFilter::new_value(float value) { void ExponentialMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; } void ExponentialMovingAverageFilter::set_alpha(float alpha) { this->alpha_ = alpha; } +// ThrottleAverageFilter +ThrottleAverageFilter::ThrottleAverageFilter(uint32_t time_period) : time_period_(time_period) {} + +optional ThrottleAverageFilter::new_value(float value) { + ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value); + if (!std::isnan(value)) { + this->sum_ += value; + this->n_++; + } + return {}; +} +void ThrottleAverageFilter::setup() { + this->set_interval("throttle_average", this->time_period_, [this]() { + ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_); + if (this->n_ == 0) { + this->output(NAN); + } else { + this->output(this->sum_ / this->n_); + this->sum_ = 0.0f; + this->n_ = 0; + } + }); +} +float ThrottleAverageFilter::get_setup_priority() const { return setup_priority::HARDWARE; } + // LambdaFilter LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::move(lambda_filter)) {} const lambda_filter_t &LambdaFilter::get_lambda_filter() const { return this->lambda_filter_; } diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 29a6813ea9..d595e419a6 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -178,6 +178,26 @@ class ExponentialMovingAverageFilter : public Filter { float alpha_; }; +/** Simple throttle average filter. + * + * It takes the average of all the values received in a period of time. + */ +class ThrottleAverageFilter : public Filter, public Component { + public: + explicit ThrottleAverageFilter(uint32_t time_period); + + void setup() override; + + optional new_value(float value) override; + + float get_setup_priority() const override; + + protected: + uint32_t time_period_; + float sum_{0.0f}; + unsigned int n_{0}; +}; + using lambda_filter_t = std::function(float)>; /** This class allows for creation of simple template filters. diff --git a/tests/test1.yaml b/tests/test1.yaml index 540a715dde..157ccfc5d1 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -343,6 +343,7 @@ sensor: - exponential_moving_average: alpha: 0.1 send_every: 15 + - throttle_average: 60s - throttle: 1s - heartbeat: 5s - debounce: 0.1s