ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
filter.h
Go to the documentation of this file.
1#pragma once
2
4#ifdef USE_SENSOR_FILTER
5
6#include <array>
7#include <utility>
8#include <vector>
12
13namespace esphome::sensor {
14
15class Sensor;
16
22class Filter {
23 public:
33 virtual optional<float> new_value(float value) = 0;
34
36 virtual void initialize(Sensor *parent, Filter *next);
37
38 void input(float value);
39
40 void output(float value);
41
42 protected:
43 friend Sensor;
44
45 Filter *next_{nullptr};
46 Sensor *parent_{nullptr};
47};
48
55 public:
56 SlidingWindowFilter(uint16_t window_size, uint16_t send_every, uint16_t send_first_at);
57
58 optional<float> new_value(float value) final;
59
60 protected:
62 virtual float compute_result() = 0;
63
66 uint16_t send_every_;
67 uint16_t send_at_;
68};
69
75 public:
77
78 protected:
81 template<typename Compare> float find_extremum_() {
82 float result = NAN;
83 Compare comp;
84 for (float v : this->window_) {
85 if (!std::isnan(v)) {
86 result = std::isnan(result) ? v : (comp(v, result) ? v : result);
87 }
88 }
89 return result;
90 }
91};
92
107
113 public:
123 explicit QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile);
124
125 void set_quantile(float quantile) { this->quantile_ = quantile; }
126
127 protected:
128 float compute_result() override;
130};
131
137 public:
146 using SortedWindowFilter::SortedWindowFilter;
147
148 protected:
149 float compute_result() override;
150};
151
156class SkipInitialFilter : public Filter {
157 public:
162 explicit SkipInitialFilter(size_t num_to_ignore);
163
164 optional<float> new_value(float value) override;
165
166 protected:
168};
169
174class MinFilter : public MinMaxFilter {
175 public:
184 using MinMaxFilter::MinMaxFilter;
185
186 protected:
187 float compute_result() override;
188};
189
194class MaxFilter : public MinMaxFilter {
195 public:
204 using MinMaxFilter::MinMaxFilter;
205
206 protected:
207 float compute_result() override;
208};
209
216 public:
226
227 protected:
228 float compute_result() override;
229};
230
237 public:
238 ExponentialMovingAverageFilter(float alpha, uint16_t send_every, uint16_t send_first_at);
239
240 optional<float> new_value(float value) override;
241
242 void set_send_every(uint16_t send_every);
243 void set_alpha(float alpha);
244
245 protected:
246 float accumulator_{NAN};
247 float alpha_;
248 uint16_t send_every_;
249 uint16_t send_at_;
250 bool first_value_{true};
251};
252
257class ThrottleAverageFilter : public Filter, public Component {
258 public:
259 explicit ThrottleAverageFilter(uint32_t time_period);
260
261 void setup() override;
262
263 optional<float> new_value(float value) override;
264
265 float get_setup_priority() const override;
266
267 protected:
268 float sum_{0.0f};
269 unsigned int n_{0};
271 bool have_nan_{false};
272};
273
274using lambda_filter_t = std::function<optional<float>(float)>;
275
283class LambdaFilter : public Filter {
284 public:
285 explicit LambdaFilter(lambda_filter_t lambda_filter);
286
287 optional<float> new_value(float value) override;
288
289 const lambda_filter_t &get_lambda_filter() const;
290 void set_lambda_filter(const lambda_filter_t &lambda_filter);
291
292 protected:
294};
295
302 public:
303 explicit StatelessLambdaFilter(optional<float> (*lambda_filter)(float)) : lambda_filter_(lambda_filter) {}
304
305 optional<float> new_value(float value) override { return this->lambda_filter_(value); }
306
307 protected:
308 optional<float> (*lambda_filter_)(float);
309};
310
312class OffsetFilter : public Filter {
313 public:
314 explicit OffsetFilter(TemplatableFn<float> offset);
315
316 optional<float> new_value(float value) override;
317
318 protected:
320};
321
323class MultiplyFilter : public Filter {
324 public:
325 explicit MultiplyFilter(TemplatableFn<float> multiplier);
326 optional<float> new_value(float value) override;
327
328 protected:
330};
331
333bool value_list_matches_any(Sensor *parent, float sensor_value, const TemplatableFn<float> *values, size_t count);
334
343template<size_t N> class ValueListFilter : public Filter {
344 protected:
345 explicit ValueListFilter(std::initializer_list<TemplatableFn<float>> values) {
346 init_array_from(this->values_, values);
347 }
348
350 bool value_matches_any_(float sensor_value) {
351 return value_list_matches_any(this->parent_, sensor_value, this->values_.data(), N);
352 }
353
354 std::array<TemplatableFn<float>, N> values_{};
355};
356
358template<size_t N> class FilterOutValueFilter : public ValueListFilter<N> {
359 public:
360 explicit FilterOutValueFilter(std::initializer_list<TemplatableFn<float>> values_to_filter_out)
361 : ValueListFilter<N>(values_to_filter_out) {}
362
363 optional<float> new_value(float value) override {
364 if (this->value_matches_any_(value))
365 return {}; // Filter out
366 return value; // Pass through
367 }
368};
369
370class ThrottleFilter : public Filter {
371 public:
372 explicit ThrottleFilter(uint32_t min_time_between_inputs);
373
374 optional<float> new_value(float value) override;
375
376 protected:
379};
380
382optional<float> throttle_with_priority_new_value(Sensor *parent, float value, const TemplatableFn<float> *values,
383 size_t count, uint32_t &last_input, uint32_t min_time_between_inputs);
384
386template<size_t N> class ThrottleWithPriorityFilter : public ValueListFilter<N> {
387 public:
388 explicit ThrottleWithPriorityFilter(uint32_t min_time_between_inputs,
389 std::initializer_list<TemplatableFn<float>> prioritized_values)
390 : ValueListFilter<N>(prioritized_values), min_time_between_inputs_(min_time_between_inputs) {}
391
392 optional<float> new_value(float value) override {
393 return throttle_with_priority_new_value(this->parent_, value, this->values_.data(), N, this->last_input_,
394 this->min_time_between_inputs_);
395 }
396
397 protected:
400};
401
402// Base class for timeout filters - contains common loop logic
403class TimeoutFilterBase : public Filter, public Component {
404 public:
405 void loop() override;
406 float get_setup_priority() const override;
407
408 protected:
409 explicit TimeoutFilterBase(uint32_t time_period) : time_period_(time_period) { this->disable_loop(); }
410 virtual float get_output_value() = 0;
411
412 uint32_t time_period_; // 4 bytes (timeout duration in ms)
413 uint32_t timeout_start_time_{0}; // 4 bytes (when the timeout was started)
414 // Total base: 8 bytes
415};
416
417// Timeout filter for "last" mode - outputs the last received value after timeout
419 public:
420 explicit TimeoutFilterLast(uint32_t time_period) : TimeoutFilterBase(time_period) {}
421
422 optional<float> new_value(float value) override;
423
424 protected:
425 float get_output_value() override { return this->pending_value_; }
426 float pending_value_{0}; // 4 bytes (value to output when timeout fires)
427 // Total: 8 (base) + 4 = 12 bytes + vtable ptr + Component overhead
428};
429
430// Timeout filter with configured value - evaluates TemplatableValue after timeout
432 public:
435
436 optional<float> new_value(float value) override;
437
438 protected:
439 float get_output_value() override { return this->value_.value(); }
440 TemplatableFn<float> value_; // 4 bytes (configured output value, can be lambda)
441 // Total: 8 (base) + 4 = 12 bytes + vtable ptr + Component overhead
442};
443
444class DebounceFilter : public Filter, public Component {
445 public:
446 explicit DebounceFilter(uint32_t time_period);
447
448 optional<float> new_value(float value) override;
449
450 float get_setup_priority() const override;
451
452 protected:
454};
455
456class HeartbeatFilter : public Filter, public Component {
457 public:
458 explicit HeartbeatFilter(uint32_t time_period);
459
460 void setup() override;
461 optional<float> new_value(float value) override;
462 float get_setup_priority() const override;
463
464 void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
465
466 protected:
469 bool has_value_{false};
470 bool optimistic_{false};
471};
472
473class DeltaFilter : public Filter {
474 public:
475 explicit DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1);
476
477 void set_baseline(float (*fn)(float));
478
479 optional<float> new_value(float value) override;
480
481 protected:
482 // These values represent linear equations for the min and max values but in practice only one of a0 and a1 will be
483 // non-zero Each limit is calculated as fabs(a0 + value * a1)
484
486 // default baseline is the previous value
487 float (*baseline_)(float) = [](float last_value) { return last_value; };
488
489 float last_value_{NAN};
490};
491
493void or_filter_initialize(Filter **filters, size_t count, Sensor *parent, Filter *phi);
494optional<float> or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value);
495
497template<size_t N> class OrFilter : public Filter {
498 public:
499 explicit OrFilter(std::initializer_list<Filter *> filters) { init_array_from(this->filters_, filters); }
500
501 void initialize(Sensor *parent, Filter *next) override {
502 Filter::initialize(parent, next);
503 or_filter_initialize(this->filters_.data(), N, parent, &this->phi_);
504 }
505
506 optional<float> new_value(float value) override {
507 return or_filter_new_value(this->filters_.data(), N, value, this->has_value_);
508 }
509
510 protected:
511 class PhiNode : public Filter {
512 public:
513 PhiNode(OrFilter *or_parent) : or_parent_(or_parent) {}
514 optional<float> new_value(float value) override {
515 if (!this->or_parent_->has_value_) {
516 this->or_parent_->output(value);
517 this->or_parent_->has_value_ = true;
518 }
519 return {};
520 }
521
522 protected:
524 };
525
526 std::array<Filter *, N> filters_{};
528 bool has_value_{false};
529};
530
532optional<float> calibrate_linear_compute(const std::array<float, 3> *functions, size_t count, float value);
533
535template<size_t N> class CalibrateLinearFilter : public Filter {
536 public:
537 explicit CalibrateLinearFilter(std::initializer_list<std::array<float, 3>> linear_functions) {
538 init_array_from(this->linear_functions_, linear_functions);
539 }
540 optional<float> new_value(float value) override {
541 return calibrate_linear_compute(this->linear_functions_.data(), N, value);
542 }
543
544 protected:
545 std::array<std::array<float, 3>, N> linear_functions_{};
546};
547
549optional<float> calibrate_polynomial_compute(const float *coefficients, size_t count, float value);
550
552template<size_t N> class CalibratePolynomialFilter : public Filter {
553 public:
554 explicit CalibratePolynomialFilter(std::initializer_list<float> coefficients) {
555 init_array_from(this->coefficients_, coefficients);
556 }
557 optional<float> new_value(float value) override {
558 return calibrate_polynomial_compute(this->coefficients_.data(), N, value);
559 }
560
561 protected:
562 std::array<float, N> coefficients_{};
563};
564
565class ClampFilter : public Filter {
566 public:
567 ClampFilter(float min, float max, bool ignore_out_of_range);
568 optional<float> new_value(float value) override;
569
570 protected:
571 float min_{NAN};
572 float max_{NAN};
574};
575
576class RoundFilter : public Filter {
577 public:
578 explicit RoundFilter(uint8_t precision);
579 optional<float> new_value(float value) override;
580
581 protected:
582 uint8_t precision_;
583};
584
586 public:
587 explicit RoundMultipleFilter(float multiple);
588 optional<float> new_value(float value) override;
589
590 protected:
592};
593
595 public:
596 ToNTCResistanceFilter(double a, double b, double c) : a_(a), b_(b), c_(c) {}
597 optional<float> new_value(float value) override;
598
599 protected:
600 double a_;
601 double b_;
602 double c_;
603};
604
606 public:
607 ToNTCTemperatureFilter(double a, double b, double c) : a_(a), b_(b), c_(c) {}
608 optional<float> new_value(float value) override;
609
610 protected:
611 double a_;
612 double b_;
613 double c_;
614};
615
621class StreamingFilter : public Filter {
622 public:
623 StreamingFilter(uint16_t window_size, uint16_t send_first_at);
624
625 optional<float> new_value(float value) final;
626
627 protected:
629 virtual void process_value(float value) = 0;
630
632 virtual float compute_batch_result() = 0;
633
635 virtual void reset_batch() = 0;
636
637 uint16_t window_size_;
638 uint16_t count_{0};
640 bool first_send_{true};
641};
642
648 public:
650
651 protected:
652 void process_value(float value) override;
653 float compute_batch_result() override;
654 void reset_batch() override;
655
656 float current_min_{NAN};
657};
658
664 public:
666
667 protected:
668 void process_value(float value) override;
669 float compute_batch_result() override;
670 void reset_batch() override;
671
672 float current_max_{NAN};
673};
674
680 public:
682
683 protected:
684 void process_value(float value) override;
685 float compute_batch_result() override;
686 void reset_batch() override;
687
688 float sum_{0.0f};
689 size_t valid_count_{0};
690};
691
692} // namespace esphome::sensor
693
694#endif // USE_SENSOR_FILTER
void disable_loop()
Disable this component's loop.
Fixed-capacity circular buffer - allocates once at runtime, never reallocates.
Definition helpers.h:383
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:522
Function-pointer-only templatable storage (4 bytes on 32-bit).
Definition automation.h:40
T value(X... x) const
Definition automation.h:79
N is set by code generation to match the exact number of calibration segments.
Definition filter.h:535
CalibrateLinearFilter(std::initializer_list< std::array< float, 3 > > linear_functions)
Definition filter.h:537
std::array< std::array< float, 3 >, N > linear_functions_
Definition filter.h:545
optional< float > new_value(float value) override
Definition filter.h:540
N is set by code generation to match the exact number of polynomial coefficients.
Definition filter.h:552
optional< float > new_value(float value) override
Definition filter.h:557
CalibratePolynomialFilter(std::initializer_list< float > coefficients)
Definition filter.h:554
std::array< float, N > coefficients_
Definition filter.h:562
ClampFilter(float min, float max, bool ignore_out_of_range)
Definition filter.cpp:406
optional< float > new_value(float value) override
Definition filter.cpp:408
optional< float > new_value(float value) override
Definition filter.cpp:352
float get_setup_priority() const override
Definition filter.cpp:359
DebounceFilter(uint32_t time_period)
Definition filter.cpp:358
void set_baseline(float(*fn)(float))
Definition filter.cpp:276
DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1)
Definition filter.cpp:273
optional< float > new_value(float value) override
Definition filter.cpp:278
float(* baseline_)(float)
Definition filter.h:487
Simple exponential moving average filter.
Definition filter.h:236
optional< float > new_value(float value) override
Definition filter.cpp:152
ExponentialMovingAverageFilter(float alpha, uint16_t send_every, uint16_t send_first_at)
Definition filter.cpp:150
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:28
virtual void initialize(Sensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
Definition filter.cpp:37
void input(float value)
Definition filter.cpp:22
A simple filter that only forwards the filter chain if it doesn't receive value_to_filter_out.
Definition filter.h:358
FilterOutValueFilter(std::initializer_list< TemplatableFn< float > > values_to_filter_out)
Definition filter.h:360
optional< float > new_value(float value) override
Definition filter.h:363
HeartbeatFilter(uint32_t time_period)
Definition filter.cpp:362
optional< float > new_value(float value) override
Definition filter.cpp:364
void set_optimistic(bool optimistic)
Definition filter.h:464
float get_setup_priority() const override
Definition filter.cpp:386
This class allows for creation of simple template filters.
Definition filter.h:283
const lambda_filter_t & get_lambda_filter() const
Definition filter.cpp:206
LambdaFilter(lambda_filter_t lambda_filter)
Definition filter.cpp:205
lambda_filter_t lambda_filter_
Definition filter.h:293
void set_lambda_filter(const lambda_filter_t &lambda_filter)
Definition filter.cpp:207
optional< float > new_value(float value) override
Definition filter.cpp:209
Simple max filter.
Definition filter.h:194
float compute_result() override
Definition filter.cpp:134
Simple median filter.
Definition filter.h:136
float compute_result() override
Definition filter.cpp:78
Simple min filter.
Definition filter.h:174
float compute_result() override
Definition filter.cpp:131
Base class for Min/Max filters.
Definition filter.h:74
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
A simple filter that multiplies to each value it receives by multiplier.
Definition filter.h:323
TemplatableFn< float > multiplier_
Definition filter.h:329
optional< float > new_value(float value) override
Definition filter.cpp:223
MultiplyFilter(TemplatableFn< float > multiplier)
Definition filter.cpp:221
A simple filter that adds offset to each value it receives.
Definition filter.h:312
optional< float > new_value(float value) override
Definition filter.cpp:218
TemplatableFn< float > offset_
Definition filter.h:319
OffsetFilter(TemplatableFn< float > offset)
Definition filter.cpp:216
optional< float > new_value(float value) override
Definition filter.h:514
PhiNode(OrFilter *or_parent)
Definition filter.h:513
N is set by code generation to match the exact number of filters configured in YAML.
Definition filter.h:497
std::array< Filter *, N > filters_
Definition filter.h:526
void initialize(Sensor *parent, Filter *next) override
Definition filter.h:501
optional< float > new_value(float value) override
Definition filter.h:506
OrFilter(std::initializer_list< Filter * > filters)
Definition filter.h:499
Simple quantile filter.
Definition filter.h:112
float compute_result() override
Definition filter.cpp:117
void set_quantile(float quantile)
Definition filter.h:125
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
Definition filter.cpp:114
RoundFilter(uint8_t precision)
Definition filter.cpp:425
optional< float > new_value(float value) override
Definition filter.cpp:426
optional< float > new_value(float value) override
Definition filter.cpp:435
Base-class for all sensors.
Definition sensor.h:47
SkipInitialFilter(size_t num_to_ignore)
Construct a SkipInitialFilter.
Definition filter.cpp:101
optional< float > new_value(float value) override
Definition filter.cpp:102
Base class for filters that use a sliding window of values.
Definition filter.h:54
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:49
SlidingWindowFilter(uint16_t window_size, uint16_t send_every, uint16_t send_first_at)
Definition filter.cpp:44
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
Simple sliding window moving average filter.
Definition filter.h:215
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:64
Optimized lambda filter for stateless lambdas (no capture).
Definition filter.h:301
optional< float >(* lambda_filter_)(float)
Definition filter.h:308
optional< float > new_value(float value) override
Definition filter.h:305
StatelessLambdaFilter(optional< float >(*lambda_filter)(float))
Definition filter.h:303
Base class for streaming filters (batch windows where window_size == send_every).
Definition filter.h:621
StreamingFilter(uint16_t window_size, uint16_t send_first_at)
Definition filter.cpp:466
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:469
Streaming max filter for batch windows (window_size == send_every).
Definition filter.h:663
void process_value(float value) override
Definition filter.cpp:509
float compute_batch_result() override
Definition filter.cpp:516
Streaming min filter for batch windows (window_size == send_every).
Definition filter.h:647
float compute_batch_result() override
Definition filter.cpp:504
void process_value(float value) override
Definition filter.cpp:497
Streaming moving average filter for batch windows (window_size == send_every).
Definition filter.h:679
void process_value(float value) override
Definition filter.cpp:521
Simple throttle average filter.
Definition filter.h:257
optional< float > new_value(float value) override
Definition filter.cpp:178
ThrottleAverageFilter(uint32_t time_period)
Definition filter.cpp:176
float get_setup_priority() const override
Definition filter.cpp:202
ThrottleFilter(uint32_t min_time_between_inputs)
Definition filter.cpp:250
optional< float > new_value(float value) override
Definition filter.cpp:251
Same as 'throttle' but will immediately publish values contained in value_to_prioritize.
Definition filter.h:386
optional< float > new_value(float value) override
Definition filter.h:392
ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, std::initializer_list< TemplatableFn< float > > prioritized_values)
Definition filter.h:388
TimeoutFilterBase(uint32_t time_period)
Definition filter.h:409
float get_setup_priority() const override
Definition filter.cpp:327
TimeoutFilterConfigured(uint32_t time_period, const TemplatableFn< float > &new_value)
Definition filter.h:433
TemplatableFn< float > value_
Definition filter.h:440
optional< float > new_value(float value) override
Definition filter.cpp:342
float get_output_value() override
Definition filter.h:425
TimeoutFilterLast(uint32_t time_period)
Definition filter.h:420
optional< float > new_value(float value) override
Definition filter.cpp:330
optional< float > new_value(float value) override
Definition filter.cpp:442
ToNTCResistanceFilter(double a, double b, double c)
Definition filter.h:596
optional< float > new_value(float value) override
Definition filter.cpp:455
ToNTCTemperatureFilter(double a, double b, double c)
Definition filter.h:607
Base class for filters that compare sensor values against a fixed list of configured values.
Definition filter.h:343
ValueListFilter(std::initializer_list< TemplatableFn< float > > values)
Definition filter.h:345
bool value_matches_any_(float sensor_value)
Check if sensor value matches any configured value (with accuracy rounding)
Definition filter.h:350
std::array< TemplatableFn< float >, N > values_
Definition filter.h:354
optional< float > throttle_with_priority_new_value(Sensor *parent, float value, const TemplatableFn< float > *values, size_t count, uint32_t &last_input, uint32_t min_time_between_inputs)
Non-template helper for ThrottleWithPriorityFilter (implementation in filter.cpp)
Definition filter.cpp:261
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:299
bool value_list_matches_any(Sensor *parent, float sensor_value, const TemplatableFn< float > *values, size_t count)
Non-template helper for value matching (implementation in filter.cpp)
Definition filter.cpp:226
optional< float > calibrate_polynomial_compute(const float *coefficients, size_t count, float value)
Non-template helper for polynomial calibration (implementation in filter.cpp)
Definition filter.cpp:396
optional< float > calibrate_linear_compute(const std::array< float, 3 > *functions, size_t count, float value)
Non-template helper for linear calibration (implementation in filter.cpp)
Definition filter.cpp:388
std::function< optional< float >(float)> lambda_filter_t
Definition filter.h:274
optional< float > or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value)
Definition filter.cpp:306
void init_array_from(std::array< T, N > &dest, std::initializer_list< T > src)
Initialize a std::array from an initializer_list.
Definition helpers.h:505
static void uint32_t