diff --git a/esphome/components/time_based/cover.py b/esphome/components/time_based/cover.py index 85f606e6cc..6a7c9b6835 100644 --- a/esphome/components/time_based/cover.py +++ b/esphome/components/time_based/cover.py @@ -8,6 +8,8 @@ from esphome.const import CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, CONF_ID, CONF_ time_based_ns = cg.esphome_ns.namespace('time_based') TimeBasedCover = time_based_ns.class_('TimeBasedCover', cover.Cover, cg.Component) +CONF_HAS_BUILT_IN_ENDSTOP = 'has_built_in_endstop' + CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(TimeBasedCover), cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True), @@ -17,6 +19,8 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({ cv.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True), cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds, + + cv.Optional(CONF_HAS_BUILT_IN_ENDSTOP, default=False): cv.boolean, }).extend(cv.COMPONENT_SCHEMA) @@ -32,3 +36,5 @@ def to_code(config): cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) yield automation.build_automation(var.get_close_trigger(), [], config[CONF_CLOSE_ACTION]) + + cg.add(var.set_has_built_in_endstop(config[CONF_HAS_BUILT_IN_ENDSTOP])) diff --git a/esphome/components/time_based/time_based_cover.cpp b/esphome/components/time_based/time_based_cover.cpp index bbc887debc..c353b552d3 100644 --- a/esphome/components/time_based/time_based_cover.cpp +++ b/esphome/components/time_based/time_based_cover.cpp @@ -30,13 +30,18 @@ void TimeBasedCover::loop() { // Recompute position every loop cycle this->recompute_position_(); - if (this->current_operation != COVER_OPERATION_IDLE && this->is_at_target_()) { - this->start_direction_(COVER_OPERATION_IDLE); + if (this->is_at_target_()) { + if (this->has_built_in_endstop_ && (this->target_position_ == COVER_OPEN || this->target_position_ == COVER_CLOSED)) { + // Don't trigger stop, let the cover stop by itself. + this->current_operation = COVER_OPERATION_IDLE; + } else { + this->start_direction_(COVER_OPERATION_IDLE); + } this->publish_state(); } // Send current position every second - if (this->current_operation != COVER_OPERATION_IDLE && now - this->last_publish_time_ > 1000) { + if (now - this->last_publish_time_ > 1000) { this->publish_state(false); this->last_publish_time_ = now; } @@ -57,6 +62,12 @@ void TimeBasedCover::control(const CoverCall &call) { auto pos = *call.get_position(); if (pos == this->position) { // already at target + // for covers with built in end stop, we should send the command again + if (this->has_built_in_endstop_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) { + auto op = pos == COVER_CLOSED ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING; + this->target_position_ = pos; + this->start_direction_(op); + } } else { auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING; this->target_position_ = pos; @@ -82,7 +93,7 @@ bool TimeBasedCover::is_at_target_() const { } } void TimeBasedCover::start_direction_(CoverOperation dir) { - if (dir == this->current_operation) + if (dir == this->current_operation && dir != COVER_OPERATION_IDLE) return; this->recompute_position_(); diff --git a/esphome/components/time_based/time_based_cover.h b/esphome/components/time_based/time_based_cover.h index 60819d797b..be3a55c546 100644 --- a/esphome/components/time_based/time_based_cover.h +++ b/esphome/components/time_based/time_based_cover.h @@ -20,6 +20,7 @@ class TimeBasedCover : public cover::Cover, public Component { void set_open_duration(uint32_t open_duration) { this->open_duration_ = open_duration; } void set_close_duration(uint32_t close_duration) { this->close_duration_ = close_duration; } cover::CoverTraits get_traits() override; + void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; } protected: void control(const cover::CoverCall &call) override; @@ -41,6 +42,7 @@ class TimeBasedCover : public cover::Cover, public Component { uint32_t start_dir_time_{0}; uint32_t last_publish_time_{0}; float target_position_{0}; + bool has_built_in_endstop_{false}; }; } // namespace time_based