ESPHome  2024.12.2
filter.cpp
Go to the documentation of this file.
1 #include "filter.h"
2 #include <cmath>
3 #include "esphome/core/hal.h"
4 #include "esphome/core/log.h"
5 #include "sensor.h"
6 
7 namespace esphome {
8 namespace sensor {
9 
10 static const char *const TAG = "sensor.filter";
11 
12 // Filter
13 void Filter::input(float value) {
14  ESP_LOGVV(TAG, "Filter(%p)::input(%f)", this, value);
15  optional<float> out = this->new_value(value);
16  if (out.has_value())
17  this->output(*out);
18 }
19 void Filter::output(float value) {
20  if (this->next_ == nullptr) {
21  ESP_LOGVV(TAG, "Filter(%p)::output(%f) -> SENSOR", this, value);
23  } else {
24  ESP_LOGVV(TAG, "Filter(%p)::output(%f) -> %p", this, value, this->next_);
25  this->next_->input(value);
26  }
27 }
28 void Filter::initialize(Sensor *parent, Filter *next) {
29  ESP_LOGVV(TAG, "Filter(%p)::initialize(parent=%p next=%p)", this, parent, next);
30  this->parent_ = parent;
31  this->next_ = next;
32 }
33 
34 // MedianFilter
35 MedianFilter::MedianFilter(size_t window_size, size_t send_every, size_t send_first_at)
36  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
37 void MedianFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
38 void MedianFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
40  while (this->queue_.size() >= this->window_size_) {
41  this->queue_.pop_front();
42  }
43  this->queue_.push_back(value);
44  ESP_LOGVV(TAG, "MedianFilter(%p)::new_value(%f)", this, value);
45 
46  if (++this->send_at_ >= this->send_every_) {
47  this->send_at_ = 0;
48 
49  float median = NAN;
50  if (!this->queue_.empty()) {
51  // Copy queue without NaN values
52  std::vector<float> median_queue;
53  for (auto v : this->queue_) {
54  if (!std::isnan(v)) {
55  median_queue.push_back(v);
56  }
57  }
58 
59  sort(median_queue.begin(), median_queue.end());
60 
61  size_t queue_size = median_queue.size();
62  if (queue_size) {
63  if (queue_size % 2) {
64  median = median_queue[queue_size / 2];
65  } else {
66  median = (median_queue[queue_size / 2] + median_queue[(queue_size / 2) - 1]) / 2.0f;
67  }
68  }
69  }
70 
71  ESP_LOGVV(TAG, "MedianFilter(%p)::new_value(%f) SENDING %f", this, value, median);
72  return median;
73  }
74  return {};
75 }
76 
77 // SkipInitialFilter
78 SkipInitialFilter::SkipInitialFilter(size_t num_to_ignore) : num_to_ignore_(num_to_ignore) {}
80  if (num_to_ignore_ > 0) {
82  ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %zu left", this, value, num_to_ignore_);
83  return {};
84  }
85 
86  ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SENDING", this, value);
87  return value;
88 }
89 
90 // QuantileFilter
91 QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
92  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size), quantile_(quantile) {}
93 void QuantileFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
94 void QuantileFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
95 void QuantileFilter::set_quantile(float quantile) { this->quantile_ = quantile; }
97  while (this->queue_.size() >= this->window_size_) {
98  this->queue_.pop_front();
99  }
100  this->queue_.push_back(value);
101  ESP_LOGVV(TAG, "QuantileFilter(%p)::new_value(%f), quantile:%f", this, value, this->quantile_);
102 
103  if (++this->send_at_ >= this->send_every_) {
104  this->send_at_ = 0;
105 
106  float result = NAN;
107  if (!this->queue_.empty()) {
108  // Copy queue without NaN values
109  std::vector<float> quantile_queue;
110  for (auto v : this->queue_) {
111  if (!std::isnan(v)) {
112  quantile_queue.push_back(v);
113  }
114  }
115 
116  sort(quantile_queue.begin(), quantile_queue.end());
117 
118  size_t queue_size = quantile_queue.size();
119  if (queue_size) {
120  size_t position = ceilf(queue_size * this->quantile_) - 1;
121  ESP_LOGVV(TAG, "QuantileFilter(%p)::position: %d/%d", this, position + 1, queue_size);
122  result = quantile_queue[position];
123  }
124  }
125 
126  ESP_LOGVV(TAG, "QuantileFilter(%p)::new_value(%f) SENDING %f", this, value, result);
127  return result;
128  }
129  return {};
130 }
131 
132 // MinFilter
133 MinFilter::MinFilter(size_t window_size, size_t send_every, size_t send_first_at)
134  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
135 void MinFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
136 void MinFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
138  while (this->queue_.size() >= this->window_size_) {
139  this->queue_.pop_front();
140  }
141  this->queue_.push_back(value);
142  ESP_LOGVV(TAG, "MinFilter(%p)::new_value(%f)", this, value);
143 
144  if (++this->send_at_ >= this->send_every_) {
145  this->send_at_ = 0;
146 
147  float min = NAN;
148  for (auto v : this->queue_) {
149  if (!std::isnan(v)) {
150  min = std::isnan(min) ? v : std::min(min, v);
151  }
152  }
153 
154  ESP_LOGVV(TAG, "MinFilter(%p)::new_value(%f) SENDING %f", this, value, min);
155  return min;
156  }
157  return {};
158 }
159 
160 // MaxFilter
161 MaxFilter::MaxFilter(size_t window_size, size_t send_every, size_t send_first_at)
162  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
163 void MaxFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
164 void MaxFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
166  while (this->queue_.size() >= this->window_size_) {
167  this->queue_.pop_front();
168  }
169  this->queue_.push_back(value);
170  ESP_LOGVV(TAG, "MaxFilter(%p)::new_value(%f)", this, value);
171 
172  if (++this->send_at_ >= this->send_every_) {
173  this->send_at_ = 0;
174 
175  float max = NAN;
176  for (auto v : this->queue_) {
177  if (!std::isnan(v)) {
178  max = std::isnan(max) ? v : std::max(max, v);
179  }
180  }
181 
182  ESP_LOGVV(TAG, "MaxFilter(%p)::new_value(%f) SENDING %f", this, value, max);
183  return max;
184  }
185  return {};
186 }
187 
188 // SlidingWindowMovingAverageFilter
190  size_t send_first_at)
191  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
192 void SlidingWindowMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
193 void SlidingWindowMovingAverageFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
195  while (this->queue_.size() >= this->window_size_) {
196  this->queue_.pop_front();
197  }
198  this->queue_.push_back(value);
199  ESP_LOGVV(TAG, "SlidingWindowMovingAverageFilter(%p)::new_value(%f)", this, value);
200 
201  if (++this->send_at_ >= this->send_every_) {
202  this->send_at_ = 0;
203 
204  float sum = 0;
205  size_t valid_count = 0;
206  for (auto v : this->queue_) {
207  if (!std::isnan(v)) {
208  sum += v;
209  valid_count++;
210  }
211  }
212 
213  float average = NAN;
214  if (valid_count) {
215  average = sum / valid_count;
216  }
217 
218  ESP_LOGVV(TAG, "SlidingWindowMovingAverageFilter(%p)::new_value(%f) SENDING %f", this, value, average);
219  return average;
220  }
221  return {};
222 }
223 
224 // ExponentialMovingAverageFilter
225 ExponentialMovingAverageFilter::ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
226  : send_every_(send_every), send_at_(send_every - send_first_at), alpha_(alpha) {}
228  if (!std::isnan(value)) {
229  if (this->first_value_) {
230  this->accumulator_ = value;
231  this->first_value_ = false;
232  } else {
233  this->accumulator_ = (this->alpha_ * value) + (1.0f - this->alpha_) * this->accumulator_;
234  }
235  }
236 
237  const float average = std::isnan(value) ? value : this->accumulator_;
238  ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) -> %f", this, value, average);
239 
240  if (++this->send_at_ >= this->send_every_) {
241  ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) SENDING %f", this, value, average);
242  this->send_at_ = 0;
243  return average;
244  }
245  return {};
246 }
247 void ExponentialMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
248 void ExponentialMovingAverageFilter::set_alpha(float alpha) { this->alpha_ = alpha; }
249 
250 // ThrottleAverageFilter
251 ThrottleAverageFilter::ThrottleAverageFilter(uint32_t time_period) : time_period_(time_period) {}
252 
254  ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value);
255  if (std::isnan(value)) {
256  this->have_nan_ = true;
257  } else {
258  this->sum_ += value;
259  this->n_++;
260  }
261  return {};
262 }
264  this->set_interval("throttle_average", this->time_period_, [this]() {
265  ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_);
266  if (this->n_ == 0) {
267  if (this->have_nan_)
268  this->output(NAN);
269  } else {
270  this->output(this->sum_ / this->n_);
271  this->sum_ = 0.0f;
272  this->n_ = 0;
273  }
274  this->have_nan_ = false;
275  });
276 }
278 
279 // LambdaFilter
280 LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::move(lambda_filter)) {}
282 void LambdaFilter::set_lambda_filter(const lambda_filter_t &lambda_filter) { this->lambda_filter_ = lambda_filter; }
283 
285  auto it = this->lambda_filter_(value);
286  ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%f) -> %f", this, value, it.value_or(INFINITY));
287  return it;
288 }
289 
290 // OffsetFilter
291 OffsetFilter::OffsetFilter(TemplatableValue<float> offset) : offset_(std::move(offset)) {}
292 
293 optional<float> OffsetFilter::new_value(float value) { return value + this->offset_.value(); }
294 
295 // MultiplyFilter
296 MultiplyFilter::MultiplyFilter(TemplatableValue<float> multiplier) : multiplier_(std::move(multiplier)) {}
297 
298 optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_.value(); }
299 
300 // FilterOutValueFilter
302  : values_to_filter_out_(std::move(values_to_filter_out)) {}
303 
305  int8_t accuracy = this->parent_->get_accuracy_decimals();
306  float accuracy_mult = powf(10.0f, accuracy);
307  for (auto filter_value : this->values_to_filter_out_) {
308  if (std::isnan(filter_value.value())) {
309  if (std::isnan(value)) {
310  return {};
311  }
312  continue;
313  }
314  float rounded_filter_out = roundf(accuracy_mult * filter_value.value());
315  float rounded_value = roundf(accuracy_mult * value);
316  if (rounded_filter_out == rounded_value) {
317  return {};
318  }
319  }
320  return value;
321 }
322 
323 // ThrottleFilter
324 ThrottleFilter::ThrottleFilter(uint32_t min_time_between_inputs) : min_time_between_inputs_(min_time_between_inputs) {}
326  const uint32_t now = millis();
327  if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_) {
328  this->last_input_ = now;
329  return value;
330  }
331  return {};
332 }
333 
334 // DeltaFilter
335 DeltaFilter::DeltaFilter(float delta, bool percentage_mode)
336  : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {}
338  if (std::isnan(value)) {
339  if (std::isnan(this->last_value_)) {
340  return {};
341  } else {
342  if (this->percentage_mode_) {
343  this->current_delta_ = fabsf(value * this->delta_);
344  }
345  return this->last_value_ = value;
346  }
347  }
348  if (std::isnan(this->last_value_) || fabsf(value - this->last_value_) >= this->current_delta_) {
349  if (this->percentage_mode_) {
350  this->current_delta_ = fabsf(value * this->delta_);
351  }
352  return this->last_value_ = value;
353  }
354  return {};
355 }
356 
357 // OrFilter
358 OrFilter::OrFilter(std::vector<Filter *> filters) : filters_(std::move(filters)), phi_(this) {}
359 OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {}
360 
362  if (!this->or_parent_->has_value_) {
363  this->or_parent_->output(value);
364  this->or_parent_->has_value_ = true;
365  }
366 
367  return {};
368 }
370  this->has_value_ = false;
371  for (Filter *filter : this->filters_)
372  filter->input(value);
373 
374  return {};
375 }
376 void OrFilter::initialize(Sensor *parent, Filter *next) {
377  Filter::initialize(parent, next);
378  for (Filter *filter : this->filters_) {
379  filter->initialize(parent, &this->phi_);
380  }
381  this->phi_.initialize(parent, nullptr);
382 }
383 
384 // TimeoutFilter
386  this->set_timeout("timeout", this->time_period_, [this]() { this->output(this->value_.value()); });
387  return value;
388 }
389 
391  : time_period_(time_period), value_(std::move(new_value)) {}
393 
394 // DebounceFilter
396  this->set_timeout("debounce", this->time_period_, [this, value]() { this->output(value); });
397 
398  return {};
399 }
400 
401 DebounceFilter::DebounceFilter(uint32_t time_period) : time_period_(time_period) {}
403 
404 // HeartbeatFilter
405 HeartbeatFilter::HeartbeatFilter(uint32_t time_period) : time_period_(time_period), last_input_(NAN) {}
406 
408  ESP_LOGVV(TAG, "HeartbeatFilter(%p)::new_value(value=%f)", this, value);
409  this->last_input_ = value;
410  this->has_value_ = true;
411 
412  return {};
413 }
415  this->set_interval("heartbeat", this->time_period_, [this]() {
416  ESP_LOGVV(TAG, "HeartbeatFilter(%p)::interval(has_value=%s, last_input=%f)", this, YESNO(this->has_value_),
417  this->last_input_);
418  if (!this->has_value_)
419  return;
420 
421  this->output(this->last_input_);
422  });
423 }
425 
427  for (std::array<float, 3> f : this->linear_functions_) {
428  if (!std::isfinite(f[2]) || value < f[2])
429  return (value * f[0]) + f[1];
430  }
431  return NAN;
432 }
433 
435  float res = 0.0f;
436  float x = 1.0f;
437  for (float coefficient : this->coefficients_) {
438  res += x * coefficient;
439  x *= value;
440  }
441  return res;
442 }
443 
444 ClampFilter::ClampFilter(float min, float max, bool ignore_out_of_range)
445  : min_(min), max_(max), ignore_out_of_range_(ignore_out_of_range) {}
447  if (std::isfinite(value)) {
448  if (std::isfinite(this->min_) && value < this->min_) {
449  if (this->ignore_out_of_range_) {
450  return {};
451  } else {
452  return this->min_;
453  }
454  }
455 
456  if (std::isfinite(this->max_) && value > this->max_) {
457  if (this->ignore_out_of_range_) {
458  return {};
459  } else {
460  return this->max_;
461  }
462  }
463  }
464  return value;
465 }
466 
467 RoundFilter::RoundFilter(uint8_t precision) : precision_(precision) {}
469  if (std::isfinite(value)) {
470  float accuracy_mult = powf(10.0f, this->precision_);
471  return roundf(accuracy_mult * value) / accuracy_mult;
472  }
473  return value;
474 }
475 
476 RoundMultipleFilter::RoundMultipleFilter(float multiple) : multiple_(multiple) {}
478  if (std::isfinite(value)) {
479  return value - remainderf(value, this->multiple_);
480  }
481  return value;
482 }
483 
484 } // namespace sensor
485 } // namespace esphome
optional< float > new_value(float value) override
Definition: filter.cpp:477
optional< float > new_value(float value) override
Definition: filter.cpp:194
lambda_filter_t lambda_filter_
Definition: filter.h:271
void set_quantile(float quantile)
Definition: filter.cpp:95
optional< float > new_value(float value) override
Definition: filter.cpp:434
void set_interval(const std::string &name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition: component.cpp:52
RoundFilter(uint8_t precision)
Definition: filter.cpp:467
MedianFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MedianFilter.
Definition: filter.cpp:35
void input(float value)
Definition: filter.cpp:13
const lambda_filter_t & get_lambda_filter() const
Definition: filter.cpp:281
std::deque< float > queue_
Definition: filter.h:71
DeltaFilter(float delta, bool percentage_mode)
Definition: filter.cpp:335
optional< float > new_value(float value) override
Definition: filter.cpp:39
PhiNode(OrFilter *or_parent)
Definition: filter.cpp:359
uint16_t x
Definition: tt21100.cpp:17
void set_window_size(size_t window_size)
Definition: filter.cpp:38
std::vector< Filter * > filters_
Definition: filter.h:389
optional< float > new_value(float value) override
Definition: filter.cpp:395
ThrottleFilter(uint32_t min_time_between_inputs)
Definition: filter.cpp:324
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:69
void set_send_every(size_t send_every)
Definition: filter.cpp:163
STL namespace.
std::deque< float > queue_
Definition: filter.h:174
TimeoutFilter(uint32_t time_period, TemplatableValue< float > new_value)
Definition: filter.cpp:390
void set_send_every(size_t send_every)
Definition: filter.cpp:93
MaxFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MaxFilter.
Definition: filter.cpp:161
void set_window_size(size_t window_size)
Definition: filter.cpp:164
void output(float value)
Definition: filter.cpp:19
bool has_value() const
Definition: optional.h:87
float get_setup_priority() const override
Definition: filter.cpp:424
optional< float > new_value(float value) override
Definition: filter.cpp:361
void set_send_every(size_t send_every)
Definition: filter.cpp:37
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
optional< float > new_value(float value) override
Definition: filter.cpp:304
optional< float > new_value(float value) override
Definition: filter.cpp:369
virtual optional< float > new_value(float value)=0
This will be called every time the filter receives a new value.
MultiplyFilter(TemplatableValue< float > multiplier)
Definition: filter.cpp:296
optional< float > new_value(float value) override
Definition: filter.cpp:293
OrFilter(std::vector< Filter *> filters)
Definition: filter.cpp:358
DebounceFilter(uint32_t time_period)
Definition: filter.cpp:401
void set_window_size(size_t window_size)
Definition: filter.cpp:136
optional< float > new_value(float value) override
Definition: filter.cpp:446
OffsetFilter(TemplatableValue< float > offset)
Definition: filter.cpp:291
optional< float > new_value(float value) override
Definition: filter.cpp:284
HeartbeatFilter(uint32_t time_period)
Definition: filter.cpp:405
float get_setup_priority() const override
Definition: filter.cpp:277
SkipInitialFilter(size_t num_to_ignore)
Construct a SkipInitialFilter.
Definition: filter.cpp:78
optional< float > new_value(float value) override
Definition: filter.cpp:337
ClampFilter(float min, float max, bool ignore_out_of_range)
Definition: filter.cpp:444
std::vector< TemplatableValue< float > > values_to_filter_out_
Definition: filter.h:303
ThrottleAverageFilter(uint32_t time_period)
Definition: filter.cpp:251
optional< float > new_value(float value) override
Definition: filter.cpp:385
virtual void initialize(Sensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
Definition: filter.cpp:28
void initialize(Sensor *parent, Filter *next) override
Definition: filter.cpp:376
optional< float > new_value(float value) override
Definition: filter.cpp:298
void set_lambda_filter(const lambda_filter_t &lambda_filter)
Definition: filter.cpp:282
TemplatableValue< float > offset_
Definition: filter.h:282
TemplatableValue< float > multiplier_
Definition: filter.h:292
optional< float > new_value(float value) override
Definition: filter.cpp:253
optional< float > new_value(float value) override
Definition: filter.cpp:325
ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
Definition: filter.cpp:225
optional< float > new_value(float value) override
Definition: filter.cpp:165
std::deque< float > queue_
Definition: filter.h:146
LambdaFilter(lambda_filter_t lambda_filter)
Definition: filter.cpp:280
void set_window_size(size_t window_size)
Definition: filter.cpp:94
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition: component.cpp:18
optional< float > new_value(float value) override
Definition: filter.cpp:137
std::function< optional< float >(float)> lambda_filter_t
Definition: filter.h:252
void internal_send_state_to_frontend(float state)
Definition: sensor.cpp:90
float get_setup_priority() const override
Definition: filter.cpp:392
void set_send_every(size_t send_every)
Definition: filter.cpp:135
std::deque< float > queue_
Definition: filter.h:100
optional< float > new_value(float value) override
Definition: filter.cpp:468
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
Definition: filter.cpp:91
Apply a filter to sensor values such as moving average.
Definition: filter.h:20
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
SlidingWindowMovingAverageFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a SlidingWindowMovingAverageFilter.
Definition: filter.cpp:189
MinFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MinFilter.
Definition: filter.cpp:133
int8_t get_accuracy_decimals()
Get the accuracy in decimals, using the manual override if set.
Definition: sensor.cpp:25
float get_setup_priority() const override
Definition: filter.cpp:402
float position
Definition: cover.h:14
optional< float > new_value(float value) override
Definition: filter.cpp:426
Base-class for all sensors.
Definition: sensor.h:57
optional< float > new_value(float value) override
Definition: filter.cpp:407
optional< float > new_value(float value) override
Definition: filter.cpp:96
FilterOutValueFilter(std::vector< TemplatableValue< float >> values_to_filter_out)
Definition: filter.cpp:301
optional< float > new_value(float value) override
Definition: filter.cpp:79
esphome::sensor::Sensor * sensor
Definition: statsd.h:38
optional< float > new_value(float value) override
Definition: filter.cpp:227