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