11static const char *
const TAG =
"sensor.filter";
15 ESP_LOGVV(TAG,
"Filter(%p)::input(%f)",
this, value);
21 if (this->
next_ ==
nullptr) {
22 ESP_LOGVV(TAG,
"Filter(%p)::output(%f) -> SENSOR",
this, value);
25 ESP_LOGVV(TAG,
"Filter(%p)::output(%f) -> %p",
this, value, this->
next_);
30 ESP_LOGVV(TAG,
"Filter(%p)::initialize(parent=%p next=%p)",
this, parent, next);
37 : window_size_(window_size), send_every_(send_every), send_at_(send_every - send_first_at) {
61 ESP_LOGVV(TAG,
"SlidingWindowFilter(%p)::new_value(%f) SENDING %f",
this, value, result);
88 size_t size = values.
size();
89 size_t mid = size / 2;
93 std::nth_element(values.
begin(), values.
begin() + mid, values.
end());
98 std::nth_element(values.
begin(), values.
begin() + mid, values.
end());
99 float upper = values[mid];
101 float lower = *std::max_element(values.
begin(), values.
begin() + mid);
102 return (lower + upper) / 2.0f;
110 ESP_LOGV(TAG,
"SkipInitialFilter(%p)::new_value(%f) SKIPPING, %zu left",
this, value,
num_to_ignore_);
114 ESP_LOGV(TAG,
"SkipInitialFilter(%p)::new_value(%f) SENDING",
this, value);
127 size_t position = ceilf(values.
size() * this->quantile_) - 1;
128 ESP_LOGVV(TAG,
"QuantileFilter(%p)::position: %zu/%zu",
this,
position + 1, values.
size());
144 size_t valid_count = 0;
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);
185 ESP_LOGVV(TAG,
"ThrottleAverageFilter(%p)::new_value(value=%f)",
this, value);
186 if (std::isnan(value)) {
196 ESP_LOGVV(TAG,
"ThrottleAverageFilter(%p)::interval(sum=%f, n=%i)",
this, this->
sum_, this->
n_);
217 ESP_LOGVV(TAG,
"LambdaFilter(%p)::new_value(%f) -> %f",
this, value, it.value_or(INFINITY));
236 float accuracy_mult = powf(10.0f, accuracy);
237 float rounded_sensor = roundf(accuracy_mult * sensor_value);
239 for (
auto &filter_value : this->
values_) {
240 float fv = filter_value.value();
243 if (std::isnan(fv)) {
244 if (std::isnan(sensor_value))
250 if (roundf(accuracy_mult * fv) == rounded_sensor)
281 :
ValueListFilter(prioritized_values), min_time_between_inputs_(min_time_between_inputs) {}
296 : delta_(delta), current_delta_(delta), last_value_(NAN), percentage_mode_(percentage_mode) {}
298 if (std::isnan(value)) {
320 if (!this->or_parent_->has_value_) {
321 this->or_parent_->output(value);
322 this->or_parent_->has_value_ =
true;
330 filter->input(value);
336 for (
auto *filter : this->
filters_) {
337 filter->initialize(parent, &this->
phi_);
344 if (this->value_.has_value()) {
345 this->set_timeout(
"timeout", this->time_period_, [
this]() { this->
output(this->value_.value().value()); });
347 this->set_timeout(
"timeout", this->time_period_, [
this, value]() { this->
output(value); });
354 : time_period_(time_period), value_(new_value) {}
371 ESP_LOGVV(TAG,
"HeartbeatFilter(%p)::new_value(value=%f)",
this, value);
383 ESP_LOGVV(TAG,
"HeartbeatFilter(%p)::interval(has_value=%s, last_input=%f)",
this, YESNO(this->
has_value_),
395 : linear_functions_(linear_functions) {}
399 if (!std::isfinite(f[2]) || value < f[2])
400 return (value * f[0]) + f[1];
406 : coefficients_(coefficients) {}
412 res +=
x * coefficient;
419 : min_(min), max_(max), ignore_out_of_range_(ignore_out_of_range) {}
421 if (std::isfinite(value)) {
422 if (std::isfinite(this->
min_) && value < this->
min_) {
430 if (std::isfinite(this->
max_) && value > this->
max_) {
443 if (std::isfinite(value)) {
444 float accuracy_mult = powf(10.0f, this->
precision_);
445 return roundf(accuracy_mult * value) / accuracy_mult;
452 if (std::isfinite(value)) {
453 return value - remainderf(value, this->
multiple_);
459 if (!std::isfinite(value)) {
464 double t = value + k;
465 double y = (this->
a_ - 1 / (t)) / (2 * this->
c_);
466 double x = sqrt(pow(this->
b_ / (3 * this->
c_), 3) + y *
y);
467 double resistance = exp(pow(
x -
y, 1 / 3.0) - pow(
x +
y, 1 / 3.0));
472 if (!std::isfinite(value)) {
475 double lr = log(
double(value));
476 double v = this->
a_ + this->
b_ * lr + this->
c_ * lr * lr * lr;
477 double temp = float(1.0 / v - 273.15);
483 : window_size_(window_size), send_first_at_(send_first_at) {}
492 bool should_send =
false;
505 ESP_LOGVV(TAG,
"StreamingFilter(%p)::new_value(%f) SENDING %f",
this, value, result);
515 if (!std::isnan(value)) {
527 if (!std::isnan(value)) {
539 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 set_interval(const std::string &name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
FixedVector< std::array< float, 3 > > linear_functions_
optional< float > new_value(float value) override
CalibrateLinearFilter(std::initializer_list< std::array< float, 3 > > linear_functions)
CalibratePolynomialFilter(std::initializer_list< float > coefficients)
optional< float > new_value(float value) override
FixedVector< float > coefficients_
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
float get_setup_priority() const override
DebounceFilter(uint32_t time_period)
DeltaFilter(float delta, bool percentage_mode)
optional< float > new_value(float value) override
void set_send_every(size_t send_every)
optional< float > new_value(float value) override
ExponentialMovingAverageFilter(float alpha, size_t send_every, size_t send_first_at)
void set_alpha(float alpha)
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.
optional< float > new_value(float value) override
FilterOutValueFilter(std::initializer_list< TemplatableValue< float > > values_to_filter_out)
HeartbeatFilter(uint32_t time_period)
optional< float > new_value(float value) override
float get_setup_priority() const 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>...
optional< float > new_value(float value) override
MultiplyFilter(TemplatableValue< float > multiplier)
TemplatableValue< float > multiplier_
optional< float > new_value(float value) override
OffsetFilter(TemplatableValue< float > offset)
TemplatableValue< float > offset_
optional< float > new_value(float value) override
PhiNode(OrFilter *or_parent)
OrFilter(std::initializer_list< Filter * > filters)
optional< float > new_value(float value) override
void initialize(Sensor *parent, Filter *next) override
FixedVector< Filter * > filters_
float compute_result() override
QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
Construct a QuantileFilter.
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)
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
size_t window_head_
Index where next value will be written.
size_t window_size_
Maximum window size.
optional< float > new_value(float value) final
size_t window_count_
Number of valid values in window (0 to window_size_)
FixedVector< float > window_
Access the sliding window values (ring buffer implementation) Use: for (size_t i = 0; i < window_coun...
size_t send_at_
Counter for send_every.
size_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.
SlidingWindowFilter(size_t window_size, size_t send_every, size_t send_first_at)
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...
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)
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)
float get_setup_priority() const 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
ThrottleWithPriorityFilter(uint32_t min_time_between_inputs, std::initializer_list< TemplatableValue< float > > prioritized_values)
uint32_t min_time_between_inputs_
optional< float > new_value(float value) override
TimeoutFilter(uint32_t time_period)
float get_setup_priority() const override
optional< float > new_value(float value) override
optional< float > new_value(float value) override
Base class for filters that compare sensor values against a list of configured values.
ValueListFilter(std::initializer_list< TemplatableValue< float > > values)
FixedVector< TemplatableValue< float > > values_
bool value_matches_any_(float sensor_value)
Check if sensor value matches any configured value (with accuracy rounding)
std::function< optional< float >(float)> lambda_filter_t
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Providing packet encoding functions for exchanging data with a remote host.
Application App
Global storage of Application pointer - only one Application can exist.