From 25fb288016645120ebdacce4bafd9d2016e86324 Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Thu, 16 Mar 2023 09:20:18 +1100 Subject: [PATCH] Update the delta filter to take a percentage value as well as an absolute value (#4391) --- esphome/components/sensor/__init__.py | 16 ++++++++++++++-- esphome/components/sensor/filter.cpp | 14 +++++++++----- esphome/components/sensor/filter.h | 6 ++++-- esphome/config_validation.py | 2 +- tests/test1.yaml | 1 + 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index d3cb39c2f6..821e0afac0 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -466,9 +466,21 @@ async def lambda_filter_to_code(config, filter_id): return cg.new_Pvariable(filter_id, lambda_) -@FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_) +def validate_delta(config): + try: + return (cv.positive_float(config), False) + except cv.Invalid: + pass + try: + return (cv.percentage(config), True) + except cv.Invalid: + pass + raise cv.Invalid("Delta filter requires a positive number or percentage value.") + + +@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta) async def delta_filter_to_code(config, filter_id): - return cg.new_Pvariable(filter_id, config) + return cg.new_Pvariable(filter_id, *config) @FILTER_REGISTRY.register("or", OrFilter, validate_filters) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 7a2c98109c..bf65ac590f 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -315,19 +315,23 @@ optional ThrottleFilter::new_value(float value) { } // DeltaFilter -DeltaFilter::DeltaFilter(float min_delta) : min_delta_(min_delta), last_value_(NAN) {} +DeltaFilter::DeltaFilter(float delta, bool percentage_mode) + : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} optional DeltaFilter::new_value(float value) { if (std::isnan(value)) { if (std::isnan(this->last_value_)) { return {}; } else { + if (this->percentage_mode_) { + this->current_delta_ = fabsf(value * this->delta_); + } return this->last_value_ = value; } } - if (std::isnan(this->last_value_)) { - return this->last_value_ = value; - } - if (fabsf(value - this->last_value_) >= this->min_delta_) { + if (std::isnan(this->last_value_) || fabsf(value - this->last_value_) >= this->current_delta_) { + if (this->percentage_mode_) { + this->current_delta_ = fabsf(value * this->delta_); + } return this->last_value_ = value; } return {}; diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index c17d14583b..b560545b76 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -325,12 +325,14 @@ class HeartbeatFilter : public Filter, public Component { class DeltaFilter : public Filter { public: - explicit DeltaFilter(float min_delta); + explicit DeltaFilter(float delta, bool percentage_mode); optional new_value(float value) override; protected: - float min_delta_; + float delta_; + float current_delta_; + bool percentage_mode_; float last_value_{NAN}; }; diff --git a/esphome/config_validation.py b/esphome/config_validation.py index a46d14053b..469b7031f6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1097,7 +1097,7 @@ def possibly_negative_percentage(value): if isinstance(value, str): try: if value.endswith("%"): - has_percent_sign = False + has_percent_sign = True value = float(value[:-1].rstrip()) / 100.0 else: value = float(value) diff --git a/tests/test1.yaml b/tests/test1.yaml index ef389ea712..0ff8b60ea2 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -392,6 +392,7 @@ sensor: - heartbeat: 5s - debounce: 0.1s - delta: 5.0 + - delta: 1% - or: - throttle: 1s - delta: 5.0