binary_sensor filters templatable delays (#5029)

This commit is contained in:
Sergey Dudanov 2023-07-04 04:25:48 +04:00 committed by GitHub
parent 099dc8d1d2
commit 5b2176562b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 36 deletions

View file

@ -95,6 +95,14 @@ DEVICE_CLASSES = [
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
CONF_TIME_OFF = "time_off"
CONF_TIME_ON = "time_on"
DEFAULT_DELAY = "1s"
DEFAULT_TIME_OFF = "100ms"
DEFAULT_TIME_ON = "900ms"
binary_sensor_ns = cg.esphome_ns.namespace("binary_sensor") binary_sensor_ns = cg.esphome_ns.namespace("binary_sensor")
BinarySensor = binary_sensor_ns.class_("BinarySensor", cg.EntityBase) BinarySensor = binary_sensor_ns.class_("BinarySensor", cg.EntityBase)
BinarySensorInitiallyOff = binary_sensor_ns.class_( BinarySensorInitiallyOff = binary_sensor_ns.class_(
@ -138,47 +146,75 @@ FILTER_REGISTRY = Registry()
validate_filters = cv.validate_registry("filter", FILTER_REGISTRY) validate_filters = cv.validate_registry("filter", FILTER_REGISTRY)
@FILTER_REGISTRY.register("invert", InvertFilter, {}) def register_filter(name, filter_type, schema):
return FILTER_REGISTRY.register(name, filter_type, schema)
@register_filter("invert", InvertFilter, {})
async def invert_filter_to_code(config, filter_id): async def invert_filter_to_code(config, filter_id):
return cg.new_Pvariable(filter_id) return cg.new_Pvariable(filter_id)
@FILTER_REGISTRY.register( @register_filter(
"delayed_on_off", DelayedOnOffFilter, cv.positive_time_period_milliseconds "delayed_on_off",
DelayedOnOffFilter,
cv.Any(
cv.templatable(cv.positive_time_period_milliseconds),
cv.Schema(
{
cv.Required(CONF_TIME_ON): cv.templatable(
cv.positive_time_period_milliseconds
),
cv.Required(CONF_TIME_OFF): cv.templatable(
cv.positive_time_period_milliseconds
),
}
),
msg="'delayed_on_off' filter requires either a delay time to be used for both "
"turn-on and turn-off delays, or two parameters 'time_on' and 'time_off' if "
"different delay times are required.",
),
) )
async def delayed_on_off_filter_to_code(config, filter_id): async def delayed_on_off_filter_to_code(config, filter_id):
var = cg.new_Pvariable(filter_id, config) var = cg.new_Pvariable(filter_id)
await cg.register_component(var, {}) await cg.register_component(var, {})
if isinstance(config, dict):
template_ = await cg.templatable(config[CONF_TIME_ON], [], cg.uint32)
cg.add(var.set_on_delay(template_))
template_ = await cg.templatable(config[CONF_TIME_OFF], [], cg.uint32)
cg.add(var.set_off_delay(template_))
else:
template_ = await cg.templatable(config, [], cg.uint32)
cg.add(var.set_on_delay(template_))
cg.add(var.set_off_delay(template_))
return var return var
@FILTER_REGISTRY.register( @register_filter(
"delayed_on", DelayedOnFilter, cv.positive_time_period_milliseconds "delayed_on", DelayedOnFilter, cv.templatable(cv.positive_time_period_milliseconds)
) )
async def delayed_on_filter_to_code(config, filter_id): async def delayed_on_filter_to_code(config, filter_id):
var = cg.new_Pvariable(filter_id, config) var = cg.new_Pvariable(filter_id)
await cg.register_component(var, {}) await cg.register_component(var, {})
template_ = await cg.templatable(config, [], cg.uint32)
cg.add(var.set_delay(template_))
return var return var
@FILTER_REGISTRY.register( @register_filter(
"delayed_off", DelayedOffFilter, cv.positive_time_period_milliseconds "delayed_off",
DelayedOffFilter,
cv.templatable(cv.positive_time_period_milliseconds),
) )
async def delayed_off_filter_to_code(config, filter_id): async def delayed_off_filter_to_code(config, filter_id):
var = cg.new_Pvariable(filter_id, config) var = cg.new_Pvariable(filter_id)
await cg.register_component(var, {}) await cg.register_component(var, {})
template_ = await cg.templatable(config, [], cg.uint32)
cg.add(var.set_delay(template_))
return var return var
CONF_TIME_OFF = "time_off" @register_filter(
CONF_TIME_ON = "time_on"
DEFAULT_DELAY = "1s"
DEFAULT_TIME_OFF = "100ms"
DEFAULT_TIME_ON = "900ms"
@FILTER_REGISTRY.register(
"autorepeat", "autorepeat",
AutorepeatFilter, AutorepeatFilter,
cv.All( cv.All(
@ -215,7 +251,7 @@ async def autorepeat_filter_to_code(config, filter_id):
return var return var
@FILTER_REGISTRY.register("lambda", LambdaFilter, cv.returning_lambda) @register_filter("lambda", LambdaFilter, cv.returning_lambda)
async def lambda_filter_to_code(config, filter_id): async def lambda_filter_to_code(config, filter_id):
lambda_ = await cg.process_lambda( lambda_ = await cg.process_lambda(
config, [(bool, "x")], return_type=cg.optional.template(bool) config, [(bool, "x")], return_type=cg.optional.template(bool)

View file

@ -26,22 +26,20 @@ void Filter::input(bool value, bool is_initial) {
} }
} }
DelayedOnOffFilter::DelayedOnOffFilter(uint32_t delay) : delay_(delay) {}
optional<bool> DelayedOnOffFilter::new_value(bool value, bool is_initial) { optional<bool> DelayedOnOffFilter::new_value(bool value, bool is_initial) {
if (value) { if (value) {
this->set_timeout("ON_OFF", this->delay_, [this, is_initial]() { this->output(true, is_initial); }); this->set_timeout("ON_OFF", this->on_delay_.value(), [this, is_initial]() { this->output(true, is_initial); });
} else { } else {
this->set_timeout("ON_OFF", this->delay_, [this, is_initial]() { this->output(false, is_initial); }); this->set_timeout("ON_OFF", this->off_delay_.value(), [this, is_initial]() { this->output(false, is_initial); });
} }
return {}; return {};
} }
float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; } float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
DelayedOnFilter::DelayedOnFilter(uint32_t delay) : delay_(delay) {}
optional<bool> DelayedOnFilter::new_value(bool value, bool is_initial) { optional<bool> DelayedOnFilter::new_value(bool value, bool is_initial) {
if (value) { if (value) {
this->set_timeout("ON", this->delay_, [this, is_initial]() { this->output(true, is_initial); }); this->set_timeout("ON", this->delay_.value(), [this, is_initial]() { this->output(true, is_initial); });
return {}; return {};
} else { } else {
this->cancel_timeout("ON"); this->cancel_timeout("ON");
@ -51,10 +49,9 @@ optional<bool> DelayedOnFilter::new_value(bool value, bool is_initial) {
float DelayedOnFilter::get_setup_priority() const { return setup_priority::HARDWARE; } float DelayedOnFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
DelayedOffFilter::DelayedOffFilter(uint32_t delay) : delay_(delay) {}
optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) { optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) {
if (!value) { if (!value) {
this->set_timeout("OFF", this->delay_, [this, is_initial]() { this->output(false, is_initial); }); this->set_timeout("OFF", this->delay_.value(), [this, is_initial]() { this->output(false, is_initial); });
return {}; return {};
} else { } else {
this->cancel_timeout("OFF"); this->cancel_timeout("OFF");

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
@ -29,38 +30,40 @@ class Filter {
class DelayedOnOffFilter : public Filter, public Component { class DelayedOnOffFilter : public Filter, public Component {
public: public:
explicit DelayedOnOffFilter(uint32_t delay);
optional<bool> new_value(bool value, bool is_initial) override; optional<bool> new_value(bool value, bool is_initial) override;
float get_setup_priority() const override; float get_setup_priority() const override;
template<typename T> void set_on_delay(T delay) { this->on_delay_ = delay; }
template<typename T> void set_off_delay(T delay) { this->off_delay_ = delay; }
protected: protected:
uint32_t delay_; TemplatableValue<uint32_t> on_delay_{};
TemplatableValue<uint32_t> off_delay_{};
}; };
class DelayedOnFilter : public Filter, public Component { class DelayedOnFilter : public Filter, public Component {
public: public:
explicit DelayedOnFilter(uint32_t delay);
optional<bool> new_value(bool value, bool is_initial) override; optional<bool> new_value(bool value, bool is_initial) override;
float get_setup_priority() const override; float get_setup_priority() const override;
template<typename T> void set_delay(T delay) { this->delay_ = delay; }
protected: protected:
uint32_t delay_; TemplatableValue<uint32_t> delay_{};
}; };
class DelayedOffFilter : public Filter, public Component { class DelayedOffFilter : public Filter, public Component {
public: public:
explicit DelayedOffFilter(uint32_t delay);
optional<bool> new_value(bool value, bool is_initial) override; optional<bool> new_value(bool value, bool is_initial) override;
float get_setup_priority() const override; float get_setup_priority() const override;
template<typename T> void set_delay(T delay) { this->delay_ = delay; }
protected: protected:
uint32_t delay_; TemplatableValue<uint32_t> delay_{};
}; };
class InvertFilter : public Filter { class InvertFilter : public Filter {

View file

@ -1355,8 +1355,15 @@ binary_sensor:
device_class: window device_class: window
filters: filters:
- invert: - invert:
- delayed_on_off: 40ms
- delayed_on_off:
time_on: 10s
time_off: !lambda "return 1000;"
- delayed_on: 40ms - delayed_on: 40ms
- delayed_off: 40ms - delayed_off: 40ms
- delayed_on_off: !lambda "return 10;"
- delayed_on: !lambda "return 1000;"
- delayed_off: !lambda "return 0;"
on_press: on_press:
then: then:
- lambda: >- - lambda: >-