mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	binary_sensor filters templatable delays (#5029)
This commit is contained in:
		| @@ -95,6 +95,14 @@ DEVICE_CLASSES = [ | ||||
|  | ||||
| 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") | ||||
| BinarySensor = binary_sensor_ns.class_("BinarySensor", cg.EntityBase) | ||||
| BinarySensorInitiallyOff = binary_sensor_ns.class_( | ||||
| @@ -138,47 +146,75 @@ FILTER_REGISTRY = 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): | ||||
|     return cg.new_Pvariable(filter_id) | ||||
|  | ||||
|  | ||||
| @FILTER_REGISTRY.register( | ||||
|     "delayed_on_off", DelayedOnOffFilter, cv.positive_time_period_milliseconds | ||||
| @register_filter( | ||||
|     "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): | ||||
|     var = cg.new_Pvariable(filter_id, config) | ||||
|     var = cg.new_Pvariable(filter_id) | ||||
|     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 | ||||
|  | ||||
|  | ||||
| @FILTER_REGISTRY.register( | ||||
|     "delayed_on", DelayedOnFilter, cv.positive_time_period_milliseconds | ||||
| @register_filter( | ||||
|     "delayed_on", DelayedOnFilter, cv.templatable(cv.positive_time_period_milliseconds) | ||||
| ) | ||||
| 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, {}) | ||||
|     template_ = await cg.templatable(config, [], cg.uint32) | ||||
|     cg.add(var.set_delay(template_)) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @FILTER_REGISTRY.register( | ||||
|     "delayed_off", DelayedOffFilter, cv.positive_time_period_milliseconds | ||||
| @register_filter( | ||||
|     "delayed_off", | ||||
|     DelayedOffFilter, | ||||
|     cv.templatable(cv.positive_time_period_milliseconds), | ||||
| ) | ||||
| 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, {}) | ||||
|     template_ = await cg.templatable(config, [], cg.uint32) | ||||
|     cg.add(var.set_delay(template_)) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| CONF_TIME_OFF = "time_off" | ||||
| CONF_TIME_ON = "time_on" | ||||
|  | ||||
| DEFAULT_DELAY = "1s" | ||||
| DEFAULT_TIME_OFF = "100ms" | ||||
| DEFAULT_TIME_ON = "900ms" | ||||
|  | ||||
|  | ||||
| @FILTER_REGISTRY.register( | ||||
| @register_filter( | ||||
|     "autorepeat", | ||||
|     AutorepeatFilter, | ||||
|     cv.All( | ||||
| @@ -215,7 +251,7 @@ async def autorepeat_filter_to_code(config, filter_id): | ||||
|     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): | ||||
|     lambda_ = await cg.process_lambda( | ||||
|         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) { | ||||
|   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 { | ||||
|     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 {}; | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|   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 {}; | ||||
|   } else { | ||||
|     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; } | ||||
|  | ||||
| DelayedOffFilter::DelayedOffFilter(uint32_t delay) : delay_(delay) {} | ||||
| optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) { | ||||
|   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 {}; | ||||
|   } else { | ||||
|     this->cancel_timeout("OFF"); | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| @@ -29,38 +30,40 @@ class Filter { | ||||
|  | ||||
| class DelayedOnOffFilter : public Filter, public Component { | ||||
|  public: | ||||
|   explicit DelayedOnOffFilter(uint32_t delay); | ||||
|  | ||||
|   optional<bool> new_value(bool value, bool is_initial) 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: | ||||
|   uint32_t delay_; | ||||
|   TemplatableValue<uint32_t> on_delay_{}; | ||||
|   TemplatableValue<uint32_t> off_delay_{}; | ||||
| }; | ||||
|  | ||||
| class DelayedOnFilter : public Filter, public Component { | ||||
|  public: | ||||
|   explicit DelayedOnFilter(uint32_t delay); | ||||
|  | ||||
|   optional<bool> new_value(bool value, bool is_initial) override; | ||||
|  | ||||
|   float get_setup_priority() const override; | ||||
|  | ||||
|   template<typename T> void set_delay(T delay) { this->delay_ = delay; } | ||||
|  | ||||
|  protected: | ||||
|   uint32_t delay_; | ||||
|   TemplatableValue<uint32_t> delay_{}; | ||||
| }; | ||||
|  | ||||
| class DelayedOffFilter : public Filter, public Component { | ||||
|  public: | ||||
|   explicit DelayedOffFilter(uint32_t delay); | ||||
|  | ||||
|   optional<bool> new_value(bool value, bool is_initial) override; | ||||
|  | ||||
|   float get_setup_priority() const override; | ||||
|  | ||||
|   template<typename T> void set_delay(T delay) { this->delay_ = delay; } | ||||
|  | ||||
|  protected: | ||||
|   uint32_t delay_; | ||||
|   TemplatableValue<uint32_t> delay_{}; | ||||
| }; | ||||
|  | ||||
| class InvertFilter : public Filter { | ||||
|   | ||||
| @@ -1355,8 +1355,15 @@ binary_sensor: | ||||
|     device_class: window | ||||
|     filters: | ||||
|       - invert: | ||||
|       - delayed_on_off: 40ms | ||||
|       - delayed_on_off: | ||||
|           time_on: 10s | ||||
|           time_off: !lambda "return 1000;" | ||||
|       - delayed_on: 40ms | ||||
|       - delayed_off: 40ms | ||||
|       - delayed_on_off: !lambda "return 10;" | ||||
|       - delayed_on: !lambda "return 1000;" | ||||
|       - delayed_off: !lambda "return 0;" | ||||
|     on_press: | ||||
|       then: | ||||
|         - lambda: >- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user