ESPHome 2025.5.0
Loading...
Searching...
No Matches
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
7namespace esphome {
8namespace sensor {
9
10static const char *const TAG = "sensor.filter";
11
12// Filter
13void 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}
19void 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}
28void 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
35MedianFilter::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) {}
37void MedianFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
38void 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
78SkipInitialFilter::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
91QuantileFilter::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) {}
93void QuantileFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
94void QuantileFilter::set_window_size(size_t window_size) { this->window_size_ = window_size; }
95void 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
133MinFilter::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) {}
135void MinFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
136void 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
161MaxFilter::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) {}
163void MaxFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
164void 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) {}
192void SlidingWindowMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
193void 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
225ExponentialMovingAverageFilter::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}
247void ExponentialMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
248void ExponentialMovingAverageFilter::set_alpha(float alpha) { this->alpha_ = alpha; }
249
250// ThrottleAverageFilter
251ThrottleAverageFilter::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
280LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::move(lambda_filter)) {}
282void 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
291OffsetFilter::OffsetFilter(TemplatableValue<float> offset) : offset_(std::move(offset)) {}
292
293optional<float> OffsetFilter::new_value(float value) { return value + this->offset_.value(); }
294
295// MultiplyFilter
296MultiplyFilter::MultiplyFilter(TemplatableValue<float> multiplier) : multiplier_(std::move(multiplier)) {}
297
298optional<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
324ThrottleFilter::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
335DeltaFilter::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
358OrFilter::OrFilter(std::vector<Filter *> filters) : filters_(std::move(filters)), phi_(this) {}
359OrFilter::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}
376void 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
401DebounceFilter::DebounceFilter(uint32_t time_period) : time_period_(time_period) {}
403
404// HeartbeatFilter
405HeartbeatFilter::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
444ClampFilter::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
467RoundFilter::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
476RoundMultipleFilter::RoundMultipleFilter(float multiple) : multiple_(multiple) {}
478 if (std::isfinite(value)) {
479 return value - remainderf(value, this->multiple_);
480 }
481 return value;
482}
483
485 if (!std::isfinite(value)) {
486 return NAN;
487 }
488 double k = 273.15;
489 // https://de.wikipedia.org/wiki/Steinhart-Hart-Gleichung#cite_note-stein2_s4-3
490 double t = value + k;
491 double y = (this->a_ - 1 / (t)) / (2 * this->c_);
492 double x = sqrt(pow(this->b_ / (3 * this->c_), 3) + y * y);
493 double resistance = exp(pow(x - y, 1 / 3.0) - pow(x + y, 1 / 3.0));
494 return resistance;
495}
496
498 if (!std::isfinite(value)) {
499 return NAN;
500 }
501 double lr = log(double(value));
502 double v = this->a_ + this->b_ * lr + this->c_ * lr * lr * lr;
503 double temp = float(1.0 / v - 273.15);
504 return temp;
505}
506
507} // namespace sensor
508} // namespace esphome
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:55
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:72
bool has_value() const
Definition optional.h:87
optional< float > new_value(float value) override
Definition filter.cpp:426
std::vector< std::array< float, 3 > > linear_functions_
Definition filter.h:401
optional< float > new_value(float value) override
Definition filter.cpp:434
ClampFilter(float min, float max, bool ignore_out_of_range)
Definition filter.cpp:444
optional< float > new_value(float value) override
Definition filter.cpp:446
optional< float > new_value(float value) override
Definition filter.cpp:395
float get_setup_priority() const override
Definition filter.cpp:402
DebounceFilter(uint32_t time_period)
Definition filter.cpp:401
DeltaFilter(float delta, bool percentage_mode)
Definition filter.cpp:335
optional< float > new_value(float value) override
Definition filter.cpp:337
optional< float > new_value(float value) override
Definition filter.cpp:227
ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
Definition filter.cpp:225
Apply a filter to sensor values such as moving average.
Definition filter.h:20
virtual optional< float > new_value(float value)=0
This will be called every time the filter receives a new value.
void output(float value)
Definition filter.cpp:19
virtual void initialize(Sensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
Definition filter.cpp:28
void input(float value)
Definition filter.cpp:13
std::vector< TemplatableValue< float > > values_to_filter_out_
Definition filter.h:303
FilterOutValueFilter(std::vector< TemplatableValue< float > > values_to_filter_out)
Definition filter.cpp:301
optional< float > new_value(float value) override
Definition filter.cpp:304
HeartbeatFilter(uint32_t time_period)
Definition filter.cpp:405
optional< float > new_value(float value) override
Definition filter.cpp:407
float get_setup_priority() const override
Definition filter.cpp:424
const lambda_filter_t & get_lambda_filter() const
Definition filter.cpp:281
LambdaFilter(lambda_filter_t lambda_filter)
Definition filter.cpp:280
lambda_filter_t lambda_filter_
Definition filter.h:271
void set_lambda_filter(const lambda_filter_t &lambda_filter)
Definition filter.cpp:282
optional< float > new_value(float value) override
Definition filter.cpp:284
void set_send_every(size_t send_every)
Definition filter.cpp:163
void set_window_size(size_t window_size)
Definition filter.cpp:164
std::deque< float > queue_
Definition filter.h:174
optional< float > new_value(float value) override
Definition filter.cpp:165
MaxFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MaxFilter.
Definition filter.cpp:161
void set_send_every(size_t send_every)
Definition filter.cpp:37
void set_window_size(size_t window_size)
Definition filter.cpp:38
MedianFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MedianFilter.
Definition filter.cpp:35
optional< float > new_value(float value) override
Definition filter.cpp:39
std::deque< float > queue_
Definition filter.h:100
void set_window_size(size_t window_size)
Definition filter.cpp:136
void set_send_every(size_t send_every)
Definition filter.cpp:135
MinFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a MinFilter.
Definition filter.cpp:133
std::deque< float > queue_
Definition filter.h:146
optional< float > new_value(float value) override
Definition filter.cpp:137
optional< float > new_value(float value) override
Definition filter.cpp:298
MultiplyFilter(TemplatableValue< float > multiplier)
Definition filter.cpp:296
TemplatableValue< float > multiplier_
Definition filter.h:292
optional< float > new_value(float value) override
Definition filter.cpp:293
OffsetFilter(TemplatableValue< float > offset)
Definition filter.cpp:291
TemplatableValue< float > offset_
Definition filter.h:282
optional< float > new_value(float value) override
Definition filter.cpp:361
PhiNode(OrFilter *or_parent)
Definition filter.cpp:359
std::vector< Filter * > filters_
Definition filter.h:389
optional< float > new_value(float value) override
Definition filter.cpp:369
void initialize(Sensor *parent, Filter *next) override
Definition filter.cpp:376
OrFilter(std::vector< Filter * > filters)
Definition filter.cpp:358
void set_window_size(size_t window_size)
Definition filter.cpp:94
void set_send_every(size_t send_every)
Definition filter.cpp:93
std::deque< float > queue_
Definition filter.h:71
void set_quantile(float quantile)
Definition filter.cpp:95
optional< float > new_value(float value) override
Definition filter.cpp:96
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
Definition filter.cpp:91
RoundFilter(uint8_t precision)
Definition filter.cpp:467
optional< float > new_value(float value) override
Definition filter.cpp:468
optional< float > new_value(float value) override
Definition filter.cpp:477
Base-class for all sensors.
Definition sensor.h:57
void internal_send_state_to_frontend(float state)
Definition sensor.cpp:90
int8_t get_accuracy_decimals()
Get the accuracy in decimals, using the manual override if set.
Definition sensor.cpp:25
SkipInitialFilter(size_t num_to_ignore)
Construct a SkipInitialFilter.
Definition filter.cpp:78
optional< float > new_value(float value) override
Definition filter.cpp:79
optional< float > new_value(float value) override
Definition filter.cpp:194
SlidingWindowMovingAverageFilter(size_t window_size, size_t send_every, size_t send_first_at)
Construct a SlidingWindowMovingAverageFilter.
Definition filter.cpp:189
optional< float > new_value(float value) override
Definition filter.cpp:253
ThrottleAverageFilter(uint32_t time_period)
Definition filter.cpp:251
float get_setup_priority() const override
Definition filter.cpp:277
ThrottleFilter(uint32_t min_time_between_inputs)
Definition filter.cpp:324
optional< float > new_value(float value) override
Definition filter.cpp:325
optional< float > new_value(float value) override
Definition filter.cpp:385
float get_setup_priority() const override
Definition filter.cpp:392
TimeoutFilter(uint32_t time_period, TemplatableValue< float > new_value)
Definition filter.cpp:390
optional< float > new_value(float value) override
Definition filter.cpp:484
optional< float > new_value(float value) override
Definition filter.cpp:497
float position
Definition cover.h:0
std::function< optional< float >(float)> lambda_filter_t
Definition filter.h:252
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.cpp:18
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6