2#ifdef USE_SENSOR_FILTER
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)) {
29 ESP_LOGVV(TAG,
"Filter(%p)::input(%f)",
this, value);
35 if (this->
next_ ==
nullptr) {
36 ESP_LOGVV(TAG,
"Filter(%p)::output(%f) -> SENSOR",
this, value);
39 ESP_LOGVV(TAG,
"Filter(%p)::output(%f) -> %p",
this, value, this->
next_);
44 ESP_LOGVV(TAG,
"Filter(%p)::initialize(parent=%p next=%p)",
this, parent,
next);
51 : send_every_(send_every), send_at_(send_every - send_first_at) {
63 ESP_LOGVV(TAG,
"SlidingWindowFilter(%p)::new_value(%f) SENDING %f",
this, value, result);
90 size_t mid =
size / 2;
94 std::nth_element(values.
begin(), values.
begin() + mid, values.
end());
99 std::nth_element(values.
begin(), values.
begin() + mid, values.
end());
100 float upper = values[mid];
102 float lower = *std::max_element(values.
begin(), values.
begin() + mid);
103 return (lower + upper) / 2.0f;
111 ESP_LOGV(TAG,
"SkipInitialFilter(%p)::new_value(%f) SKIPPING, %zu left",
this, value,
num_to_ignore_);
115 ESP_LOGV(TAG,
"SkipInitialFilter(%p)::new_value(%f) SENDING",
this, value);
128 size_t position = ceilf(values.
size() * this->quantile_) - 1;
129 ESP_LOGVV(TAG,
"QuantileFilter(%p)::position: %zu/%zu",
this,
position + 1, values.
size());
145 size_t valid_count = 0;
146 for (
float v : this->
window_) {
147 if (!std::isnan(v)) {
152 return valid_count ? sum / valid_count : NAN;
157 : alpha_(alpha), send_every_(send_every), send_at_(send_every - send_first_at) {}
159 if (!std::isnan(value)) {
168 const float average = std::isnan(value) ? value : this->
accumulator_;
169 ESP_LOGVV(TAG,
"ExponentialMovingAverageFilter(%p)::new_value(%f) -> %f",
this, value, average);
172 ESP_LOGVV(TAG,
"ExponentialMovingAverageFilter(%p)::new_value(%f) SENDING %f",
this, value, average);
183 ESP_LOGVV(TAG,
"ThrottleAverageFilter(%p)::new_value(value=%f)",
this, value);
184 if (std::isnan(value)) {
195 ESP_LOGVV(TAG,
"ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)",
this, this->
sum_, this->
n_);
215 ESP_LOGVV(TAG,
"LambdaFilter(%p)::new_value(%f) -> %f",
this, value, it.value_or(INFINITY));
232 float accuracy_mult =
pow10_int(accuracy);
233 float rounded_sensor = roundf(accuracy_mult * sensor_value);
236 float fv = v->value();
239 if (std::isnan(fv)) {
240 if (std::isnan(sensor_value))
246 if (roundf(accuracy_mult * fv) == rounded_sensor)
277 : min_time_between_inputs_(min_time_between_inputs) {}
286 : min_a0_(min_a0), min_a1_(min_a1), max_a0_(max_a0), max_a1_(max_a1) {}
291 const bool no_value = std::isnan(value);
292 const bool no_reference = std::isnan(this->
last_value_);
293 if (no_value && no_reference)
295 if (no_value || no_reference) {
303 float delta = fabsf(value -
ref);
305 if (delta > min && delta <= max) {
314 for (
size_t i = 0; i <
count; i++) {
322 for (
size_t i = 0; i <
count; i++)
323 filters[i]->input(value);
395 ESP_LOGVV(TAG,
"HeartbeatFilter(%p)::new_value(value=%f)",
this, value);
408 ESP_LOGVV(TAG,
"HeartbeatFilter(%p)::interval(has_value=%s, last_input=%f)",
this, YESNO(this->
has_value_),
420 for (
const auto *function = this->
functions_;; function++) {
421 if (!std::isfinite((*function)[2]) || value < (*function)[2])
422 return (value * (*function)[0]) + (*function)[1];
430 for (
size_t i = 1; i <=
count; i++) {
438 : min_(min), max_(max), ignore_out_of_range_(ignore_out_of_range) {}
440 if (std::isfinite(this->
min_) && !(value >= this->
min_)) {
447 if (std::isfinite(this->
max_) && !(value <= this->
max_)) {
458 if (std::isfinite(value)) {
460 return roundf(accuracy_mult * value) / accuracy_mult;
467 if (std::isfinite(value)) {
468 return value - remainderf(value, this->
multiple_);
474 if (!std::isfinite(value)) {
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));
487 if (!std::isfinite(value)) {
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);
497static constexpr float MAGNUS_B = 17.67f, MAGNUS_C = 243.5f;
499static bool rh_correction_temp_in_band(
float t) {
return t >= -40.0f && t <= 50.0f; }
504 ESP_LOGW(TAG,
"RHCorrectionFilter(%p): no temperature yet, passing humidity through uncorrected",
this);
515 const float tnc = tc - offset;
517 if (std::isnan(tnc)) {
519 ESP_LOGW(TAG,
"RHCorrectionFilter(%p): temperature or offset is NaN, dropping humidity updates",
this);
524 if (!rh_correction_temp_in_band(tc) || !rh_correction_temp_in_band(tnc)) {
526 ESP_LOGW(TAG,
"RHCorrectionFilter(%p): Temperature out of range -40..50 °C. Tc=%f Tnc=%f",
this, tc, tnc);
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);
540 : window_size_(window_size), send_first_at_(send_first_at) {}
549 bool should_send =
false;
562 ESP_LOGVV(TAG,
"StreamingFilter(%p)::new_value(%f) SENDING %f",
this, value, result);
572 if (!std::isnan(value)) {
584 if (!std::isnan(value)) {
596 if (!std::isnan(value)) {
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.
void disable_loop()
Disable this component's loop.
void push_overwrite(const T &value)
Push a value, overwriting the oldest if full.
void init(index_type capacity)
Allocate capacity - can only be called once.
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Function-pointer-only templatable storage (4 bytes on 32-bit).
optional< float > new_value(float value) override
const std::array< float, 3 > * functions_
const float * coefficients_
optional< float > new_value(float value) override
bool ignore_out_of_range_
ClampFilter(float min, float max, bool ignore_out_of_range)
optional< float > new_value(float value) override
optional< float > new_value(float value) override
DebounceFilter(uint32_t time_period)
void set_baseline(float(*fn)(float))
DeltaFilter(float min_a0, float min_a1, float max_a0, float max_a1)
optional< float > new_value(float value) override
float(* baseline_)(float)
optional< float > new_value(float value) override
ExponentialMovingAverageFilter(float alpha, uint16_t send_every, uint16_t send_first_at)
Apply a filter to sensor values such as moving average.
virtual optional< float > new_value(float value)=0
This will be called every time the filter receives a new value.
virtual void initialize(Sensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
HeartbeatFilter(uint32_t time_period)
optional< float > new_value(float value) override
void initialize(Sensor *parent, Filter *next) override
const lambda_filter_t & get_lambda_filter() const
LambdaFilter(lambda_filter_t lambda_filter)
lambda_filter_t lambda_filter_
void set_lambda_filter(const lambda_filter_t &lambda_filter)
optional< float > new_value(float value) override
float compute_result() override
float compute_result() override
float find_extremum_()
Helper to find min or max value in window, skipping NaN values Usage: find_extremum_<std::less<float>...
TemplatableFn< float > multiplier_
optional< float > new_value(float value) override
MultiplyFilter(TemplatableFn< float > multiplier)
optional< float > new_value(float value) override
TemplatableFn< float > offset_
OffsetFilter(TemplatableFn< float > offset)
float compute_result() override
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
TemplatableFn< float > temperature_offset_
optional< float > new_value(float value) override
const Sensor * temperature_sensor_
RoundFilter(uint8_t precision)
optional< float > new_value(float value) override
optional< float > new_value(float value) override
RoundMultipleFilter(float multiple)
Base-class for all sensors.
void internal_send_state_to_frontend(float state)
float get_state() const
Getter-syntax for .state.
int8_t get_accuracy_decimals()
Get the accuracy in decimals, using the manual override if set.
SkipInitialFilter(size_t num_to_ignore)
Construct a SkipInitialFilter.
optional< float > new_value(float value) override
FixedRingBuffer< float > window_
Sliding window ring buffer - automatically overwrites oldest values when full.
optional< float > new_value(float value) final
SlidingWindowFilter(uint16_t window_size, uint16_t send_every, uint16_t send_first_at)
uint16_t send_every_
Send result every N values.
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.
float compute_result() override
Base class for filters that need a sorted window (Median, Quantile).
FixedVector< float > get_window_values_()
Helper to get non-NaN values from the window (not sorted - caller will use nth_element) Returns empty...
StreamingFilter(uint16_t window_size, uint16_t send_first_at)
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
void reset_batch() override
void process_value(float value) override
float compute_batch_result() override
void reset_batch() override
float compute_batch_result() override
void process_value(float value) override
float compute_batch_result() override
void reset_batch() override
void process_value(float value) override
optional< float > new_value(float value) override
ThrottleAverageFilter(uint32_t time_period)
void initialize(Sensor *parent, Filter *next) override
uint32_t min_time_between_inputs_
ThrottleFilter(uint32_t min_time_between_inputs)
optional< float > new_value(float value) override
optional< float > new_value(float value) override
uint32_t min_time_between_inputs_
uint32_t min_time_between_inputs_
optional< float > new_value(float value) override
ThrottleWithPriorityNanFilter(uint32_t min_time_between_inputs)
uint32_t timeout_start_time_
float get_setup_priority() const override
virtual float get_output_value()=0
optional< float > new_value(float value) override
optional< float > new_value(float value) override
optional< float > new_value(float value) override
optional< float > new_value(float value) override
bool value_matches_any_(float sensor_value)
Check if sensor value matches any configured value (with accuracy rounding)
const TemplatableFn< float > * values_
std::vector< uint8_t > & out
void or_filter_initialize(Filter **filters, size_t count, Sensor *parent, Filter *phi)
Non-template helpers for OrFilter (implementation in filter.cpp)
ESPHOME_LOG_TAG(TAG, "sensor.filter")
std::function< optional< float >(float)> lambda_filter_t
optional< float > or_filter_new_value(Filter **filters, size_t count, float value, bool &has_value)
constexpr float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
uint32_t IRAM_ATTR HOT millis()
constexpr float fahrenheit_to_celsius(float value)
Convert degrees Fahrenheit to degrees Celsius.
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.