ESPHome 2026.2.4
Loading...
Searching...
No Matches
filter.cpp
Go to the documentation of this file.
1#include "filter.h"
2#include <cmath>
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6#include "sensor.h"
7
8namespace esphome::sensor {
9
10static const char *const TAG = "sensor.filter";
11
12// Filter scheduler IDs.
13// Each filter is its own Component instance, so the scheduler scopes
14// IDs by component pointer — no risk of collisions between instances.
15constexpr uint32_t FILTER_ID = 0;
16
17// Filter
18void Filter::input(float value) {
19 ESP_LOGVV(TAG, "Filter(%p)::input(%f)", this, value);
20 optional<float> out = this->new_value(value);
21 if (out.has_value())
22 this->output(*out);
23}
24void Filter::output(float value) {
25 if (this->next_ == nullptr) {
26 ESP_LOGVV(TAG, "Filter(%p)::output(%f) -> SENSOR", this, value);
28 } else {
29 ESP_LOGVV(TAG, "Filter(%p)::output(%f) -> %p", this, value, this->next_);
30 this->next_->input(value);
31 }
32}
33void Filter::initialize(Sensor *parent, Filter *next) {
34 ESP_LOGVV(TAG, "Filter(%p)::initialize(parent=%p next=%p)", this, parent, next);
35 this->parent_ = parent;
36 this->next_ = next;
37}
38
39// SlidingWindowFilter
40SlidingWindowFilter::SlidingWindowFilter(size_t window_size, size_t send_every, size_t send_first_at)
41 : window_size_(window_size), send_every_(send_every), send_at_(send_every - send_first_at) {
42 // Allocate ring buffer once at initialization
43 this->window_.init(window_size);
44}
45
47 // Add value to ring buffer
49 // Buffer not yet full - just append
50 this->window_.push_back(value);
51 this->window_count_++;
52 } else {
53 // Buffer full - overwrite oldest value (ring buffer)
54 this->window_[this->window_head_] = value;
55 this->window_head_++;
56 if (this->window_head_ >= this->window_size_) {
57 this->window_head_ = 0;
58 }
59 }
60
61 // Check if we should send a result
62 if (++this->send_at_ >= this->send_every_) {
63 this->send_at_ = 0;
64 float result = this->compute_result();
65 ESP_LOGVV(TAG, "SlidingWindowFilter(%p)::new_value(%f) SENDING %f", this, value, result);
66 return result;
67 }
68 return {};
69}
70
71// SortedWindowFilter
73 // Copy window without NaN values using FixedVector (no heap allocation)
74 // Returns unsorted values - caller will use std::nth_element for partial sorting as needed
75 FixedVector<float> values;
76 values.init(this->window_count_);
77 for (size_t i = 0; i < this->window_count_; i++) {
78 float v = this->window_[i];
79 if (!std::isnan(v)) {
80 values.push_back(v);
81 }
82 }
83 return values;
84}
85
86// MedianFilter
89 if (values.empty())
90 return NAN;
91
92 size_t size = values.size();
93 size_t mid = size / 2;
94
95 if (size % 2) {
96 // Odd number of elements - use nth_element to find middle element
97 std::nth_element(values.begin(), values.begin() + mid, values.end());
98 return values[mid];
99 }
100 // Even number of elements - need both middle elements
101 // Use nth_element to find upper middle element
102 std::nth_element(values.begin(), values.begin() + mid, values.end());
103 float upper = values[mid];
104 // Find the maximum of the lower half (which is now everything before mid)
105 float lower = *std::max_element(values.begin(), values.begin() + mid);
106 return (lower + upper) / 2.0f;
107}
108
109// SkipInitialFilter
110SkipInitialFilter::SkipInitialFilter(size_t num_to_ignore) : num_to_ignore_(num_to_ignore) {}
112 if (num_to_ignore_ > 0) {
114 ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %zu left", this, value, num_to_ignore_);
115 return {};
116 }
117
118 ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SENDING", this, value);
119 return value;
120}
121
122// QuantileFilter
123QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
124 : SortedWindowFilter(window_size, send_every, send_first_at), quantile_(quantile) {}
125
127 FixedVector<float> values = this->get_window_values_();
128 if (values.empty())
129 return NAN;
130
131 size_t position = ceilf(values.size() * this->quantile_) - 1;
132 ESP_LOGVV(TAG, "QuantileFilter(%p)::position: %zu/%zu", this, position + 1, values.size());
133
134 // Use nth_element to find the quantile element (O(n) instead of O(n log n))
135 std::nth_element(values.begin(), values.begin() + position, values.end());
136 return values[position];
137}
138
139// MinFilter
141
142// MaxFilter
144
145// SlidingWindowMovingAverageFilter
147 float sum = 0;
148 size_t valid_count = 0;
149 for (size_t i = 0; i < this->window_count_; i++) {
150 float v = this->window_[i];
151 if (!std::isnan(v)) {
152 sum += v;
153 valid_count++;
154 }
155 }
156 return valid_count ? sum / valid_count : NAN;
157}
158
159// ExponentialMovingAverageFilter
160ExponentialMovingAverageFilter::ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
161 : alpha_(alpha), send_every_(send_every), send_at_(send_every - send_first_at) {}
163 if (!std::isnan(value)) {
164 if (this->first_value_) {
165 this->accumulator_ = value;
166 this->first_value_ = false;
167 } else {
168 this->accumulator_ = (this->alpha_ * value) + (1.0f - this->alpha_) * this->accumulator_;
169 }
170 }
171
172 const float average = std::isnan(value) ? value : this->accumulator_;
173 ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) -> %f", this, value, average);
174
175 if (++this->send_at_ >= this->send_every_) {
176 ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) SENDING %f", this, value, average);
177 this->send_at_ = 0;
178 return average;
179 }
180 return {};
181}
182void ExponentialMovingAverageFilter::set_send_every(size_t send_every) { this->send_every_ = send_every; }
183void ExponentialMovingAverageFilter::set_alpha(float alpha) { this->alpha_ = alpha; }
184
185// ThrottleAverageFilter
186ThrottleAverageFilter::ThrottleAverageFilter(uint32_t time_period) : time_period_(time_period) {}
187
189 ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value);
190 if (std::isnan(value)) {
191 this->have_nan_ = true;
192 } else {
193 this->sum_ += value;
194 this->n_++;
195 }
196 return {};
197}
199 this->set_interval(FILTER_ID, this->time_period_, [this]() {
200 ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_);
201 if (this->n_ == 0) {
202 if (this->have_nan_)
203 this->output(NAN);
204 } else {
205 this->output(this->sum_ / this->n_);
206 this->sum_ = 0.0f;
207 this->n_ = 0;
208 }
209 this->have_nan_ = false;
210 });
211}
213
214// LambdaFilter
215LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::move(lambda_filter)) {}
217void LambdaFilter::set_lambda_filter(const lambda_filter_t &lambda_filter) { this->lambda_filter_ = lambda_filter; }
218
220 auto it = this->lambda_filter_(value);
221 ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%f) -> %f", this, value, it.value_or(INFINITY));
222 return it;
223}
224
225// OffsetFilter
226OffsetFilter::OffsetFilter(TemplatableValue<float> offset) : offset_(std::move(offset)) {}
227
228optional<float> OffsetFilter::new_value(float value) { return value + this->offset_.value(); }
229
230// MultiplyFilter
231MultiplyFilter::MultiplyFilter(TemplatableValue<float> multiplier) : multiplier_(std::move(multiplier)) {}
232
233optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_.value(); }
234
235// ValueListFilter (base class)
236ValueListFilter::ValueListFilter(std::initializer_list<TemplatableValue<float>> values) : values_(values) {}
237
238bool ValueListFilter::value_matches_any_(float sensor_value) {
239 int8_t accuracy = this->parent_->get_accuracy_decimals();
240 float accuracy_mult = powf(10.0f, accuracy);
241 float rounded_sensor = roundf(accuracy_mult * sensor_value);
242
243 for (auto &filter_value : this->values_) {
244 float fv = filter_value.value();
245
246 // Handle NaN comparison
247 if (std::isnan(fv)) {
248 if (std::isnan(sensor_value))
249 return true;
250 continue;
251 }
252
253 // Compare rounded values
254 if (roundf(accuracy_mult * fv) == rounded_sensor)
255 return true;
256 }
257
258 return false;
259}
260
261// FilterOutValueFilter
262FilterOutValueFilter::FilterOutValueFilter(std::initializer_list<TemplatableValue<float>> values_to_filter_out)
263 : ValueListFilter(values_to_filter_out) {}
264
266 if (this->value_matches_any_(value))
267 return {}; // Filter out
268 return value; // Pass through
269}
270
271// ThrottleFilter
272ThrottleFilter::ThrottleFilter(uint32_t min_time_between_inputs) : min_time_between_inputs_(min_time_between_inputs) {}
274 const uint32_t now = App.get_loop_component_start_time();
275 if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_) {
276 this->last_input_ = now;
277 return value;
278 }
279 return {};
280}
281
282// ThrottleWithPriorityFilter
284 uint32_t min_time_between_inputs, std::initializer_list<TemplatableValue<float>> prioritized_values)
285 : ValueListFilter(prioritized_values), min_time_between_inputs_(min_time_between_inputs) {}
286
288 const uint32_t now = App.get_loop_component_start_time();
289 // Allow value through if: no previous input, time expired, or is prioritized
290 if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_ ||
291 this->value_matches_any_(value)) {
292 this->last_input_ = now;
293 return value;
294 }
295 return {};
296}
297
298// DeltaFilter
299DeltaFilter::DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1)
300 : min_a0_(min_a0), min_a1_(min_a1), max_a0_(max_a0), max_a1_(max_a1) {}
301
302void DeltaFilter::set_baseline(float (*fn)(float)) { this->baseline_ = fn; }
303
305 // Always yield the first value.
306 if (std::isnan(this->last_value_)) {
307 this->last_value_ = value;
308 return value;
309 }
310 // calculate min and max using the linear equation
311 float ref = this->baseline_(this->last_value_);
312 float min = fabsf(this->min_a0_ + ref * this->min_a1_);
313 float max = fabsf(this->max_a0_ + ref * this->max_a1_);
314 float delta = fabsf(value - ref);
315 // if there is no reference, e.g. for the first value, just accept this one,
316 // otherwise accept only if within range.
317 if (delta > min && delta <= max) {
318 this->last_value_ = value;
319 return value;
320 }
321 return {};
322}
323
324// OrFilter
325OrFilter::OrFilter(std::initializer_list<Filter *> filters) : filters_(filters), phi_(this) {}
326OrFilter::PhiNode::PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {}
327
329 if (!this->or_parent_->has_value_) {
330 this->or_parent_->output(value);
331 this->or_parent_->has_value_ = true;
332 }
333
334 return {};
335}
337 this->has_value_ = false;
338 for (auto *filter : this->filters_)
339 filter->input(value);
340
341 return {};
342}
343void OrFilter::initialize(Sensor *parent, Filter *next) {
344 Filter::initialize(parent, next);
345 for (auto *filter : this->filters_) {
346 filter->initialize(parent, &this->phi_);
347 }
348 this->phi_.initialize(parent, nullptr);
349}
350
351// TimeoutFilterBase - shared loop logic
353 // Check if timeout period has elapsed
354 // Use cached loop start time to avoid repeated millis() calls
355 const uint32_t now = App.get_loop_component_start_time();
356 if (now - this->timeout_start_time_ >= this->time_period_) {
357 // Timeout fired - get output value from derived class and output it
358 this->output(this->get_output_value());
359
360 // Disable loop until next value arrives
361 this->disable_loop();
362 }
363}
364
366
367// TimeoutFilterLast - "last" mode implementation
369 // Store the value to output when timeout fires
370 this->pending_value_ = value;
371
372 // Record when timeout started and enable loop
373 this->timeout_start_time_ = millis();
374 this->enable_loop();
375
376 return value;
377}
378
379// TimeoutFilterConfigured - configured value mode implementation
381 // Record when timeout started and enable loop
382 // Note: we don't store the incoming value since we have a configured value
383 this->timeout_start_time_ = millis();
384 this->enable_loop();
385
386 return value;
387}
388
389// DebounceFilter
391 this->set_timeout(FILTER_ID, this->time_period_, [this, value]() { this->output(value); });
392
393 return {};
394}
395
396DebounceFilter::DebounceFilter(uint32_t time_period) : time_period_(time_period) {}
398
399// HeartbeatFilter
400HeartbeatFilter::HeartbeatFilter(uint32_t time_period) : time_period_(time_period), last_input_(NAN) {}
401
403 ESP_LOGVV(TAG, "HeartbeatFilter(%p)::new_value(value=%f)", this, value);
404 this->last_input_ = value;
405 this->has_value_ = true;
406
407 if (this->optimistic_) {
408 return value;
409 }
410 return {};
411}
412
414 this->set_interval(FILTER_ID, this->time_period_, [this]() {
415 ESP_LOGVV(TAG, "HeartbeatFilter(%p)::interval(has_value=%s, last_input=%f)", this, YESNO(this->has_value_),
416 this->last_input_);
417 if (!this->has_value_)
418 return;
419
420 this->output(this->last_input_);
421 });
422}
423
425
426CalibrateLinearFilter::CalibrateLinearFilter(std::initializer_list<std::array<float, 3>> linear_functions)
427 : linear_functions_(linear_functions) {}
428
430 for (const auto &f : this->linear_functions_) {
431 if (!std::isfinite(f[2]) || value < f[2])
432 return (value * f[0]) + f[1];
433 }
434 return NAN;
435}
436
437CalibratePolynomialFilter::CalibratePolynomialFilter(std::initializer_list<float> coefficients)
438 : coefficients_(coefficients) {}
439
441 float res = 0.0f;
442 float x = 1.0f;
443 for (const auto &coefficient : this->coefficients_) {
444 res += x * coefficient;
445 x *= value;
446 }
447 return res;
448}
449
450ClampFilter::ClampFilter(float min, float max, bool ignore_out_of_range)
451 : min_(min), max_(max), ignore_out_of_range_(ignore_out_of_range) {}
453 if (std::isfinite(this->min_) && !(value >= this->min_)) {
454 if (this->ignore_out_of_range_) {
455 return {};
456 }
457 return this->min_;
458 }
459
460 if (std::isfinite(this->max_) && !(value <= this->max_)) {
461 if (this->ignore_out_of_range_) {
462 return {};
463 }
464 return this->max_;
465 }
466 return value;
467}
468
469RoundFilter::RoundFilter(uint8_t precision) : precision_(precision) {}
471 if (std::isfinite(value)) {
472 float accuracy_mult = powf(10.0f, this->precision_);
473 return roundf(accuracy_mult * value) / accuracy_mult;
474 }
475 return value;
476}
477
478RoundMultipleFilter::RoundMultipleFilter(float multiple) : multiple_(multiple) {}
480 if (std::isfinite(value)) {
481 return value - remainderf(value, this->multiple_);
482 }
483 return value;
484}
485
487 if (!std::isfinite(value)) {
488 return NAN;
489 }
490 double k = 273.15;
491 // https://de.wikipedia.org/wiki/Steinhart-Hart-Gleichung#cite_note-stein2_s4-3
492 double t = value + k;
493 double y = (this->a_ - 1 / (t)) / (2 * this->c_);
494 double x = sqrt(pow(this->b_ / (3 * this->c_), 3) + y * y);
495 double resistance = exp(pow(x - y, 1 / 3.0) - pow(x + y, 1 / 3.0));
496 return resistance;
497}
498
500 if (!std::isfinite(value)) {
501 return NAN;
502 }
503 double lr = log(double(value));
504 double v = this->a_ + this->b_ * lr + this->c_ * lr * lr * lr;
505 double temp = float(1.0 / v - 273.15);
506 return temp;
507}
508
509// StreamingFilter (base class)
510StreamingFilter::StreamingFilter(size_t window_size, size_t send_first_at)
511 : window_size_(window_size), send_first_at_(send_first_at) {}
512
514 // Process the value (child class tracks min/max/sum/etc)
515 this->process_value(value);
516
517 this->count_++;
518
519 // Check if we should send (handle send_first_at for first value)
520 bool should_send = false;
521 if (this->first_send_ && this->count_ >= this->send_first_at_) {
522 should_send = true;
523 this->first_send_ = false;
524 } else if (!this->first_send_ && this->count_ >= this->window_size_) {
525 should_send = true;
526 }
527
528 if (should_send) {
529 float result = this->compute_batch_result();
530 // Reset for next batch
531 this->count_ = 0;
532 this->reset_batch();
533 ESP_LOGVV(TAG, "StreamingFilter(%p)::new_value(%f) SENDING %f", this, value, result);
534 return result;
535 }
536
537 return {};
538}
539
540// StreamingMinFilter
542 // Update running minimum (ignore NaN values)
543 if (!std::isnan(value)) {
544 this->current_min_ = std::isnan(this->current_min_) ? value : std::min(this->current_min_, value);
545 }
546}
547
549
551
552// StreamingMaxFilter
554 // Update running maximum (ignore NaN values)
555 if (!std::isnan(value)) {
556 this->current_max_ = std::isnan(this->current_max_) ? value : std::max(this->current_max_, value);
557 }
558}
559
561
563
564// StreamingMovingAverageFilter
566 // Accumulate sum (ignore NaN values)
567 if (!std::isnan(value)) {
568 this->sum_ += value;
569 this->valid_count_++;
570 }
572
574 return this->valid_count_ > 0 ? this->sum_ / this->valid_count_ : NAN;
575}
576
578 this->sum_ = 0.0f;
579 this->valid_count_ = 0;
580}
581
582} // namespace esphome::sensor
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_interval(const std voi set_interval)(const char *name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
Definition component.h:336
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:227
bool empty() const
Definition helpers.h:385
size_t size() const
Definition helpers.h:384
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Definition helpers.h:344
void init(size_t n)
Definition helpers.h:317
T value(X... x) const
Definition automation.h:149
bool has_value() const
Definition optional.h:92
FixedVector< std::array< float, 3 > > linear_functions_
Definition filter.h:501
optional< float > new_value(float value) override
Definition filter.cpp:429
CalibrateLinearFilter(std::initializer_list< std::array< float, 3 > > linear_functions)
Definition filter.cpp:426
CalibratePolynomialFilter(std::initializer_list< float > coefficients)
Definition filter.cpp:437
optional< float > new_value(float value) override
Definition filter.cpp:440
ClampFilter(float min, float max, bool ignore_out_of_range)
Definition filter.cpp:450
optional< float > new_value(float value) override
Definition filter.cpp:452
optional< float > new_value(float value) override
Definition filter.cpp:390
float get_setup_priority() const override
Definition filter.cpp:397
DebounceFilter(uint32_t time_period)
Definition filter.cpp:396
void set_baseline(float(*fn)(float))
Definition filter.cpp:302
DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1)
Definition filter.cpp:299
optional< float > new_value(float value) override
Definition filter.cpp:304
float(* baseline_)(float)
Definition filter.h:467
optional< float > new_value(float value) override
Definition filter.cpp:162
ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
Definition filter.cpp:160
Apply a filter to sensor values such as moving average.
Definition filter.h:19
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:24
virtual void initialize(Sensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
Definition filter.cpp:33
void input(float value)
Definition filter.cpp:18
optional< float > new_value(float value) override
Definition filter.cpp:265
FilterOutValueFilter(std::initializer_list< TemplatableValue< float > > values_to_filter_out)
Definition filter.cpp:262
HeartbeatFilter(uint32_t time_period)
Definition filter.cpp:400
optional< float > new_value(float value) override
Definition filter.cpp:402
float get_setup_priority() const override
Definition filter.cpp:424
const lambda_filter_t & get_lambda_filter() const
Definition filter.cpp:216
LambdaFilter(lambda_filter_t lambda_filter)
Definition filter.cpp:215
lambda_filter_t lambda_filter_
Definition filter.h:295
void set_lambda_filter(const lambda_filter_t &lambda_filter)
Definition filter.cpp:217
optional< float > new_value(float value) override
Definition filter.cpp:219
float compute_result() override
Definition filter.cpp:143
float compute_result() override
Definition filter.cpp:87
float compute_result() override
Definition filter.cpp:140
float find_extremum_()
Helper to find min or max value in window, skipping NaN values Usage: find_extremum_<std::less<float>...
Definition filter.h:82
optional< float > new_value(float value) override
Definition filter.cpp:233
MultiplyFilter(TemplatableValue< float > multiplier)
Definition filter.cpp:231
TemplatableValue< float > multiplier_
Definition filter.h:331
optional< float > new_value(float value) override
Definition filter.cpp:228
OffsetFilter(TemplatableValue< float > offset)
Definition filter.cpp:226
TemplatableValue< float > offset_
Definition filter.h:321
optional< float > new_value(float value) override
Definition filter.cpp:328
PhiNode(OrFilter *or_parent)
Definition filter.cpp:326
OrFilter(std::initializer_list< Filter * > filters)
Definition filter.cpp:325
optional< float > new_value(float value) override
Definition filter.cpp:336
void initialize(Sensor *parent, Filter *next) override
Definition filter.cpp:343
FixedVector< Filter * > filters_
Definition filter.h:490
float compute_result() override
Definition filter.cpp:126
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
Definition filter.cpp:123
RoundFilter(uint8_t precision)
Definition filter.cpp:469
optional< float > new_value(float value) override
Definition filter.cpp:470
optional< float > new_value(float value) override
Definition filter.cpp:479
Base-class for all sensors.
Definition sensor.h:43
void internal_send_state_to_frontend(float state)
Definition sensor.cpp:115
int8_t get_accuracy_decimals()
Get the accuracy in decimals, using the manual override if set.
Definition sensor.cpp:45
SkipInitialFilter(size_t num_to_ignore)
Construct a SkipInitialFilter.
Definition filter.cpp:110
optional< float > new_value(float value) override
Definition filter.cpp:111
size_t window_head_
Index where next value will be written.
Definition filter.h:64
size_t window_size_
Maximum window size.
Definition filter.h:66
optional< float > new_value(float value) final
Definition filter.cpp:46
size_t window_count_
Number of valid values in window (0 to window_size_)
Definition filter.h:65
FixedVector< float > window_
Access the sliding window values (ring buffer implementation) Use: for (size_t i = 0; i < window_coun...
Definition filter.h:63
size_t send_at_
Counter for send_every.
Definition filter.h:68
size_t send_every_
Send result every N values.
Definition filter.h:67
virtual float compute_result()=0
Called by new_value() to compute the filtered result from the current window.
SlidingWindowFilter(size_t window_size, size_t send_every, size_t send_first_at)
Definition filter.cpp:40
Base class for filters that need a sorted window (Median, Quantile).
Definition filter.h:100
FixedVector< float > get_window_values_()
Helper to get non-NaN values from the window (not sorted - caller will use nth_element) Returns empty...
Definition filter.cpp:72
virtual void process_value(float value)=0
Called by new_value() to process each value in the batch.
virtual float compute_batch_result()=0
Called by new_value() to compute the result after collecting window_size values.
StreamingFilter(size_t window_size, size_t send_first_at)
Definition filter.cpp:510
virtual void reset_batch()=0
Called by new_value() to reset internal state after sending a result.
optional< float > new_value(float value) final
Definition filter.cpp:513
void process_value(float value) override
Definition filter.cpp:553
float compute_batch_result() override
Definition filter.cpp:560
float compute_batch_result() override
Definition filter.cpp:548
void process_value(float value) override
Definition filter.cpp:541
void process_value(float value) override
Definition filter.cpp:565
optional< float > new_value(float value) override
Definition filter.cpp:188
ThrottleAverageFilter(uint32_t time_period)
Definition filter.cpp:186
float get_setup_priority() const override
Definition filter.cpp:212
ThrottleFilter(uint32_t min_time_between_inputs)
Definition filter.cpp:272
optional< float > new_value(float value) override
Definition filter.cpp:273
optional< float > new_value(float value) override
Definition filter.cpp:287
ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, std::initializer_list< TemplatableValue< float > > prioritized_values)
Definition filter.cpp:283
float get_setup_priority() const override
Definition filter.cpp:365
optional< float > new_value(float value) override
Definition filter.cpp:380
optional< float > new_value(float value) override
Definition filter.cpp:368
optional< float > new_value(float value) override
Definition filter.cpp:486
optional< float > new_value(float value) override
Definition filter.cpp:499
Base class for filters that compare sensor values against a list of configured values.
Definition filter.h:340
ValueListFilter(std::initializer_list< TemplatableValue< float > > values)
Definition filter.cpp:236
FixedVector< TemplatableValue< float > > values_
Definition filter.h:347
bool value_matches_any_(float sensor_value)
Check if sensor value matches any configured value (with accuracy rounding)
Definition filter.cpp:238
float position
Definition cover.h:0
constexpr uint32_t FILTER_ID
Definition filter.cpp:15
std::function< optional< float >(float)> lambda_filter_t
Definition filter.h:276
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.cpp:83
size_t size
Definition helpers.h:729
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:25
Application App
Global storage of Application pointer - only one Application can exist.
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6