[sensor] Make some values templatable (#7735)

This commit is contained in:
Clyde Stubbs 2024-11-11 12:18:05 +11:00 committed by GitHub
parent c35240ca32
commit d885d65c9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 36 deletions

View file

@ -335,19 +335,28 @@ def sensor_schema(
return SENSOR_SCHEMA.extend(schema)
@FILTER_REGISTRY.register("offset", OffsetFilter, cv.float_)
@FILTER_REGISTRY.register("offset", OffsetFilter, cv.templatable(cv.float_))
async def offset_filter_to_code(config, filter_id):
return cg.new_Pvariable(filter_id, config)
template_ = await cg.templatable(config, [], float)
return cg.new_Pvariable(filter_id, template_)
@FILTER_REGISTRY.register("multiply", MultiplyFilter, cv.float_)
@FILTER_REGISTRY.register("multiply", MultiplyFilter, cv.templatable(cv.float_))
async def multiply_filter_to_code(config, filter_id):
return cg.new_Pvariable(filter_id, config)
template_ = await cg.templatable(config, [], float)
return cg.new_Pvariable(filter_id, template_)
@FILTER_REGISTRY.register("filter_out", FilterOutValueFilter, cv.float_)
@FILTER_REGISTRY.register(
"filter_out",
FilterOutValueFilter,
cv.Any(cv.templatable(cv.float_), [cv.templatable(cv.float_)]),
)
async def filter_out_filter_to_code(config, filter_id):
return cg.new_Pvariable(filter_id, config)
if not isinstance(config, list):
config = [config]
template_ = [await cg.templatable(x, [], float) for x in config]
return cg.new_Pvariable(filter_id, template_)
QUANTILE_SCHEMA = cv.All(
@ -573,7 +582,7 @@ async def heartbeat_filter_to_code(config, filter_id):
TIMEOUT_SCHEMA = cv.maybe_simple_value(
{
cv.Required(CONF_TIMEOUT): cv.positive_time_period_milliseconds,
cv.Optional(CONF_VALUE, default="nan"): cv.float_,
cv.Optional(CONF_VALUE, default="nan"): cv.templatable(cv.float_),
},
key=CONF_TIMEOUT,
)
@ -581,7 +590,8 @@ TIMEOUT_SCHEMA = cv.maybe_simple_value(
@FILTER_REGISTRY.register("timeout", TimeoutFilter, TIMEOUT_SCHEMA)
async def timeout_filter_to_code(config, filter_id):
var = cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], config[CONF_VALUE])
template_ = await cg.templatable(config[CONF_VALUE], [], float)
var = cg.new_Pvariable(filter_id, config[CONF_TIMEOUT], template_)
await cg.register_component(var, {})
return var

View file

@ -288,36 +288,36 @@ optional<float> LambdaFilter::new_value(float value) {
}
// OffsetFilter
OffsetFilter::OffsetFilter(float offset) : offset_(offset) {}
OffsetFilter::OffsetFilter(TemplatableValue<float> offset) : offset_(std::move(offset)) {}
optional<float> OffsetFilter::new_value(float value) { return value + this->offset_; }
optional<float> OffsetFilter::new_value(float value) { return value + this->offset_.value(); }
// MultiplyFilter
MultiplyFilter::MultiplyFilter(float multiplier) : multiplier_(multiplier) {}
MultiplyFilter::MultiplyFilter(TemplatableValue<float> multiplier) : multiplier_(std::move(multiplier)) {}
optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_; }
optional<float> MultiplyFilter::new_value(float value) { return value * this->multiplier_.value(); }
// FilterOutValueFilter
FilterOutValueFilter::FilterOutValueFilter(float value_to_filter_out) : value_to_filter_out_(value_to_filter_out) {}
FilterOutValueFilter::FilterOutValueFilter(std::vector<TemplatableValue<float>> values_to_filter_out)
: values_to_filter_out_(std::move(values_to_filter_out)) {}
optional<float> FilterOutValueFilter::new_value(float value) {
if (std::isnan(this->value_to_filter_out_)) {
if (std::isnan(value)) {
return {};
} else {
return value;
int8_t accuracy = this->parent_->get_accuracy_decimals();
float accuracy_mult = powf(10.0f, accuracy);
for (auto filter_value : this->values_to_filter_out_) {
if (std::isnan(filter_value.value())) {
if (std::isnan(value)) {
return {};
}
continue;
}
} else {
int8_t accuracy = this->parent_->get_accuracy_decimals();
float accuracy_mult = powf(10.0f, accuracy);
float rounded_filter_out = roundf(accuracy_mult * this->value_to_filter_out_);
float rounded_filter_out = roundf(accuracy_mult * filter_value.value());
float rounded_value = roundf(accuracy_mult * value);
if (rounded_filter_out == rounded_value) {
return {};
} else {
return value;
}
}
return value;
}
// ThrottleFilter
@ -383,11 +383,12 @@ void OrFilter::initialize(Sensor *parent, Filter *next) {
// TimeoutFilter
optional<float> TimeoutFilter::new_value(float value) {
this->set_timeout("timeout", this->time_period_, [this]() { this->output(this->value_); });
this->set_timeout("timeout", this->time_period_, [this]() { this->output(this->value_.value()); });
return value;
}
TimeoutFilter::TimeoutFilter(uint32_t time_period, float new_value) : time_period_(time_period), value_(new_value) {}
TimeoutFilter::TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value)
: time_period_(time_period), value_(std::move(new_value)) {}
float TimeoutFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
// DebounceFilter

View file

@ -5,6 +5,7 @@
#include <vector>
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/automation.h"
namespace esphome {
namespace sensor {
@ -273,34 +274,33 @@ class LambdaFilter : public Filter {
/// A simple filter that adds `offset` to each value it receives.
class OffsetFilter : public Filter {
public:
explicit OffsetFilter(float offset);
explicit OffsetFilter(TemplatableValue<float> offset);
optional<float> new_value(float value) override;
protected:
float offset_;
TemplatableValue<float> offset_;
};
/// A simple filter that multiplies to each value it receives by `multiplier`.
class MultiplyFilter : public Filter {
public:
explicit MultiplyFilter(float multiplier);
explicit MultiplyFilter(TemplatableValue<float> multiplier);
optional<float> new_value(float value) override;
protected:
float multiplier_;
TemplatableValue<float> multiplier_;
};
/// A simple filter that only forwards the filter chain if it doesn't receive `value_to_filter_out`.
class FilterOutValueFilter : public Filter {
public:
explicit FilterOutValueFilter(float value_to_filter_out);
explicit FilterOutValueFilter(std::vector<TemplatableValue<float>> values_to_filter_out);
optional<float> new_value(float value) override;
protected:
float value_to_filter_out_;
std::vector<TemplatableValue<float>> values_to_filter_out_;
};
class ThrottleFilter : public Filter {
@ -316,8 +316,7 @@ class ThrottleFilter : public Filter {
class TimeoutFilter : public Filter, public Component {
public:
explicit TimeoutFilter(uint32_t time_period, float new_value);
void set_value(float new_value) { this->value_ = new_value; }
explicit TimeoutFilter(uint32_t time_period, TemplatableValue<float> new_value);
optional<float> new_value(float value) override;
@ -325,7 +324,7 @@ class TimeoutFilter : public Filter, public Component {
protected:
uint32_t time_period_;
float value_;
TemplatableValue<float> value_;
};
class DebounceFilter : public Filter, public Component {

View file

@ -9,6 +9,25 @@ sensor:
return 0.0;
}
update_interval: 60s
filters:
- offset: 10
- multiply: 1
- offset: !lambda return 10;
- multiply: !lambda return 2;
- filter_out:
- 10
- 20
- !lambda return 10;
- filter_out: 10
- filter_out: !lambda return NAN;
- timeout:
timeout: 10s
value: !lambda return 10;
- timeout:
timeout: 1h
value: 20.0
- timeout:
timeout: 1d
esphome:
on_boot: