ESPHome  2023.3.1
filter.cpp
Go to the documentation of this file.
1 #include "filter.h"
2 #include "esphome/core/hal.h"
3 #include "esphome/core/log.h"
4 #include "sensor.h"
5 #include <cmath>
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 // QuantileFilter
78 QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
79  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size), quantile_(quantile) {}
80 void QuantileFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
81 void QuantileFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
82 void QuantileFilter::set_quantile(float quantile) { this->quantile_ = quantile; }
84  while (this->queue_.size() >= this->window_size_) {
85  this->queue_.pop_front();
86  }
87  this->queue_.push_back(value);
88  ESP_LOGVV(TAG, "QuantileFilter(%p)::new_value(%f), quantile:%f", this, value, this->quantile_);
89 
90  if (++this->send_at_ >= this->send_every_) {
91  this->send_at_ = 0;
92 
93  float result = NAN;
94  if (!this->queue_.empty()) {
95  // Copy queue without NaN values
96  std::vector<float> quantile_queue;
97  for (auto v : this->queue_) {
98  if (!std::isnan(v)) {
99  quantile_queue.push_back(v);
100  }
101  }
102 
103  sort(quantile_queue.begin(), quantile_queue.end());
104 
105  size_t queue_size = quantile_queue.size();
106  if (queue_size) {
107  size_t position = ceilf(queue_size * this->quantile_) - 1;
108  ESP_LOGVV(TAG, "QuantileFilter(%p)::position: %d/%d", this, position + 1, queue_size);
109  result = quantile_queue[position];
110  }
111  }
112 
113  ESP_LOGVV(TAG, "QuantileFilter(%p)::new_value(%f) SENDING %f", this, value, result);
114  return result;
115  }
116  return {};
117 }
118 
119 // MinFilter
120 MinFilter::MinFilter(size_t window_size, size_t send_every, size_t send_first_at)
121  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
122 void MinFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
123 void MinFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
125  while (this->queue_.size() >= this->window_size_) {
126  this->queue_.pop_front();
127  }
128  this->queue_.push_back(value);
129  ESP_LOGVV(TAG, "MinFilter(%p)::new_value(%f)", this, value);
130 
131  if (++this->send_at_ >= this->send_every_) {
132  this->send_at_ = 0;
133 
134  float min = NAN;
135  for (auto v : this->queue_) {
136  if (!std::isnan(v)) {
137  min = std::isnan(min) ? v : std::min(min, v);
138  }
139  }
140 
141  ESP_LOGVV(TAG, "MinFilter(%p)::new_value(%f) SENDING %f", this, value, min);
142  return min;
143  }
144  return {};
145 }
146 
147 // MaxFilter
148 MaxFilter::MaxFilter(size_t window_size, size_t send_every, size_t send_first_at)
149  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
150 void MaxFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
151 void MaxFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
153  while (this->queue_.size() >= this->window_size_) {
154  this->queue_.pop_front();
155  }
156  this->queue_.push_back(value);
157  ESP_LOGVV(TAG, "MaxFilter(%p)::new_value(%f)", this, value);
158 
159  if (++this->send_at_ >= this->send_every_) {
160  this->send_at_ = 0;
161 
162  float max = NAN;
163  for (auto v : this->queue_) {
164  if (!std::isnan(v)) {
165  max = std::isnan(max) ? v : std::max(max, v);
166  }
167  }
168 
169  ESP_LOGVV(TAG, "MaxFilter(%p)::new_value(%f) SENDING %f", this, value, max);
170  return max;
171  }
172  return {};
173 }
174 
175 // SlidingWindowMovingAverageFilter
177  size_t send_first_at)
178  : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size) {}
179 void SlidingWindowMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
180 void SlidingWindowMovingAverageFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
182  while (this->queue_.size() >= this->window_size_) {
183  this->queue_.pop_front();
184  }
185  this->queue_.push_back(value);
186  ESP_LOGVV(TAG, "SlidingWindowMovingAverageFilter(%p)::new_value(%f)", this, value);
187 
188  if (++this->send_at_ >= this->send_every_) {
189  this->send_at_ = 0;
190 
191  float sum = 0;
192  size_t valid_count = 0;
193  for (auto v : this->queue_) {
194  if (!std::isnan(v)) {
195  sum += v;
196  valid_count++;
197  }
198  }
199 
200  float average = NAN;
201  if (valid_count) {
202  average = sum / valid_count;
203  }
204 
205  ESP_LOGVV(TAG, "SlidingWindowMovingAverageFilter(%p)::new_value(%f) SENDING %f", this, value, average);
206  return average;
207  }
208  return {};
209 }
210 
211 // ExponentialMovingAverageFilter
212 ExponentialMovingAverageFilter::ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
213  : send_every_(send_every), send_at_(send_every - send_first_at), alpha_(alpha) {}
215  if (!std::isnan(value)) {
216  if (this->first_value_) {
217  this->accumulator_ = value;
218  this->first_value_ = false;
219  } else {
220  this->accumulator_ = (this->alpha_ * value) + (1.0f - this->alpha_) * this->accumulator_;
221  }
222  }
223 
224  const float average = std::isnan(value) ? value : this->accumulator_;
225  ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) -> %f", this, value, average);
226 
227  if (++this->send_at_ >= this->send_every_) {
228  ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) SENDING %f", this, value, average);
229  this->send_at_ = 0;
230  return average;
231  }
232  return {};
233 }
234 void ExponentialMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
235 void ExponentialMovingAverageFilter::set_alpha(float alpha) { this->alpha_ = alpha; }
236 
237 // ThrottleAverageFilter
238 ThrottleAverageFilter::ThrottleAverageFilter(uint32_t time_period) : time_period_(time_period) {}
239 
241  ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value);
242  if (!std::isnan(value)) {
243  this->sum_ += value;
244  this->n_++;
245  }
246  return {};
247 }
249  this->set_interval("throttle_average", this->time_period_, [this]() {
250  ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_);
251  if (this->n_ == 0) {
252  this->output(NAN);
253  } else {
254  this->output(this->sum_ / this->n_);
255  this->sum_ = 0.0f;
256  this->n_ = 0;
257  }
258  });
259 }
261 
262 // LambdaFilter
263 LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::move(lambda_filter)) {}
265 void LambdaFilter::set_lambda_filter(const lambda_filter_t &lambda_filter) { this->lambda_filter_ = lambda_filter; }
266 
268  auto it = this->lambda_filter_(value);
269  ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%f) -> %f", this, value, it.value_or(INFINITY));
270  return it;
271 }
272 
273 // OffsetFilter
274 OffsetFilter::OffsetFilter(float offset) : offset_(offset) {}
275 
276 optional<float> OffsetFilter::new_value(float value) { return value + this->offset_; }
277 
278 // MultiplyFilter
279 MultiplyFilter::MultiplyFilter(float multiplier) : multiplier_(multiplier) {}
280 
281 optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_; }
282 
283 // FilterOutValueFilter
284 FilterOutValueFilter::FilterOutValueFilter(float value_to_filter_out) : value_to_filter_out_(value_to_filter_out) {}
285 
287  if (std::isnan(this->value_to_filter_out_)) {
288  if (std::isnan(value)) {
289  return {};
290  } else {
291  return value;
292  }
293  } else {
294  int8_t accuracy = this->parent_->get_accuracy_decimals();
295  float accuracy_mult = powf(10.0f, accuracy);
296  float rounded_filter_out = roundf(accuracy_mult * this->value_to_filter_out_);
297  float rounded_value = roundf(accuracy_mult * value);
298  if (rounded_filter_out == rounded_value) {
299  return {};
300  } else {
301  return value;
302  }
303  }
304 }
305 
306 // ThrottleFilter
307 ThrottleFilter::ThrottleFilter(uint32_t min_time_between_inputs) : min_time_between_inputs_(min_time_between_inputs) {}
309  const uint32_t now = millis();
310  if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_) {
311  this->last_input_ = now;
312  return value;
313  }
314  return {};
315 }
316 
317 // DeltaFilter
318 DeltaFilter::DeltaFilter(float min_delta) : min_delta_(min_delta), last_value_(NAN) {}
320  if (std::isnan(value)) {
321  if (std::isnan(this->last_value_)) {
322  return {};
323  } else {
324  return this->last_value_ = value;
325  }
326  }
327  if (std::isnan(this->last_value_)) {
328  return this->last_value_ = value;
329  }
330  if (fabsf(value - this->last_value_) >= this->min_delta_) {
331  return this->last_value_ = value;
332  }
333  return {};
334 }
335 
336 // OrFilter
337 OrFilter::OrFilter(std::vector<Filter *> filters) : filters_(std::move(filters)), phi_(this) {}
338 OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {}
339 
341  this->or_parent_->output(value);
342 
343  return {};
344 }
346  for (Filter *filter : this->filters_)
347  filter->input(value);
348 
349  return {};
350 }
351 void OrFilter::initialize(Sensor *parent, Filter *next) {
352  Filter::initialize(parent, next);
353  for (Filter *filter : this->filters_) {
354  filter->initialize(parent, &this->phi_);
355  }
356  this->phi_.initialize(parent, nullptr);
357 }
358 
359 // DebounceFilter
361  this->set_timeout("debounce", this->time_period_, [this, value]() { this->output(value); });
362 
363  return {};
364 }
365 
366 DebounceFilter::DebounceFilter(uint32_t time_period) : time_period_(time_period) {}
368 
369 // HeartbeatFilter
370 HeartbeatFilter::HeartbeatFilter(uint32_t time_period) : time_period_(time_period), last_input_(NAN) {}
371 
373  ESP_LOGVV(TAG, "HeartbeatFilter(%p)::new_value(value=%f)", this, value);
374  this->last_input_ = value;
375  this->has_value_ = true;
376 
377  return {};
378 }
380  this->set_interval("heartbeat", this->time_period_, [this]() {
381  ESP_LOGVV(TAG, "HeartbeatFilter(%p)::interval(has_value=%s, last_input=%f)", this, YESNO(this->has_value_),
382  this->last_input_);
383  if (!this->has_value_)
384  return;
385 
386  this->output(this->last_input_);
387  });
388 }
390 
391 optional<float> CalibrateLinearFilter::new_value(float value) { return value * this->slope_ + this->bias_; }
392 CalibrateLinearFilter::CalibrateLinearFilter(float slope, float bias) : slope_(slope), bias_(bias) {}
393 
395  float res = 0.0f;
396  float x = 1.0f;
397  for (float coefficient : this->coefficients_) {
398  res += x * coefficient;
399  x *= value;
400  }
401  return res;
402 }
403 
404 } // namespace sensor
405 } // namespace esphome
MultiplyFilter(float multiplier)
Definition: filter.cpp:279
optional< float > new_value(float value) override
Definition: filter.cpp:181
lambda_filter_t lambda_filter_
Definition: filter.h:251
void set_quantile(float quantile)
Definition: filter.cpp:82
optional< float > new_value(float value) override
Definition: filter.cpp:394
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:51
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:264
std::deque< float > queue_
Definition: filter.h:70
optional< float > new_value(float value) override
Definition: filter.cpp:39
PhiNode(OrFilter *or_parent)
Definition: filter.cpp:338
void set_window_size(size_t window_size)
Definition: filter.cpp:38
std::vector< Filter * > filters_
Definition: filter.h:355
optional< float > new_value(float value) override
Definition: filter.cpp:360
ThrottleFilter(uint32_t min_time_between_inputs)
Definition: filter.cpp:307
void set_send_every(size_t send_every)
Definition: filter.cpp:150
STL namespace.
std::deque< float > queue_
Definition: filter.h:155
void set_send_every(size_t send_every)
Definition: filter.cpp:80
MaxFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MaxFilter.
Definition: filter.cpp:148
void set_window_size(size_t window_size)
Definition: filter.cpp:151
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:389
optional< float > new_value(float value) override
Definition: filter.cpp:340
void set_send_every(size_t send_every)
Definition: filter.cpp:37
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
optional< float > new_value(float value) override
Definition: filter.cpp:286
optional< float > new_value(float value) override
Definition: filter.cpp:345
virtual optional< float > new_value(float value)=0
This will be called every time the filter receives a new value.
optional< float > new_value(float value) override
Definition: filter.cpp:276
OrFilter(std::vector< Filter *> filters)
Definition: filter.cpp:337
DebounceFilter(uint32_t time_period)
Definition: filter.cpp:366
void set_window_size(size_t window_size)
Definition: filter.cpp:123
optional< float > new_value(float value) override
Definition: filter.cpp:267
HeartbeatFilter(uint32_t time_period)
Definition: filter.cpp:370
float get_setup_priority() const override
Definition: filter.cpp:260
optional< float > new_value(float value) override
Definition: filter.cpp:319
OffsetFilter(float offset)
Definition: filter.cpp:274
ThrottleAverageFilter(uint32_t time_period)
Definition: filter.cpp:238
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:351
optional< float > new_value(float value) override
Definition: filter.cpp:281
void set_lambda_filter(const lambda_filter_t &lambda_filter)
Definition: filter.cpp:265
optional< float > new_value(float value) override
Definition: filter.cpp:240
optional< float > new_value(float value) override
Definition: filter.cpp:308
ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
Definition: filter.cpp:212
optional< float > new_value(float value) override
Definition: filter.cpp:152
std::deque< float > queue_
Definition: filter.h:127
LambdaFilter(lambda_filter_t lambda_filter)
Definition: filter.cpp:263
void set_window_size(size_t window_size)
Definition: filter.cpp:81
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition: component.cpp:17
optional< float > new_value(float value) override
Definition: filter.cpp:124
std::function< optional< float >(float)> lambda_filter_t
Definition: filter.h:232
void internal_send_state_to_frontend(float state)
Definition: sensor.cpp:123
void set_send_every(size_t send_every)
Definition: filter.cpp:122
std::deque< float > queue_
Definition: filter.h:99
DeltaFilter(float min_delta)
Definition: filter.cpp:318
FilterOutValueFilter(float value_to_filter_out)
Definition: filter.cpp:284
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
Definition: filter.cpp:78
Apply a filter to sensor values such as moving average.
Definition: filter.h:19
Definition: a4988.cpp:4
SlidingWindowMovingAverageFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a SlidingWindowMovingAverageFilter.
Definition: filter.cpp:176
MinFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MinFilter.
Definition: filter.cpp:120
int8_t get_accuracy_decimals()
Get the accuracy in decimals, using the manual override if set.
Definition: sensor.cpp:39
float get_setup_priority() const override
Definition: filter.cpp:367
float position
Definition: cover.h:14
optional< float > new_value(float value) override
Definition: filter.cpp:391
CalibrateLinearFilter(float slope, float bias)
Definition: filter.cpp:392
Base-class for all sensors.
Definition: sensor.h:57
optional< float > new_value(float value) override
Definition: filter.cpp:372
optional< float > new_value(float value) override
Definition: filter.cpp:83
optional< float > new_value(float value) override
Definition: filter.cpp:214