ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
filter.cpp
Go to the documentation of this file.
2#ifdef USE_SENSOR_FILTER
3
4#include "filter.h"
5#include <cmath>
7#include "esphome/core/hal.h"
9#include "esphome/core/log.h"
10#include "sensor.h"
11
12namespace esphome::sensor {
13
14ESPHOME_LOG_TAG(TAG, "sensor.filter");
15
18static bool throttle_nan_passes(uint32_t &last_input, uint32_t period, float value) {
20 if (last_input == 0 || now - last_input >= period || std::isnan(value)) {
21 last_input = now;
22 return true;
23 }
24 return false;
25}
26
27// Filter
28void Filter::input(float value) {
29 ESP_LOGVV(TAG, "Filter(%p)::input(%f)", this, value);
30 optional<float> out = this->new_value(value);
31 if (out.has_value())
32 this->output(*out);
33}
34void Filter::output(float value) {
35 if (this->next_ == nullptr) {
36 ESP_LOGVV(TAG, "Filter(%p)::output(%f) -> SENSOR", this, value);
38 } else {
39 ESP_LOGVV(TAG, "Filter(%p)::output(%f) -> %p", this, value, this->next_);
40 this->next_->input(value);
41 }
42}
44 ESP_LOGVV(TAG, "Filter(%p)::initialize(parent=%p next=%p)", this, parent, next);
45 this->parent_ = parent;
46 this->next_ = next;
47}
48
49// SlidingWindowFilter
50SlidingWindowFilter::SlidingWindowFilter(uint16_t window_size, uint16_t send_every, uint16_t send_first_at)
51 : send_every_(send_every), send_at_(send_every - send_first_at) {
52 this->window_.init(window_size);
53}
54
55optional<float> SlidingWindowFilter::new_value(float value) {
56 // Add value to ring buffer (overwrites oldest when full)
57 this->window_.push_overwrite(value);
58
59 // Check if we should send a result
60 if (++this->send_at_ >= this->send_every_) {
61 this->send_at_ = 0;
62 float result = this->compute_result();
63 ESP_LOGVV(TAG, "SlidingWindowFilter(%p)::new_value(%f) SENDING %f", this, value, result);
64 return result;
65 }
66 return {};
67}
68
69// SortedWindowFilter
71 // Copy window without NaN values using FixedVector (no heap allocation)
72 // Returns unsorted values - caller will use std::nth_element for partial sorting as needed
73 FixedVector<float> values;
74 values.init(this->window_.size());
75 for (float v : this->window_) {
76 if (!std::isnan(v)) {
77 values.push_back(v);
78 }
79 }
80 return values;
81}
82
83// MedianFilter
86 if (values.empty())
87 return NAN;
88
89 size_t size = values.size();
90 size_t mid = size / 2;
91
92 if (size % 2) {
93 // Odd number of elements - use nth_element to find middle element
94 std::nth_element(values.begin(), values.begin() + mid, values.end());
95 return values[mid];
96 }
97 // Even number of elements - need both middle elements
98 // Use nth_element to find upper middle element
99 std::nth_element(values.begin(), values.begin() + mid, values.end());
100 float upper = values[mid];
101 // Find the maximum of the lower half (which is now everything before mid)
102 float lower = *std::max_element(values.begin(), values.begin() + mid);
103 return (lower + upper) / 2.0f;
104}
105
106// SkipInitialFilter
107SkipInitialFilter::SkipInitialFilter(size_t num_to_ignore) : num_to_ignore_(num_to_ignore) {}
108optional<float> SkipInitialFilter::new_value(float value) {
109 if (num_to_ignore_ > 0) {
111 ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %zu left", this, value, num_to_ignore_);
112 return {};
113 }
114
115 ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SENDING", this, value);
116 return value;
117}
118
119// QuantileFilter
120QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
121 : SortedWindowFilter(window_size, send_every, send_first_at), quantile_(quantile) {}
122
124 FixedVector<float> values = this->get_window_values_();
125 if (values.empty())
126 return NAN;
127
128 size_t position = ceilf(values.size() * this->quantile_) - 1;
129 ESP_LOGVV(TAG, "QuantileFilter(%p)::position: %zu/%zu", this, position + 1, values.size());
130
131 // Use nth_element to find the quantile element (O(n) instead of O(n log n))
132 std::nth_element(values.begin(), values.begin() + position, values.end());
133 return values[position];
134}
135
136// MinFilter
138
139// MaxFilter
141
142// SlidingWindowMovingAverageFilter
144 float sum = 0;
145 size_t valid_count = 0;
146 for (float v : this->window_) {
147 if (!std::isnan(v)) {
148 sum += v;
149 valid_count++;
150 }
151 }
152 return valid_count ? sum / valid_count : NAN;
153}
154
155// ExponentialMovingAverageFilter
156ExponentialMovingAverageFilter::ExponentialMovingAverageFilter(float alpha, uint16_t send_every, uint16_t send_first_at)
157 : alpha_(alpha), send_every_(send_every), send_at_(send_every - send_first_at) {}
158optional<float> ExponentialMovingAverageFilter::new_value(float value) {
159 if (!std::isnan(value)) {
160 if (this->first_value_) {
161 this->accumulator_ = value;
162 this->first_value_ = false;
163 } else {
164 this->accumulator_ = (this->alpha_ * value) + (1.0f - this->alpha_) * this->accumulator_;
165 }
166 }
167
168 const float average = std::isnan(value) ? value : this->accumulator_;
169 ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) -> %f", this, value, average);
170
171 if (++this->send_at_ >= this->send_every_) {
172 ESP_LOGVV(TAG, "ExponentialMovingAverageFilter(%p)::new_value(%f) SENDING %f", this, value, average);
173 this->send_at_ = 0;
174 return average;
175 }
176 return {};
177}
178
179// ThrottleAverageFilter
180ThrottleAverageFilter::ThrottleAverageFilter(uint32_t time_period) : time_period_(time_period) {}
181
182optional<float> ThrottleAverageFilter::new_value(float value) {
183 ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::new_value(value=%f)", this, value);
184 if (std::isnan(value)) {
185 this->have_nan_ = true;
186 } else {
187 this->sum_ += value;
188 this->n_++;
189 }
190 return {};
191}
193 Filter::initialize(parent, next);
194 App.scheduler.set_interval(this, this->time_period_, [this]() {
195 ESP_LOGVV(TAG, "ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)", this, this->sum_, this->n_);
196 if (this->n_ == 0) {
197 if (this->have_nan_)
198 this->output(NAN);
199 } else {
200 this->output(this->sum_ / this->n_);
201 this->sum_ = 0.0f;
202 this->n_ = 0;
203 }
204 this->have_nan_ = false;
205 });
206}
207
208// LambdaFilter
209LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std::move(lambda_filter)) {}
211void LambdaFilter::set_lambda_filter(const lambda_filter_t &lambda_filter) { this->lambda_filter_ = lambda_filter; }
212
213optional<float> LambdaFilter::new_value(float value) {
214 auto it = this->lambda_filter_(value);
215 ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%f) -> %f", this, value, it.value_or(INFINITY));
216 return it;
217}
218
219// OffsetFilter
221
222optional<float> OffsetFilter::new_value(float value) { return value + this->offset_.value(); }
223
224// MultiplyFilter
225MultiplyFilter::MultiplyFilter(TemplatableFn<float> multiplier) : multiplier_(multiplier) {}
226
227optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_.value(); }
228
229// ValueListFilter
230bool ValueListFilter::value_matches_any_(float sensor_value) {
231 int8_t accuracy = this->parent_->get_accuracy_decimals();
232 float accuracy_mult = pow10_int(accuracy);
233 float rounded_sensor = roundf(accuracy_mult * sensor_value);
234
235 for (const TemplatableFn<float> *v = this->values_; v->has_value(); v++) {
236 float fv = v->value();
237
238 // Handle NaN comparison
239 if (std::isnan(fv)) {
240 if (std::isnan(sensor_value))
241 return true;
242 continue;
243 }
244
245 // Compare rounded values
246 if (roundf(accuracy_mult * fv) == rounded_sensor)
247 return true;
248 }
249
250 return false;
251}
252
253// ThrottleFilter
254ThrottleFilter::ThrottleFilter(uint32_t min_time_between_inputs) : min_time_between_inputs_(min_time_between_inputs) {}
255optional<float> ThrottleFilter::new_value(float value) {
257 if (this->last_input_ == 0 || now - this->last_input_ >= min_time_between_inputs_) {
258 this->last_input_ = now;
259 return value;
260 }
261 return {};
262}
263
264// ThrottleWithPriorityFilter
265optional<float> ThrottleWithPriorityFilter::new_value(float value) {
267 if (this->last_input_ == 0 || now - this->last_input_ >= this->min_time_between_inputs_ ||
268 this->value_matches_any_(value)) {
269 this->last_input_ = now;
270 return value;
271 }
272 return {};
273}
274
275// ThrottleWithPriorityNanFilter
277 : min_time_between_inputs_(min_time_between_inputs) {}
278optional<float> ThrottleWithPriorityNanFilter::new_value(float value) {
279 if (throttle_nan_passes(this->last_input_, this->min_time_between_inputs_, value))
280 return value;
281 return {};
282}
283
284// DeltaFilter
285DeltaFilter::DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1)
286 : min_a0_(min_a0), min_a1_(min_a1), max_a0_(max_a0), max_a1_(max_a1) {}
287
288void DeltaFilter::set_baseline(float (*fn)(float)) { this->baseline_ = fn; }
289
290optional<float> DeltaFilter::new_value(float value) {
291 const bool no_value = std::isnan(value);
292 const bool no_reference = std::isnan(this->last_value_);
293 if (no_value && no_reference)
294 return {};
295 if (no_value || no_reference) {
296 this->last_value_ = value;
297 return value;
298 }
299 // calculate min and max using the linear equation
300 float ref = this->baseline_(this->last_value_);
301 float min = fabsf(this->min_a0_ + ref * this->min_a1_);
302 float max = fabsf(this->max_a0_ + ref * this->max_a1_);
303 float delta = fabsf(value - ref);
304 // accept only if within range
305 if (delta > min && delta <= max) {
306 this->last_value_ = value;
307 return value;
308 }
309 return {};
310}
311
312// OrFilter helpers
313void or_filter_initialize(Filter **filters, size_t count, Sensor *parent, Filter *phi) {
314 for (size_t i = 0; i < count; i++) {
315 filters[i]->initialize(parent, phi);
316 }
317 phi->initialize(parent, nullptr);
318}
319
320optional<float> or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value) {
321 has_value = false;
322 for (size_t i = 0; i < count; i++)
323 filters[i]->input(value);
324 return {};
325}
326
327// TimeoutFilterBase - shared loop logic
329 // Check if timeout period has elapsed
330 // Use cached loop start time to avoid repeated millis() calls
332 if (now - this->timeout_start_time_ >= this->time_period_) {
333 // Timeout fired - get output value from derived class and output it
334 this->output(this->get_output_value());
335
336 // Disable loop until next value arrives
337 this->disable_loop();
338 }
339}
340
342
343// TimeoutFilterLast - "last" mode implementation
344optional<float> TimeoutFilterLast::new_value(float value) {
345 // Store the value to output when timeout fires
346 this->pending_value_ = value;
347
348 // Record when timeout started and enable loop
349 this->timeout_start_time_ = millis();
350 this->enable_loop();
351
352 return value;
353}
354
355// TimeoutFilterConfigured - configured value mode implementation
356optional<float> TimeoutFilterConfigured::new_value(float value) {
357 // Record when timeout started and enable loop
358 // Note: we don't store the incoming value since we have a configured value
359 this->timeout_start_time_ = millis();
360 this->enable_loop();
361
362 return value;
363}
364
365// TimeoutThrottleFilter
366optional<float> TimeoutThrottleFilter::new_value(float value) {
368 if (throttle_nan_passes(this->last_input_, this->time_period_, value))
369 return value;
370 return {};
371}
372
375 if (now - this->timeout_start_time_ >= this->time_period_) {
376 if (throttle_nan_passes(this->last_input_, this->time_period_, this->pending_value_))
377 this->output(this->pending_value_);
378 this->disable_loop();
379 }
380}
381
382// DebounceFilter
383optional<float> DebounceFilter::new_value(float value) {
384 App.scheduler.set_timeout(this, this->time_period_, [this, value]() { this->output(value); });
385
386 return {};
387}
388
389DebounceFilter::DebounceFilter(uint32_t time_period) : time_period_(time_period) {}
390
391// HeartbeatFilter
392HeartbeatFilter::HeartbeatFilter(uint32_t time_period) : time_period_(time_period), last_input_(NAN) {}
393
394optional<float> HeartbeatFilter::new_value(float value) {
395 ESP_LOGVV(TAG, "HeartbeatFilter(%p)::new_value(value=%f)", this, value);
396 this->last_input_ = value;
397 this->has_value_ = true;
398
399 if (this->optimistic_) {
400 return value;
401 }
402 return {};
403}
404
406 Filter::initialize(parent, next);
407 App.scheduler.set_interval(this, this->time_period_, [this]() {
408 ESP_LOGVV(TAG, "HeartbeatFilter(%p)::interval(has_value=%s, last_input=%f)", this, YESNO(this->has_value_),
409 this->last_input_);
410 if (!this->has_value_)
411 return;
412
413 this->output(this->last_input_);
414 });
415}
416
417// The calibration tables hold only floats, so aligned 32-bit loads from PROGMEM are safe on ESP8266.
418optional<float> CalibrateLinearFilter::new_value(float value) {
419 // Always returns: codegen ends the table with a segment whose boundary is NaN.
420 for (const auto *function = this->functions_;; function++) {
421 if (!std::isfinite((*function)[2]) || value < (*function)[2])
422 return (value * (*function)[0]) + (*function)[1];
423 }
424}
425
426optional<float> CalibratePolynomialFilter::new_value(float value) {
427 float res = 0.0f;
428 float x = 1.0f;
429 const auto count = static_cast<size_t>(this->coefficients_[0]);
430 for (size_t i = 1; i <= count; i++) {
431 res += x * this->coefficients_[i];
432 x *= value;
433 }
434 return res;
435}
436
437ClampFilter::ClampFilter(float min, float max, bool ignore_out_of_range)
438 : min_(min), max_(max), ignore_out_of_range_(ignore_out_of_range) {}
439optional<float> ClampFilter::new_value(float value) {
440 if (std::isfinite(this->min_) && !(value >= this->min_)) {
441 if (this->ignore_out_of_range_) {
442 return {};
443 }
444 return this->min_;
445 }
446
447 if (std::isfinite(this->max_) && !(value <= this->max_)) {
448 if (this->ignore_out_of_range_) {
449 return {};
450 }
451 return this->max_;
452 }
453 return value;
454}
455
456RoundFilter::RoundFilter(uint8_t precision) : precision_(precision) {}
457optional<float> RoundFilter::new_value(float value) {
458 if (std::isfinite(value)) {
459 float accuracy_mult = pow10_int(this->precision_);
460 return roundf(accuracy_mult * value) / accuracy_mult;
461 }
462 return value;
463}
464
465RoundMultipleFilter::RoundMultipleFilter(float multiple) : multiple_(multiple) {}
466optional<float> RoundMultipleFilter::new_value(float value) {
467 if (std::isfinite(value)) {
468 return value - remainderf(value, this->multiple_);
469 }
470 return value;
471}
472
473optional<float> ToNTCResistanceFilter::new_value(float value) {
474 if (!std::isfinite(value)) {
475 return NAN;
476 }
477 double k = 273.15;
478 // https://de.wikipedia.org/wiki/Steinhart-Hart-Gleichung#cite_note-stein2_s4-3
479 double t = static_cast<double>(value) + k;
480 double y = (this->a_ - 1 / (t)) / (2 * this->c_);
481 double x = sqrt(pow(this->b_ / (3 * this->c_), 3) + y * y);
482 double resistance = exp(pow(x - y, 1 / 3.0) - pow(x + y, 1 / 3.0));
483 return resistance;
484}
485
486optional<float> ToNTCTemperatureFilter::new_value(float value) {
487 if (!std::isfinite(value)) {
488 return NAN;
489 }
490 double lr = log(double(value));
491 double v = this->a_ + this->b_ * lr + this->c_ * lr * lr * lr;
492 double temp = float(1.0 / v - 273.15);
493 return temp;
494}
495
496// RHCorrectionFilter
497static constexpr float MAGNUS_B = 17.67f, MAGNUS_C = 243.5f;
498
499static bool rh_correction_temp_in_band(float t) { return t >= -40.0f && t <= 50.0f; }
500
501optional<float> RHCorrectionFilter::new_value(float value) {
502 if (!this->temperature_sensor_->has_state()) {
503 if (!this->warned_) {
504 ESP_LOGW(TAG, "RHCorrectionFilter(%p): no temperature yet, passing humidity through uncorrected", this);
505 this->warned_ = true;
506 }
507 return value;
508 }
509 float offset = this->temperature_offset_.value();
510 float tc = this->temperature_sensor_->get_state();
511 if (this->use_fahrenheit_) {
512 tc = fahrenheit_to_celsius(tc);
513 offset /= 1.8f;
514 }
515 const float tnc = tc - offset;
516 // A NaN temperature or offset is a faulted input: keep the last corrected value
517 if (std::isnan(tnc)) {
518 if (!this->warned_) {
519 ESP_LOGW(TAG, "RHCorrectionFilter(%p): temperature or offset is NaN, dropping humidity updates", this);
520 this->warned_ = true;
521 }
522 return {};
523 }
524 if (!rh_correction_temp_in_band(tc) || !rh_correction_temp_in_band(tnc)) {
525 if (!this->warned_) {
526 ESP_LOGW(TAG, "RHCorrectionFilter(%p): Temperature out of range -40..50 °C. Tc=%f Tnc=%f", this, tc, tnc);
527 this->warned_ = true;
528 }
529 return value;
530 }
531 this->warned_ = false;
532 const float rh =
533 clamp(value * std::exp(MAGNUS_B * MAGNUS_C * (tnc - tc) / ((tnc + MAGNUS_C) * (tc + MAGNUS_C))), 0.0f, 100.0f);
534 ESP_LOGVV(TAG, "RHCorrectionFilter(%p)::new_value(%f) -> %f", this, value, rh);
535 return rh;
536}
537
538// StreamingFilter (base class)
539StreamingFilter::StreamingFilter(uint16_t window_size, uint16_t send_first_at)
540 : window_size_(window_size), send_first_at_(send_first_at) {}
541
542optional<float> StreamingFilter::new_value(float value) {
543 // Process the value (child class tracks min/max/sum/etc)
544 this->process_value(value);
545
546 this->count_++;
547
548 // Check if we should send (handle send_first_at for first value)
549 bool should_send = false;
550 if (this->first_send_ && this->count_ >= this->send_first_at_) {
551 should_send = true;
552 this->first_send_ = false;
553 } else if (!this->first_send_ && this->count_ >= this->window_size_) {
554 should_send = true;
555 }
556
557 if (should_send) {
558 float result = this->compute_batch_result();
559 // Reset for next batch
560 this->count_ = 0;
561 this->reset_batch();
562 ESP_LOGVV(TAG, "StreamingFilter(%p)::new_value(%f) SENDING %f", this, value, result);
563 return result;
564 }
565
566 return {};
567}
568
569// StreamingMinFilter
571 // Update running minimum (ignore NaN values)
572 if (!std::isnan(value)) {
573 this->current_min_ = std::isnan(this->current_min_) ? value : std::min(this->current_min_, value);
574 }
575}
576
578
580
581// StreamingMaxFilter
583 // Update running maximum (ignore NaN values)
584 if (!std::isnan(value)) {
585 this->current_max_ = std::isnan(this->current_max_) ? value : std::max(this->current_max_, value);
586 }
587}
588
590
592
593// StreamingMovingAverageFilter
595 // Accumulate sum (ignore NaN values)
596 if (!std::isnan(value)) {
597 this->sum_ += value;
598 this->valid_count_++;
599 }
600}
601
603 return this->valid_count_ > 0 ? this->sum_ / this->valid_count_ : NAN;
604}
605
607 this->sum_ = 0.0f;
608 this->valid_count_ = 0;
609}
610
611} // namespace esphome::sensor
612
613#endif // USE_SENSOR_FILTER
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.
void enable_loop()
Enable this component's loop.
Definition component.h:248
void disable_loop()
Disable this component's loop.
bool has_state() const
void push_overwrite(const T &value)
Push a value, overwriting the oldest if full.
Definition helpers.h:541
void init(index_type capacity)
Allocate capacity - can only be called once.
Definition helpers.h:519
index_type size() const
Definition helpers.h:562
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
Definition helpers.h:624
bool empty() const
Definition helpers.h:801
size_t size() const
Definition helpers.h:800
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Definition helpers.h:751
void init(size_t n)
Definition helpers.h:714
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:20
bool has_value() const
Definition automation.h:66
T value(X... x) const
Definition automation.h:68
optional< float > new_value(float value) override
Definition filter.cpp:418
const std::array< float, 3 > * functions_
Definition filter.h:573
optional< float > new_value(float value) override
Definition filter.cpp:426
ClampFilter(float min, float max, bool ignore_out_of_range)
Definition filter.cpp:437
optional< float > new_value(float value) override
Definition filter.cpp:439
optional< float > new_value(float value) override
Definition filter.cpp:383
DebounceFilter(uint32_t time_period)
Definition filter.cpp:389
void set_baseline(float(*fn)(float))
Definition filter.cpp:288
DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1)
Definition filter.cpp:285
optional< float > new_value(float value) override
Definition filter.cpp:290
float(* baseline_)(float)
Definition filter.h:518
optional< float > new_value(float value) override
Definition filter.cpp:158
ExponentialMovingAverageFilter(float alpha, uint16_t send_every, uint16_t send_first_at)
Definition filter.cpp:156
Apply a filter to sensor values such as moving average.
Definition filter.h:22
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:34
virtual void initialize(Sensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
Definition filter.cpp:43
void input(float value)
Definition filter.cpp:28
HeartbeatFilter(uint32_t time_period)
Definition filter.cpp:392
optional< float > new_value(float value) override
Definition filter.cpp:394
void initialize(Sensor *parent, Filter *next) override
Definition filter.cpp:405
const lambda_filter_t & get_lambda_filter() const
Definition filter.cpp:210
LambdaFilter(lambda_filter_t lambda_filter)
Definition filter.cpp:209
lambda_filter_t lambda_filter_
Definition filter.h:294
void set_lambda_filter(const lambda_filter_t &lambda_filter)
Definition filter.cpp:211
optional< float > new_value(float value) override
Definition filter.cpp:213
float compute_result() override
Definition filter.cpp:140
float compute_result() override
Definition filter.cpp:84
float compute_result() override
Definition filter.cpp:137
float find_extremum_()
Helper to find min or max value in window, skipping NaN values Usage: find_extremum_<std::less<float>...
Definition filter.h:81
TemplatableFn< float > multiplier_
Definition filter.h:330
optional< float > new_value(float value) override
Definition filter.cpp:227
MultiplyFilter(TemplatableFn< float > multiplier)
Definition filter.cpp:225
optional< float > new_value(float value) override
Definition filter.cpp:222
TemplatableFn< float > offset_
Definition filter.h:320
OffsetFilter(TemplatableFn< float > offset)
Definition filter.cpp:220
float compute_result() override
Definition filter.cpp:123
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
Definition filter.cpp:120
TemplatableFn< float > temperature_offset_
Definition filter.h:664
optional< float > new_value(float value) override
Definition filter.cpp:501
RoundFilter(uint8_t precision)
Definition filter.cpp:456
optional< float > new_value(float value) override
Definition filter.cpp:457
optional< float > new_value(float value) override
Definition filter.cpp:466
Base-class for all sensors.
Definition sensor.h:47
void internal_send_state_to_frontend(float state)
Definition sensor.cpp:116
float get_state() const
Getter-syntax for .state.
Definition sensor.h:98
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:107
optional< float > new_value(float value) override
Definition filter.cpp:108
FixedRingBuffer< float > window_
Sliding window ring buffer - automatically overwrites oldest values when full.
Definition filter.h:65
optional< float > new_value(float value) final
Definition filter.cpp:55
SlidingWindowFilter(uint16_t window_size, uint16_t send_every, uint16_t send_first_at)
Definition filter.cpp:50
uint16_t send_every_
Send result every N values.
Definition filter.h:66
virtual float compute_result()=0
Called by new_value() to compute the filtered result from the current window.
uint16_t send_at_
Counter for send_every.
Definition filter.h:67
Base class for filters that need a sorted window (Median, Quantile).
Definition filter.h:98
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:70
StreamingFilter(uint16_t window_size, uint16_t send_first_at)
Definition filter.cpp:539
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.
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:542
void process_value(float value) override
Definition filter.cpp:582
float compute_batch_result() override
Definition filter.cpp:589
float compute_batch_result() override
Definition filter.cpp:577
void process_value(float value) override
Definition filter.cpp:570
void process_value(float value) override
Definition filter.cpp:594
optional< float > new_value(float value) override
Definition filter.cpp:182
ThrottleAverageFilter(uint32_t time_period)
Definition filter.cpp:180
void initialize(Sensor *parent, Filter *next) override
Definition filter.cpp:192
ThrottleFilter(uint32_t min_time_between_inputs)
Definition filter.cpp:254
optional< float > new_value(float value) override
Definition filter.cpp:255
optional< float > new_value(float value) override
Definition filter.cpp:265
optional< float > new_value(float value) override
Definition filter.cpp:278
ThrottleWithPriorityNanFilter(uint32_t min_time_between_inputs)
Definition filter.cpp:276
float get_setup_priority() const override
Definition filter.cpp:341
optional< float > new_value(float value) override
Definition filter.cpp:356
optional< float > new_value(float value) override
Definition filter.cpp:344
optional< float > new_value(float value) override
Definition filter.cpp:366
optional< float > new_value(float value) override
Definition filter.cpp:473
optional< float > new_value(float value) override
Definition filter.cpp:486
bool value_matches_any_(float sensor_value)
Check if sensor value matches any configured value (with accuracy rounding)
Definition filter.cpp:230
const TemplatableFn< float > * values_
Definition filter.h:346
float position
Definition cover.h:0
StringRef ref
NameCopy * next
std::vector< uint8_t > & out
Definition gif.cpp:49
unsigned count
Definition gif.cpp:51
void or_filter_initialize(Filter **filters, size_t count, Sensor *parent, Filter *phi)
Non-template helpers for OrFilter (implementation in filter.cpp)
Definition filter.cpp:313
ESPHOME_LOG_TAG(TAG, "sensor.filter")
std::function< optional< float >(float)> lambda_filter_t
Definition filter.h:275
optional< float > or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value)
Definition filter.cpp:320
constexpr float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.h:43
uint16_t size
Definition helpers.cpp:34
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:25
constexpr float fahrenheit_to_celsius(float value)
Convert degrees Fahrenheit to degrees Celsius.
Definition helpers.h:1787
Application App
Global storage of Application pointer - only one Application can exist.
float pow10_int(int8_t exp)
Compute 10^exp using iterative multiplication/division.
Definition helpers.h:874
STL namespace.
static void uint32_t
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6