add time based cover, has built in endstop (#665)

* add has built in endstop

* rewrite as proposed

* Update esphome/components/time_based/time_based_cover.h

Co-Authored-By: Otto Winter <otto@otto-winter.com>

* lint

* Re trigger stop_operation if stop called

* allow se triggering open/close command if safe

* using COVER_OPEN/CLOSE constants
This commit is contained in:
Guillermo Ruffino 2019-08-29 11:07:41 -03:00 committed by Otto Winter
parent d27291b997
commit 83a92f03fc
3 changed files with 23 additions and 4 deletions

View file

@ -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') time_based_ns = cg.esphome_ns.namespace('time_based')
TimeBasedCover = time_based_ns.class_('TimeBasedCover', cover.Cover, cg.Component) 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({ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TimeBasedCover), cv.GenerateID(): cv.declare_id(TimeBasedCover),
cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True), 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_ACTION): automation.validate_automation(single=True),
cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds, 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) }).extend(cv.COMPONENT_SCHEMA)
@ -32,3 +36,5 @@ def to_code(config):
cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION]))
yield automation.build_automation(var.get_close_trigger(), [], config[CONF_CLOSE_ACTION]) 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]))

View file

@ -30,13 +30,18 @@ void TimeBasedCover::loop() {
// Recompute position every loop cycle // Recompute position every loop cycle
this->recompute_position_(); this->recompute_position_();
if (this->current_operation != COVER_OPERATION_IDLE && this->is_at_target_()) { if (this->is_at_target_()) {
this->start_direction_(COVER_OPERATION_IDLE); 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(); this->publish_state();
} }
// Send current position every second // 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->publish_state(false);
this->last_publish_time_ = now; this->last_publish_time_ = now;
} }
@ -57,6 +62,12 @@ void TimeBasedCover::control(const CoverCall &call) {
auto pos = *call.get_position(); auto pos = *call.get_position();
if (pos == this->position) { if (pos == this->position) {
// already at target // 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 { } else {
auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING; auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
this->target_position_ = pos; this->target_position_ = pos;
@ -82,7 +93,7 @@ bool TimeBasedCover::is_at_target_() const {
} }
} }
void TimeBasedCover::start_direction_(CoverOperation dir) { void TimeBasedCover::start_direction_(CoverOperation dir) {
if (dir == this->current_operation) if (dir == this->current_operation && dir != COVER_OPERATION_IDLE)
return; return;
this->recompute_position_(); this->recompute_position_();

View file

@ -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_open_duration(uint32_t open_duration) { this->open_duration_ = open_duration; }
void set_close_duration(uint32_t close_duration) { this->close_duration_ = close_duration; } void set_close_duration(uint32_t close_duration) { this->close_duration_ = close_duration; }
cover::CoverTraits get_traits() override; cover::CoverTraits get_traits() override;
void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; }
protected: protected:
void control(const cover::CoverCall &call) override; 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 start_dir_time_{0};
uint32_t last_publish_time_{0}; uint32_t last_publish_time_{0};
float target_position_{0}; float target_position_{0};
bool has_built_in_endstop_{false};
}; };
} // namespace time_based } // namespace time_based