mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
binary_sensor filters templatable delays (#5029)
This commit is contained in:
parent
099dc8d1d2
commit
5b2176562b
4 changed files with 79 additions and 36 deletions
|
@ -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)
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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: >-
|
||||||
|
|
Loading…
Reference in a new issue