From 12dd2cbcd5f37fcfc87f5e76dd81b22eaa2210df Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Thu, 2 Feb 2023 20:52:19 +0100 Subject: [PATCH 01/14] implementation of time based cover with tilt --- .../components/time_based_tilt/__init__.py | 0 esphome/components/time_based_tilt/cover.py | 70 ++++ .../time_based_tilt/time_based_tilt_cover.cpp | 311 ++++++++++++++++++ .../time_based_tilt/time_based_tilt_cover.h | 76 +++++ 4 files changed, 457 insertions(+) create mode 100644 esphome/components/time_based_tilt/__init__.py create mode 100644 esphome/components/time_based_tilt/cover.py create mode 100644 esphome/components/time_based_tilt/time_based_tilt_cover.cpp create mode 100644 esphome/components/time_based_tilt/time_based_tilt_cover.h diff --git a/esphome/components/time_based_tilt/__init__.py b/esphome/components/time_based_tilt/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/time_based_tilt/cover.py b/esphome/components/time_based_tilt/cover.py new file mode 100644 index 0000000000..6af94e1fa6 --- /dev/null +++ b/esphome/components/time_based_tilt/cover.py @@ -0,0 +1,70 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import automation +from esphome.components import cover +from esphome.const import ( + CONF_CLOSE_ACTION, + CONF_CLOSE_DURATION, + CONF_ID, + CONF_OPEN_ACTION, + CONF_OPEN_DURATION, + CONF_STOP_ACTION, + CONF_ASSUMED_STATE, +) + +time_based_tilt_ns = cg.esphome_ns.namespace("time_based_tilt") +TimeBasedTiltCover = time_based_tilt_ns.class_("TimeBasedTiltCover", cover.Cover, cg.Component) + +CONF_TILT_OPEN_DURATION = "tilt_open_duration" +CONF_TILT_CLOSE_DURATION = "tilt_close_duration" +CONF_INTERLOCK_WAIT_TIME = "interlock_wait_time" +CONF_RECALIBRATION_TIME = "recalibration_time" +CONF_INERTIA_OPEN_TIME = "inertia_open_time" +CONF_INERTIA_CLOSE_TIME = "inertia_close_time" + +CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(TimeBasedTiltCover), + cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True), + cv.Required(CONF_OPEN_ACTION): automation.validate_automation(single=True), + cv.Required(CONF_OPEN_DURATION): cv.positive_time_period_milliseconds, + 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_ASSUMED_STATE, default=True): cv.boolean, + cv.Optional(CONF_TILT_OPEN_DURATION, default="0ms"): cv.positive_time_period_milliseconds, + cv.Optional(CONF_TILT_CLOSE_DURATION, default="0ms"): cv.positive_time_period_milliseconds, + cv.Optional(CONF_INTERLOCK_WAIT_TIME, default="0ms"): cv.positive_time_period_milliseconds, + cv.Optional(CONF_RECALIBRATION_TIME, default="0ms"): cv.positive_time_period_milliseconds, + cv.Optional(CONF_INERTIA_OPEN_TIME, default="0ms"): cv.positive_time_period_milliseconds, + cv.Optional(CONF_INERTIA_CLOSE_TIME, default="0ms"): cv.positive_time_period_milliseconds, + } +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await cover.register_cover(var, config) + + await automation.build_automation( + var.get_stop_trigger(), [], config[CONF_STOP_ACTION] + ) + + cg.add(var.set_open_duration(config[CONF_OPEN_DURATION])) + await automation.build_automation( + var.get_open_trigger(), [], config[CONF_OPEN_ACTION] + ) + + cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION])) + await automation.build_automation( + var.get_close_trigger(), [], config[CONF_CLOSE_ACTION] + ) + + cg.add(var.set_tilt_open_duration(config[CONF_TILT_OPEN_DURATION])) + cg.add(var.set_tilt_close_duration(config[CONF_TILT_CLOSE_DURATION])) + cg.add(var.set_interlock_wait_time(config[CONF_INTERLOCK_WAIT_TIME])) + cg.add(var.set_recalibration_time(config[CONF_RECALIBRATION_TIME])) + cg.add(var.set_inertia_close_time(config[CONF_INERTIA_CLOSE_TIME])) + cg.add(var.set_inertia_open_time(config[CONF_INERTIA_OPEN_TIME])) + cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE])) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp new file mode 100644 index 0000000000..3ae95d3788 --- /dev/null +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -0,0 +1,311 @@ +#include "time_based_tilt_cover.h" +#include "esphome/core/log.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace time_based_tilt { + +static const char *const TAG = "time_based_tilt.cover"; + +using namespace esphome::cover; + +void TimeBasedTiltCover::dump_config() { + LOG_COVER("", "Time Based Tilt Cover", this); + ESP_LOGCONFIG(TAG, " Open Duration: %.3fs", this->open_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, " Close Duration: %.3fs", this->close_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, " Tilt Close Duration: %.3fs", this->tilt_close_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, " Tilt Open Duration: %.3fs", this->tilt_open_duration_ / 1e3f); + ESP_LOGCONFIG(TAG, " Interlock wait time: %.3fs", this->interlock_wait_time_ / 1e3f); + ESP_LOGCONFIG(TAG, " Inertia close time: %.3fs", this->inertia_close_time_ / 1e3f); + ESP_LOGCONFIG(TAG, " Inertia open time: %.3fs", this->inertia_open_time_ / 1e3f); + ESP_LOGCONFIG(TAG, " Recalibration time: %.3fs", this->recalibration_time_ / 1e3f); +} +void TimeBasedTiltCover::setup() { + auto restore = this->restore_state_(); + if (restore.has_value()) { + restore->apply(this); + } else { + this->position = 0.5f; + this->tilt = 0.5f; + } +} +bool TimeBasedTiltCover::is_at_target_position_() const { + switch (this->current_operation) { + case COVER_OPERATION_OPENING: + return this->position >= this->target_position_; + case COVER_OPERATION_CLOSING: + return this->position <= this->target_position_; + case COVER_OPERATION_IDLE: + default: + return true; + } +} + +bool TimeBasedTiltCover::is_at_target_tilt_() const { + switch (this->current_operation) { + case COVER_OPERATION_OPENING: + return this->tilt >= this->target_tilt_; + case COVER_OPERATION_CLOSING: + return this->tilt <= this->target_tilt_; + case COVER_OPERATION_IDLE: + default: + return true; + } +} + +void TimeBasedTiltCover::loop() { + + if ( this->fsm_state_ == STATE_IDLE && this->target_position_ == TARGET_NONE && this->target_tilt_ == TARGET_NONE ) return; + + const uint32_t now = millis(); + + if ( this->fsm_state_ == STATE_CALIBRATING ) { + if ( now - this->last_recompute_time_ >= this->recalibration_time_ ) { + this->fsm_state_ = STATE_STOPPING; + } + return; + } + + if ( this->fsm_state_ == STATE_STOPPING ) + { + this->stop_trigger_->trigger(); + this->interlockedTime = millis(); + this->interlocked_direction = this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; + this->fsm_state_ = STATE_IDLE; + this->last_operation_ = this->current_operation; + this->current_operation = COVER_OPERATION_IDLE; + return; + } + + if ( this->fsm_state_ == STATE_IDLE && (this->target_position_ != TARGET_NONE || this->target_tilt_ != TARGET_NONE) ) + { + + if (this->target_position_ != TARGET_NONE ) { + this->current_operation = this->compute_direction(this->target_position_,this->position); + } else { + this->current_operation = this->compute_direction(this->target_tilt_,this->tilt); + } + + if ( this->current_operation == this->interlocked_direction + && now - this->interlockedTime < this->interlock_wait_time_ ) return; + + Trigger<> *trig = this->current_operation == COVER_OPERATION_CLOSING ? this->close_trigger_ : this->open_trigger_; + + trig->trigger(); + this->last_recompute_time_ = now; + + this->fsm_state_ = STATE_MOVING; + return; + } + + if ( this->fsm_state_ == STATE_MOVING ) + { + + auto travel_time = now - this->last_recompute_time_; + this->last_recompute_time_ = now; + + float dir_factor = this->current_operation == COVER_OPERATION_CLOSING ? -1.0 : 1.0 ; + auto inertia_time = this->current_operation == COVER_OPERATION_CLOSING ? this->inertia_close_time_ : this->inertia_open_time_ ; + + if ( inertia_time > 0 && this->inertia * dir_factor < 0.5f ) // inertia before movement + { + auto inertia_step = dir_factor * travel_time / inertia_time; + this->inertia += inertia_step; + auto rest = this->inertia - clamp( this->inertia , -0.5f, 0.5f); + this->inertia = clamp( this->inertia, -0.5f, 0.5f); + + if ( ! rest ) return; // the movement has not yet actually started + travel_time = dir_factor * rest * inertia_time; // actual movement time taking inertia into account + } + + auto tilt_time = this->current_operation == COVER_OPERATION_CLOSING ? this->tilt_close_duration_ : this->tilt_open_duration_; + + if ( tilt_time > 0 && ( this->tilt - 0.5f ) * dir_factor < 0.5f ) // tilting before movement + { + auto tilt_step = dir_factor * travel_time / tilt_time; + this->tilt += tilt_step; + auto rest = this->tilt - 0.5f - clamp( this->tilt - 0.5f , -0.5f, 0.5f); + this->tilt = clamp( this->tilt , 0.0f, 1.0f); + + if (this->target_position_ == TARGET_NONE && this->is_at_target_tilt_()){ // only tilting w/o position change + this->last_recompute_time_ = now; + this->target_tilt_ = TARGET_NONE; + this->publish_state(); + this->last_publish_time_= now; + + if ( ( this->position == 0.0f && this->tilt == 0.0f ) || ( this->position == 1.0f && this->tilt == 1.0f ) ) // start recalibration + { + this->fsm_state_ = STATE_CALIBRATING; + } else { + this->fsm_state_ = STATE_STOPPING; + } + + return; // only tilting w/o position change so no need to recompute position + } + + if ( now - this->last_publish_time_ > 300 ){ + this->publish_state(false); + this->last_publish_time_= now; + } + + if ( ! rest ) return; // the movement has not yet actually started + + travel_time = dir_factor * rest * tilt_time; // actual movement time taking tilt into account + } + + auto move_time = this->current_operation == COVER_OPERATION_CLOSING ? this->close_duration_ : this->open_duration_ ; + + if ( move_time > 0 && ( this->position - 0.5f ) * dir_factor < 0.5f ) + { + auto move_step = dir_factor * travel_time / move_time; + this->position += move_step; + this->position = clamp( this->position , 0.0f, 1.0f); + } + + if (this->is_at_target_position_()){ + this->last_recompute_time_ = now; + this->target_position_ = TARGET_NONE; + this->publish_state(); + this->last_publish_time_= now; + + if ( ( this->position == 0.0f && this->tilt == 0.0f ) || ( this->position == 1.0f && this->tilt == 1.0f ) ) + { + this->fsm_state_ = STATE_CALIBRATING; + } else { + this->fsm_state_ = STATE_STOPPING; + } + } + + if ( now - this->last_publish_time_ > 1000 ){ + this->publish_state(false); + this->last_publish_time_= now; + } + } + +} + +float TimeBasedTiltCover::get_setup_priority() const { return setup_priority::DATA; } +CoverTraits TimeBasedTiltCover::get_traits() { + auto traits = CoverTraits(); + traits.set_supports_position(true); + traits.set_supports_tilt(this->tilt_close_duration_ !=0 && this->tilt_open_duration_ !=0); + traits.set_supports_toggle(true); + traits.set_is_assumed_state(this->assumed_state_); + return traits; +} +void TimeBasedTiltCover::control(const CoverCall &call) { + if (call.get_stop()) { + this->target_position_ = TARGET_NONE; + this->target_tilt_= TARGET_NONE; + if (this->fsm_state_ == STATE_MOVING){ + this->fsm_state_ = STATE_STOPPING; + } + return; + } + if (call.get_position().has_value() && call.get_tilt().has_value() ) { + auto pos = *call.get_position(); + auto til = *call.get_tilt(); + + if (this->round_position(pos) == this->round_position(this->position)) + pos = TARGET_NONE; + if (this->round_position(til) == this->round_position(this->tilt)) + til = TARGET_NONE; + + this->target_position_ = pos; + this->target_tilt_ = til; + + if (this->fsm_state_ == STATE_MOVING){ //TODO: check direction also on tilting + auto direction = COVER_OPERATION_IDLE; + if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { + direction = this->compute_direction(this->target_position_ , this->position ); + } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt){ + direction = this->compute_direction( this->target_tilt_ , this->tilt ); + } + + if (direction != this->current_operation ) + { + this->fsm_state_ = STATE_STOPPING; + } + } + } else if (call.get_position().has_value()) { + auto pos = *call.get_position(); + + if ( pos == 0.0f && this->position == 0.0f && this->tilt != 0.0f ){ + pos = TARGET_NONE; + this->target_tilt_ = 0.0f; + } else if ( pos == 1.0f && this->position == 1.0f && this->tilt != 1.0f ){ + pos = TARGET_NONE; + this->target_tilt_ = 1.0f; + } else if ( this->round_position(pos) == this->round_position(this->position) ){ + pos = TARGET_NONE; + } + + this->target_position_ = pos; + + if (this->fsm_state_ == STATE_MOVING){ + auto direction = COVER_OPERATION_IDLE; + if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { + direction = this->compute_direction(this->target_position_ , this->position ); + this->target_tilt_ = TARGET_NONE; // unset previous target tilt + } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt){ + direction = this->compute_direction( this->target_tilt_ , this->tilt ); + } + + if (direction != this->current_operation ) + { + this->fsm_state_ = STATE_STOPPING; + } + } + } else if (call.get_tilt().has_value()) { + auto til = *call.get_tilt(); + if ( this->round_position(til) == this->round_position(this->tilt) ) + { + til = TARGET_NONE; + } + + this->target_tilt_ = til; + + if (this->fsm_state_ == STATE_MOVING){ + auto direction = COVER_OPERATION_IDLE; + if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt){ + direction = this->compute_direction( this->target_tilt_ , this->tilt ); + this->target_position_ = TARGET_NONE; + } + + if (direction != this->current_operation ) + { + this->fsm_state_ = STATE_STOPPING; + } + } + } + + if (call.get_toggle().has_value()) { + if (this->current_operation != COVER_OPERATION_IDLE) { + this->publish_state(); + this->fsm_state_ = STATE_STOPPING; + this->target_position_ = TARGET_NONE; + this->target_tilt_ = TARGET_NONE; + } else { + if ( this->position == COVER_CLOSED && this->tilt == COVER_CLOSED ) { + this->target_position_ = COVER_OPEN; + } else if ( this->position == COVER_OPEN && this->tilt == COVER_OPEN ) { + this->target_position_ = COVER_CLOSED; + } else if ( this->last_operation_ == COVER_OPERATION_CLOSING ) { + if (this->position != COVER_OPEN) { + this->target_position_ = COVER_OPEN; + } else { + this->target_tilt_ = COVER_OPEN; + } + } else { + if (this->position != COVER_CLOSED) { + this->target_position_ = COVER_CLOSED; + } else { + this->target_tilt_ = COVER_CLOSED; + } + } + } + } +} + +} // namespace time_based_tilt +} // namespace esphome diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.h b/esphome/components/time_based_tilt/time_based_tilt_cover.h new file mode 100644 index 0000000000..974a5acc0c --- /dev/null +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.h @@ -0,0 +1,76 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/cover/cover.h" + +namespace esphome { +namespace time_based_tilt { + +class TimeBasedTiltCover : public cover::Cover, public Component { + public: + void setup() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override; + + Trigger<> *get_open_trigger() const { return this->open_trigger_; } + Trigger<> *get_close_trigger() const { return this->close_trigger_; } + Trigger<> *get_stop_trigger() const { return this->stop_trigger_; } + 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_tilt_open_duration(uint32_t tilt_open_duration) { this->tilt_open_duration_ = tilt_open_duration; } + void set_tilt_close_duration(uint32_t tilt_close_duration) { this->tilt_close_duration_ = tilt_close_duration; } + void set_interlock_wait_time(uint32_t interlock_wait_time) { this->interlock_wait_time_ = interlock_wait_time; } + void set_recalibration_time(uint32_t recalibration_time) { this->recalibration_time_ = recalibration_time; } + void set_inertia_open_time(uint32_t inertia_time) { this->inertia_open_time_ = inertia_time; } + void set_inertia_close_time(uint32_t inertia_time) { this->inertia_close_time_ = inertia_time; } + cover::CoverOperation compute_direction(float target, float current){ return target < current ? cover::COVER_OPERATION_CLOSING : cover::COVER_OPERATION_OPENING ; }; + float round_position(float pos) { return round(100 * pos)/100; }; + cover::CoverTraits get_traits() override; + void set_assumed_state(bool value) { this->assumed_state_ = value; } + + protected: + void control(const cover::CoverCall &call) override; + bool is_at_target_position_() const; + bool is_at_target_tilt_() const; + + Trigger<> *open_trigger_{new Trigger<>()}; + Trigger<> *close_trigger_{new Trigger<>()}; + Trigger<> *stop_trigger_{new Trigger<>()}; + + uint32_t open_duration_; + uint32_t close_duration_; + + uint32_t tilt_close_duration_; + uint32_t tilt_open_duration_; + + uint32_t interlock_wait_time_; + uint32_t recalibration_time_; + uint32_t inertia_open_time_; + uint32_t inertia_close_time_; + + const float TARGET_NONE{-1}; + enum State : uint8_t { + STATE_IDLE, + STATE_MOVING, + STATE_STOPPING, + STATE_CALIBRATING + }; + + Trigger<> *prev_command_trigger_{nullptr}; + uint32_t last_recompute_time_{0}; + uint32_t last_publish_time_{0}; + float target_position_{TARGET_NONE}; + float target_tilt_{TARGET_NONE}; + float inertia{0.0f}; + bool has_built_in_endstop_{false}; + bool assumed_state_{false}; + cover::CoverOperation last_operation_{cover::COVER_OPERATION_OPENING}; + State fsm_state_{STATE_IDLE}; + cover::CoverOperation interlocked_direction{cover::COVER_OPERATION_IDLE}; + uint32_t interlockedTime{0}; +}; + +} // namespace time_based_tilt +} // namespace esphome From 44b071dce7c96e48e4ba1a0644457ac65f4fa8e6 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Thu, 2 Feb 2023 22:33:16 +0100 Subject: [PATCH 02/14] - fix publishing state - use constants for open and close posititions --- .../time_based_tilt/time_based_tilt_cover.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index 3ae95d3788..5a9737d770 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -74,6 +74,7 @@ void TimeBasedTiltCover::loop() { this->fsm_state_ = STATE_IDLE; this->last_operation_ = this->current_operation; this->current_operation = COVER_OPERATION_IDLE; + this->publish_state(); return; } @@ -130,12 +131,12 @@ void TimeBasedTiltCover::loop() { if (this->target_position_ == TARGET_NONE && this->is_at_target_tilt_()){ // only tilting w/o position change this->last_recompute_time_ = now; this->target_tilt_ = TARGET_NONE; - this->publish_state(); this->last_publish_time_= now; - if ( ( this->position == 0.0f && this->tilt == 0.0f ) || ( this->position == 1.0f && this->tilt == 1.0f ) ) // start recalibration + if ( ( this->position == COVER_CLOSED && this->tilt == COVER_CLOSED ) || ( this->position == COVER_OPEN && this->tilt == COVER_OPEN ) ) // start recalibration { this->fsm_state_ = STATE_CALIBRATING; + this->publish_state(false); } else { this->fsm_state_ = STATE_STOPPING; } @@ -143,7 +144,7 @@ void TimeBasedTiltCover::loop() { return; // only tilting w/o position change so no need to recompute position } - if ( now - this->last_publish_time_ > 300 ){ + if ( now - this->last_publish_time_ > ( ( tilt_time / 5 ) > 1000 ? 1000 : ( tilt_time / 5 ) ) ){ this->publish_state(false); this->last_publish_time_= now; } @@ -165,12 +166,12 @@ void TimeBasedTiltCover::loop() { if (this->is_at_target_position_()){ this->last_recompute_time_ = now; this->target_position_ = TARGET_NONE; - this->publish_state(); this->last_publish_time_= now; - if ( ( this->position == 0.0f && this->tilt == 0.0f ) || ( this->position == 1.0f && this->tilt == 1.0f ) ) + if ( ( this->position == COVER_CLOSED && this->tilt == COVER_CLOSED ) || ( this->position == COVER_OPEN && this->tilt == COVER_OPEN ) ) { this->fsm_state_ = STATE_CALIBRATING; + this->publish_state(false); } else { this->fsm_state_ = STATE_STOPPING; } @@ -230,12 +231,12 @@ void TimeBasedTiltCover::control(const CoverCall &call) { } else if (call.get_position().has_value()) { auto pos = *call.get_position(); - if ( pos == 0.0f && this->position == 0.0f && this->tilt != 0.0f ){ + if ( pos == COVER_CLOSED && this->position == COVER_CLOSED && this->tilt != COVER_CLOSED ){ pos = TARGET_NONE; - this->target_tilt_ = 0.0f; - } else if ( pos == 1.0f && this->position == 1.0f && this->tilt != 1.0f ){ + this->target_tilt_ = COVER_CLOSED; + } else if ( pos == COVER_OPEN && this->position == COVER_OPEN && this->tilt != COVER_OPEN ){ pos = TARGET_NONE; - this->target_tilt_ = 1.0f; + this->target_tilt_ = COVER_OPEN; } else if ( this->round_position(pos) == this->round_position(this->position) ){ pos = TARGET_NONE; } @@ -281,7 +282,6 @@ void TimeBasedTiltCover::control(const CoverCall &call) { if (call.get_toggle().has_value()) { if (this->current_operation != COVER_OPERATION_IDLE) { - this->publish_state(); this->fsm_state_ = STATE_STOPPING; this->target_position_ = TARGET_NONE; this->target_tilt_ = TARGET_NONE; From 791a53b279e91f3fc5890785d3d95fdf8e816b6a Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Fri, 3 Feb 2023 09:15:05 +0100 Subject: [PATCH 03/14] fixed recalibration if covers w/o tilt function --- .../time_based_tilt/time_based_tilt_cover.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index 5a9737d770..50fa060fdb 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -21,6 +21,11 @@ void TimeBasedTiltCover::dump_config() { ESP_LOGCONFIG(TAG, " Recalibration time: %.3fs", this->recalibration_time_ / 1e3f); } void TimeBasedTiltCover::setup() { + if ( this->tilt_close_duration_ == 0 || this->tilt_open_duration_ == 0 ) + { + this->tilt_close_duration_ = 0; + this->tilt_open_duration_ = 0; + } auto restore = this->restore_state_(); if (restore.has_value()) { restore->apply(this); @@ -133,7 +138,9 @@ void TimeBasedTiltCover::loop() { this->target_tilt_ = TARGET_NONE; this->last_publish_time_= now; - if ( ( this->position == COVER_CLOSED && this->tilt == COVER_CLOSED ) || ( this->position == COVER_OPEN && this->tilt == COVER_OPEN ) ) // start recalibration + if ( this->recalibration_time_ > 0 && + ((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED) || + (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; this->publish_state(false); @@ -144,7 +151,7 @@ void TimeBasedTiltCover::loop() { return; // only tilting w/o position change so no need to recompute position } - if ( now - this->last_publish_time_ > ( ( tilt_time / 5 ) > 1000 ? 1000 : ( tilt_time / 5 ) ) ){ + if ( now - this->last_publish_time_ > (( tilt_time / 5 ) > 1000 ? 1000 : ( tilt_time / 5 )) ){ this->publish_state(false); this->last_publish_time_= now; } @@ -168,10 +175,12 @@ void TimeBasedTiltCover::loop() { this->target_position_ = TARGET_NONE; this->last_publish_time_= now; - if ( ( this->position == COVER_CLOSED && this->tilt == COVER_CLOSED ) || ( this->position == COVER_OPEN && this->tilt == COVER_OPEN ) ) + if ( this->recalibration_time_ > 0 && + ((this->position == COVER_CLOSED && ( tilt_time == 0 || this->tilt == COVER_CLOSED) || + (this->position == COVER_OPEN && ( tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; - this->publish_state(false); + this->publish_state(false); } else { this->fsm_state_ = STATE_STOPPING; } From edf6c9e5f211b1f6f6bcf5e8f978c05a48b391eb Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Sat, 4 Feb 2023 19:16:43 +0100 Subject: [PATCH 04/14] fixes compilation error with esp-idf --- .../components/time_based_tilt/time_based_tilt_cover.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index 50fa060fdb..df4769d586 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -139,7 +139,7 @@ void TimeBasedTiltCover::loop() { this->last_publish_time_= now; if ( this->recalibration_time_ > 0 && - ((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED) || + (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; @@ -176,8 +176,8 @@ void TimeBasedTiltCover::loop() { this->last_publish_time_= now; if ( this->recalibration_time_ > 0 && - ((this->position == COVER_CLOSED && ( tilt_time == 0 || this->tilt == COVER_CLOSED) || - (this->position == COVER_OPEN && ( tilt_time == 0 || this->tilt == COVER_OPEN))))) + (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || + (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; this->publish_state(false); From 7c6c9344ced33c808b11cdfa9de9bb39931d7047 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Sat, 4 Feb 2023 21:55:43 +0100 Subject: [PATCH 05/14] cleaning --- esphome/components/time_based_tilt/cover.py | 28 +++++-- .../time_based_tilt/time_based_tilt_cover.cpp | 74 ++++++++----------- .../time_based_tilt/time_based_tilt_cover.h | 13 ++-- 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/esphome/components/time_based_tilt/cover.py b/esphome/components/time_based_tilt/cover.py index 6af94e1fa6..2bc1aa5509 100644 --- a/esphome/components/time_based_tilt/cover.py +++ b/esphome/components/time_based_tilt/cover.py @@ -13,7 +13,9 @@ from esphome.const import ( ) time_based_tilt_ns = cg.esphome_ns.namespace("time_based_tilt") -TimeBasedTiltCover = time_based_tilt_ns.class_("TimeBasedTiltCover", cover.Cover, cg.Component) +TimeBasedTiltCover = time_based_tilt_ns.class_( + "TimeBasedTiltCover", cover.Cover, cg.Component +) CONF_TILT_OPEN_DURATION = "tilt_open_duration" CONF_TILT_CLOSE_DURATION = "tilt_close_duration" @@ -32,12 +34,24 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds, cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds, cv.Optional(CONF_ASSUMED_STATE, default=True): cv.boolean, - cv.Optional(CONF_TILT_OPEN_DURATION, default="0ms"): cv.positive_time_period_milliseconds, - cv.Optional(CONF_TILT_CLOSE_DURATION, default="0ms"): cv.positive_time_period_milliseconds, - cv.Optional(CONF_INTERLOCK_WAIT_TIME, default="0ms"): cv.positive_time_period_milliseconds, - cv.Optional(CONF_RECALIBRATION_TIME, default="0ms"): cv.positive_time_period_milliseconds, - cv.Optional(CONF_INERTIA_OPEN_TIME, default="0ms"): cv.positive_time_period_milliseconds, - cv.Optional(CONF_INERTIA_CLOSE_TIME, default="0ms"): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_TILT_OPEN_DURATION, default="0ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_TILT_CLOSE_DURATION, default="0ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_INTERLOCK_WAIT_TIME, default="0ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_RECALIBRATION_TIME, default="0ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_INERTIA_OPEN_TIME, default="0ms" + ): cv.positive_time_period_milliseconds, + cv.Optional( + CONF_INERTIA_CLOSE_TIME, default="0ms" + ): cv.positive_time_period_milliseconds, } ).extend(cv.COMPONENT_SCHEMA) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index df4769d586..00b96bc77d 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -21,8 +21,7 @@ void TimeBasedTiltCover::dump_config() { ESP_LOGCONFIG(TAG, " Recalibration time: %.3fs", this->recalibration_time_ / 1e3f); } void TimeBasedTiltCover::setup() { - if ( this->tilt_close_duration_ == 0 || this->tilt_open_duration_ == 0 ) - { + if ( this->tilt_close_duration_ == 0 || this->tilt_open_duration_ == 0 ) { this->tilt_close_duration_ = 0; this->tilt_open_duration_ = 0; } @@ -71,10 +70,9 @@ void TimeBasedTiltCover::loop() { return; } - if ( this->fsm_state_ == STATE_STOPPING ) - { + if ( this->fsm_state_ == STATE_STOPPING ) { this->stop_trigger_->trigger(); - this->interlockedTime = millis(); + this->interlocked_time = millis(); this->interlocked_direction = this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; this->fsm_state_ = STATE_IDLE; this->last_operation_ = this->current_operation; @@ -83,8 +81,7 @@ void TimeBasedTiltCover::loop() { return; } - if ( this->fsm_state_ == STATE_IDLE && (this->target_position_ != TARGET_NONE || this->target_tilt_ != TARGET_NONE) ) - { + if ( this->fsm_state_ == STATE_IDLE && (this->target_position_ != TARGET_NONE || this->target_tilt_ != TARGET_NONE) ) { if (this->target_position_ != TARGET_NONE ) { this->current_operation = this->compute_direction(this->target_position_,this->position); @@ -93,7 +90,7 @@ void TimeBasedTiltCover::loop() { } if ( this->current_operation == this->interlocked_direction - && now - this->interlockedTime < this->interlock_wait_time_ ) return; + && now - this->interlocked_time < this->interlock_wait_time_ ) return; Trigger<> *trig = this->current_operation == COVER_OPERATION_CLOSING ? this->close_trigger_ : this->open_trigger_; @@ -104,8 +101,7 @@ void TimeBasedTiltCover::loop() { return; } - if ( this->fsm_state_ == STATE_MOVING ) - { + if ( this->fsm_state_ == STATE_MOVING ) { auto travel_time = now - this->last_recompute_time_; this->last_recompute_time_ = now; @@ -113,8 +109,7 @@ void TimeBasedTiltCover::loop() { float dir_factor = this->current_operation == COVER_OPERATION_CLOSING ? -1.0 : 1.0 ; auto inertia_time = this->current_operation == COVER_OPERATION_CLOSING ? this->inertia_close_time_ : this->inertia_open_time_ ; - if ( inertia_time > 0 && this->inertia * dir_factor < 0.5f ) // inertia before movement - { + if ( inertia_time > 0 && this->inertia * dir_factor < 0.5f ) { // inertia before movement auto inertia_step = dir_factor * travel_time / inertia_time; this->inertia += inertia_step; auto rest = this->inertia - clamp( this->inertia , -0.5f, 0.5f); @@ -126,20 +121,19 @@ void TimeBasedTiltCover::loop() { auto tilt_time = this->current_operation == COVER_OPERATION_CLOSING ? this->tilt_close_duration_ : this->tilt_open_duration_; - if ( tilt_time > 0 && ( this->tilt - 0.5f ) * dir_factor < 0.5f ) // tilting before movement - { + if ( tilt_time > 0 && ( this->tilt - 0.5f ) * dir_factor < 0.5f ) { // tilting before movement auto tilt_step = dir_factor * travel_time / tilt_time; this->tilt += tilt_step; auto rest = this->tilt - 0.5f - clamp( this->tilt - 0.5f , -0.5f, 0.5f); this->tilt = clamp( this->tilt , 0.0f, 1.0f); - if (this->target_position_ == TARGET_NONE && this->is_at_target_tilt_()){ // only tilting w/o position change + if (this->target_position_ == TARGET_NONE && this->is_at_target_tilt_()) { // only tilting w/o position change this->last_recompute_time_ = now; this->target_tilt_ = TARGET_NONE; this->last_publish_time_= now; - if ( this->recalibration_time_ > 0 && - (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || + if ( this->recalibration_time_ > 0 && + (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; @@ -151,9 +145,9 @@ void TimeBasedTiltCover::loop() { return; // only tilting w/o position change so no need to recompute position } - if ( now - this->last_publish_time_ > (( tilt_time / 5 ) > 1000 ? 1000 : ( tilt_time / 5 )) ){ - this->publish_state(false); - this->last_publish_time_= now; + if ( now - this->last_publish_time_ > (( tilt_time / 5 ) > 1000 ? 1000 : ( tilt_time / 5 )) ) { + this->publish_state(false); + this->last_publish_time_= now; } if ( ! rest ) return; // the movement has not yet actually started @@ -163,20 +157,19 @@ void TimeBasedTiltCover::loop() { auto move_time = this->current_operation == COVER_OPERATION_CLOSING ? this->close_duration_ : this->open_duration_ ; - if ( move_time > 0 && ( this->position - 0.5f ) * dir_factor < 0.5f ) - { + if ( move_time > 0 && ( this->position - 0.5f ) * dir_factor < 0.5f ) { auto move_step = dir_factor * travel_time / move_time; this->position += move_step; this->position = clamp( this->position , 0.0f, 1.0f); } - if (this->is_at_target_position_()){ + if (this->is_at_target_position_()) { this->last_recompute_time_ = now; this->target_position_ = TARGET_NONE; this->last_publish_time_= now; - if ( this->recalibration_time_ > 0 && - (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || + if ( this->recalibration_time_ > 0 && + (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; @@ -186,7 +179,7 @@ void TimeBasedTiltCover::loop() { } } - if ( now - this->last_publish_time_ > 1000 ){ + if ( now - this->last_publish_time_ > 1000 ) { this->publish_state(false); this->last_publish_time_= now; } @@ -207,7 +200,7 @@ void TimeBasedTiltCover::control(const CoverCall &call) { if (call.get_stop()) { this->target_position_ = TARGET_NONE; this->target_tilt_= TARGET_NONE; - if (this->fsm_state_ == STATE_MOVING){ + if (this->fsm_state_ == STATE_MOVING) { this->fsm_state_ = STATE_STOPPING; } return; @@ -224,11 +217,11 @@ void TimeBasedTiltCover::control(const CoverCall &call) { this->target_position_ = pos; this->target_tilt_ = til; - if (this->fsm_state_ == STATE_MOVING){ //TODO: check direction also on tilting + if (this->fsm_state_ == STATE_MOVING) { //TODO: check direction also on tilting auto direction = COVER_OPERATION_IDLE; if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { direction = this->compute_direction(this->target_position_ , this->position ); - } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt){ + } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { direction = this->compute_direction( this->target_tilt_ , this->tilt ); } @@ -240,50 +233,47 @@ void TimeBasedTiltCover::control(const CoverCall &call) { } else if (call.get_position().has_value()) { auto pos = *call.get_position(); - if ( pos == COVER_CLOSED && this->position == COVER_CLOSED && this->tilt != COVER_CLOSED ){ + if ( pos == COVER_CLOSED && this->position == COVER_CLOSED && this->tilt != COVER_CLOSED ) { pos = TARGET_NONE; this->target_tilt_ = COVER_CLOSED; - } else if ( pos == COVER_OPEN && this->position == COVER_OPEN && this->tilt != COVER_OPEN ){ + } else if ( pos == COVER_OPEN && this->position == COVER_OPEN && this->tilt != COVER_OPEN ) { pos = TARGET_NONE; this->target_tilt_ = COVER_OPEN; - } else if ( this->round_position(pos) == this->round_position(this->position) ){ + } else if ( this->round_position(pos) == this->round_position(this->position) ) { pos = TARGET_NONE; } this->target_position_ = pos; - if (this->fsm_state_ == STATE_MOVING){ + if (this->fsm_state_ == STATE_MOVING) { auto direction = COVER_OPERATION_IDLE; if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { direction = this->compute_direction(this->target_position_ , this->position ); this->target_tilt_ = TARGET_NONE; // unset previous target tilt - } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt){ + } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { direction = this->compute_direction( this->target_tilt_ , this->tilt ); } - if (direction != this->current_operation ) - { + if (direction != this->current_operation ) { this->fsm_state_ = STATE_STOPPING; } } } else if (call.get_tilt().has_value()) { auto til = *call.get_tilt(); - if ( this->round_position(til) == this->round_position(this->tilt) ) - { + if ( this->round_position(til) == this->round_position(this->tilt) ) { til = TARGET_NONE; } this->target_tilt_ = til; - if (this->fsm_state_ == STATE_MOVING){ + if (this->fsm_state_ == STATE_MOVING) { auto direction = COVER_OPERATION_IDLE; - if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt){ + if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { direction = this->compute_direction( this->target_tilt_ , this->tilt ); this->target_position_ = TARGET_NONE; } - if (direction != this->current_operation ) - { + if (direction != this->current_operation ) { this->fsm_state_ = STATE_STOPPING; } } diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.h b/esphome/components/time_based_tilt/time_based_tilt_cover.h index 974a5acc0c..75b6dc2e9e 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.h +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.h @@ -25,7 +25,7 @@ class TimeBasedTiltCover : public cover::Cover, public Component { void set_recalibration_time(uint32_t recalibration_time) { this->recalibration_time_ = recalibration_time; } void set_inertia_open_time(uint32_t inertia_time) { this->inertia_open_time_ = inertia_time; } void set_inertia_close_time(uint32_t inertia_time) { this->inertia_close_time_ = inertia_time; } - cover::CoverOperation compute_direction(float target, float current){ return target < current ? cover::COVER_OPERATION_CLOSING : cover::COVER_OPERATION_OPENING ; }; + cover::CoverOperation compute_direction(float target, float current) { return target < current ? cover::COVER_OPERATION_CLOSING : cover::COVER_OPERATION_OPENING ; }; float round_position(float pos) { return round(100 * pos)/100; }; cover::CoverTraits get_traits() override; void set_assumed_state(bool value) { this->assumed_state_ = value; } @@ -34,7 +34,7 @@ class TimeBasedTiltCover : public cover::Cover, public Component { void control(const cover::CoverCall &call) override; bool is_at_target_position_() const; bool is_at_target_tilt_() const; - + Trigger<> *open_trigger_{new Trigger<>()}; Trigger<> *close_trigger_{new Trigger<>()}; Trigger<> *stop_trigger_{new Trigger<>()}; @@ -52,13 +52,12 @@ class TimeBasedTiltCover : public cover::Cover, public Component { const float TARGET_NONE{-1}; enum State : uint8_t { - STATE_IDLE, - STATE_MOVING, - STATE_STOPPING, + STATE_IDLE, + STATE_MOVING, + STATE_STOPPING, STATE_CALIBRATING }; - Trigger<> *prev_command_trigger_{nullptr}; uint32_t last_recompute_time_{0}; uint32_t last_publish_time_{0}; float target_position_{TARGET_NONE}; @@ -69,7 +68,7 @@ class TimeBasedTiltCover : public cover::Cover, public Component { cover::CoverOperation last_operation_{cover::COVER_OPERATION_OPENING}; State fsm_state_{STATE_IDLE}; cover::CoverOperation interlocked_direction{cover::COVER_OPERATION_IDLE}; - uint32_t interlockedTime{0}; + uint32_t interlocked_time{0}; }; } // namespace time_based_tilt From 6e87770ae2f5d701077fc5d3587527406b7186fd Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Sat, 4 Feb 2023 22:28:18 +0100 Subject: [PATCH 06/14] cleaning --- esphome/components/time_based_tilt/cover.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/time_based_tilt/cover.py b/esphome/components/time_based_tilt/cover.py index 2bc1aa5509..b51576b305 100644 --- a/esphome/components/time_based_tilt/cover.py +++ b/esphome/components/time_based_tilt/cover.py @@ -32,7 +32,6 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( cv.Required(CONF_OPEN_DURATION): cv.positive_time_period_milliseconds, 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_ASSUMED_STATE, default=True): cv.boolean, cv.Optional( CONF_TILT_OPEN_DURATION, default="0ms" From a7d9152204d51251852a8107dfb17e726bc6d2dd Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Mon, 6 Feb 2023 19:39:55 +0100 Subject: [PATCH 07/14] Fixing a bug when issuing the stop command just after the start (between the transition from STATE_IDLE to STATE_MOVING). Now the STOP command always stops the cover even during recalibration. --- .../time_based_tilt/time_based_tilt_cover.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index 00b96bc77d..a40316d176 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -72,8 +72,12 @@ void TimeBasedTiltCover::loop() { if ( this->fsm_state_ == STATE_STOPPING ) { this->stop_trigger_->trigger(); - this->interlocked_time = millis(); - this->interlocked_direction = this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; + if (this->current_operation != COVER_OPERATION_IDLE){ + this->interlocked_time = millis(); + this->interlocked_direction = this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; + } else { + this->interlocked_direction = COVER_OPERATION_IDLE; + } this->fsm_state_ = STATE_IDLE; this->last_operation_ = this->current_operation; this->current_operation = COVER_OPERATION_IDLE; @@ -200,9 +204,7 @@ void TimeBasedTiltCover::control(const CoverCall &call) { if (call.get_stop()) { this->target_position_ = TARGET_NONE; this->target_tilt_= TARGET_NONE; - if (this->fsm_state_ == STATE_MOVING) { - this->fsm_state_ = STATE_STOPPING; - } + this->fsm_state_ = STATE_STOPPING; return; } if (call.get_position().has_value() && call.get_tilt().has_value() ) { From 0f8c3ebfd71cebeec3b7bc28c40fd572e56a9a97 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Sun, 24 Dec 2023 21:24:42 +0100 Subject: [PATCH 08/14] set supports stop --- esphome/components/time_based_tilt/time_based_tilt_cover.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index a40316d176..fdf406b5de 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -197,6 +197,7 @@ CoverTraits TimeBasedTiltCover::get_traits() { traits.set_supports_position(true); traits.set_supports_tilt(this->tilt_close_duration_ !=0 && this->tilt_open_duration_ !=0); traits.set_supports_toggle(true); + traits.set_supports_stop(true); traits.set_is_assumed_state(this->assumed_state_); return traits; } From 021fe6fc2e9863fb42ca5a0d85eebc8e46cb91a2 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Sun, 7 Jan 2024 14:20:03 +0100 Subject: [PATCH 09/14] added some comments --- esphome/components/time_based_tilt/cover.py | 2 ++ .../time_based_tilt/time_based_tilt_cover.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/esphome/components/time_based_tilt/cover.py b/esphome/components/time_based_tilt/cover.py index b51576b305..d3ca1ef69e 100644 --- a/esphome/components/time_based_tilt/cover.py +++ b/esphome/components/time_based_tilt/cover.py @@ -12,6 +12,8 @@ from esphome.const import ( CONF_ASSUMED_STATE, ) +CODEOWNERS = ["@klaudiusz223"] + time_based_tilt_ns = cg.esphome_ns.namespace("time_based_tilt") TimeBasedTiltCover = time_based_tilt_ns.class_( "TimeBasedTiltCover", cover.Cover, cg.Component diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index fdf406b5de..d0ad8a92d6 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -63,6 +63,7 @@ void TimeBasedTiltCover::loop() { const uint32_t now = millis(); + // recalibrating in extreme postions if ( this->fsm_state_ == STATE_CALIBRATING ) { if ( now - this->last_recompute_time_ >= this->recalibration_time_ ) { this->fsm_state_ = STATE_STOPPING; @@ -70,6 +71,7 @@ void TimeBasedTiltCover::loop() { return; } + // STOPPING - determining the direction of the last movement and the stopping time. Needed to support interlocking if ( this->fsm_state_ == STATE_STOPPING ) { this->stop_trigger_->trigger(); if (this->current_operation != COVER_OPERATION_IDLE){ @@ -85,6 +87,7 @@ void TimeBasedTiltCover::loop() { return; } + // if the cover is not moving, check whether the new targets are set and if they are, compute move direction if ( this->fsm_state_ == STATE_IDLE && (this->target_position_ != TARGET_NONE || this->target_tilt_ != TARGET_NONE) ) { if (this->target_position_ != TARGET_NONE ) { @@ -92,7 +95,7 @@ void TimeBasedTiltCover::loop() { } else { this->current_operation = this->compute_direction(this->target_tilt_,this->tilt); } - + // interlocking support if ( this->current_operation == this->interlocked_direction && now - this->interlocked_time < this->interlock_wait_time_ ) return; @@ -105,6 +108,7 @@ void TimeBasedTiltCover::loop() { return; } + //moving state if ( this->fsm_state_ == STATE_MOVING ) { auto travel_time = now - this->last_recompute_time_; @@ -136,6 +140,7 @@ void TimeBasedTiltCover::loop() { this->target_tilt_ = TARGET_NONE; this->last_publish_time_= now; + // If the cover is in extreme positions, run recalibration if ( this->recalibration_time_ > 0 && (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) @@ -172,6 +177,7 @@ void TimeBasedTiltCover::loop() { this->target_position_ = TARGET_NONE; this->last_publish_time_= now; + // If the cover is in extreme positions, run recalibration if ( this->recalibration_time_ > 0 && (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) @@ -220,7 +226,7 @@ void TimeBasedTiltCover::control(const CoverCall &call) { this->target_position_ = pos; this->target_tilt_ = til; - if (this->fsm_state_ == STATE_MOVING) { //TODO: check direction also on tilting + if (this->fsm_state_ == STATE_MOVING) { auto direction = COVER_OPERATION_IDLE; if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { direction = this->compute_direction(this->target_position_ , this->position ); From f2067538c2427ea37925dee025a462f3f6caa493 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Fri, 26 Jan 2024 01:08:04 +0100 Subject: [PATCH 10/14] static const --- esphome/components/time_based_tilt/time_based_tilt_cover.cpp | 2 ++ esphome/components/time_based_tilt/time_based_tilt_cover.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index d0ad8a92d6..6a0fe7c6fa 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -7,6 +7,8 @@ namespace time_based_tilt { static const char *const TAG = "time_based_tilt.cover"; +const float TimeBasedTiltCover::TARGET_NONE = -1; + using namespace esphome::cover; void TimeBasedTiltCover::dump_config() { diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.h b/esphome/components/time_based_tilt/time_based_tilt_cover.h index 75b6dc2e9e..137f93be77 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.h +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.h @@ -50,7 +50,7 @@ class TimeBasedTiltCover : public cover::Cover, public Component { uint32_t inertia_open_time_; uint32_t inertia_close_time_; - const float TARGET_NONE{-1}; + const static float TARGET_NONE; enum State : uint8_t { STATE_IDLE, STATE_MOVING, From a6b25f1eefb98c45b9ac0a1bd819e631059ad52d Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Fri, 26 Jan 2024 02:10:44 +0100 Subject: [PATCH 11/14] add test --- tests/test3.1.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 5cbdca91c1..e3c5a7786c 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -362,6 +362,7 @@ binary_sensor: - cover.toggle: time_based_cover - cover.toggle: endstop_cover - cover.toggle: current_based_cover + - cover.toggle: time_based_tilt_cover globals: - id: my_global_string @@ -554,6 +555,23 @@ cover: close_action: - switch.turn_on: gpio_switch2 close_duration: 4.5min + - platform: time_based_tilt + name: Time Based Cover with Tilt + id: time_based_tilt_cover + stop_action: + - switch.turn_on: gpio_switch1 + open_action: + - switch.turn_on: gpio_switch1 + open_duration: 5min + close_action: + - switch.turn_on: gpio_switch2 + close_duration: 4.5min + inertia_open_time: 300 ms + tilt_open_duration: 930 ms + inertia_close_time: 250 ms + tilt_close_duration: 900 ms + interlock_wait_time: 500ms + recalibration_time: 2500ms - platform: current_based name: Current Based Cover id: current_based_cover From 6705f3b8982b946c9eca274e2edfd84e1b837967 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Fri, 26 Jan 2024 03:16:14 +0100 Subject: [PATCH 12/14] update CODEOWNERS --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index db44317776..930b7b0d8b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -337,6 +337,7 @@ esphome/components/template/alarm_control_panel/* @grahambrown11 @hwstar esphome/components/text/* @mauritskorse esphome/components/thermostat/* @kbx81 esphome/components/time/* @OttoWinter +esphome/components/time_based_tilt/* @klaudiusz223 esphome/components/tlc5947/* @rnauber esphome/components/tm1621/* @Philippe12 esphome/components/tm1637/* @glmnet From 0c0f2bf58e297a145007117ea54c28c17012e9f7 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Fri, 26 Jan 2024 03:48:26 +0100 Subject: [PATCH 13/14] fix formatting --- .../time_based_tilt/time_based_tilt_cover.cpp | 238 +++++++++--------- .../time_based_tilt/time_based_tilt_cover.h | 13 +- 2 files changed, 124 insertions(+), 127 deletions(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index 6a0fe7c6fa..24a0f28212 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -23,7 +23,7 @@ void TimeBasedTiltCover::dump_config() { ESP_LOGCONFIG(TAG, " Recalibration time: %.3fs", this->recalibration_time_ / 1e3f); } void TimeBasedTiltCover::setup() { - if ( this->tilt_close_duration_ == 0 || this->tilt_open_duration_ == 0 ) { + if (this->tilt_close_duration_ == 0 || this->tilt_open_duration_ == 0) { this->tilt_close_duration_ = 0; this->tilt_open_duration_ = 0; } @@ -60,25 +60,26 @@ bool TimeBasedTiltCover::is_at_target_tilt_() const { } void TimeBasedTiltCover::loop() { - - if ( this->fsm_state_ == STATE_IDLE && this->target_position_ == TARGET_NONE && this->target_tilt_ == TARGET_NONE ) return; + if (this->fsm_state_ == STATE_IDLE && this->target_position_ == TARGET_NONE && this->target_tilt_ == TARGET_NONE) + return; const uint32_t now = millis(); // recalibrating in extreme postions - if ( this->fsm_state_ == STATE_CALIBRATING ) { - if ( now - this->last_recompute_time_ >= this->recalibration_time_ ) { + if (this->fsm_state_ == STATE_CALIBRATING) { + if (now - this->last_recompute_time_ >= this->recalibration_time_) { this->fsm_state_ = STATE_STOPPING; } return; } // STOPPING - determining the direction of the last movement and the stopping time. Needed to support interlocking - if ( this->fsm_state_ == STATE_STOPPING ) { + if (this->fsm_state_ == STATE_STOPPING) { this->stop_trigger_->trigger(); - if (this->current_operation != COVER_OPERATION_IDLE){ + if (this->current_operation != COVER_OPERATION_IDLE) { this->interlocked_time = millis(); - this->interlocked_direction = this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; + this->interlocked_direction = + this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; } else { this->interlocked_direction = COVER_OPERATION_IDLE; } @@ -90,16 +91,16 @@ void TimeBasedTiltCover::loop() { } // if the cover is not moving, check whether the new targets are set and if they are, compute move direction - if ( this->fsm_state_ == STATE_IDLE && (this->target_position_ != TARGET_NONE || this->target_tilt_ != TARGET_NONE) ) { - - if (this->target_position_ != TARGET_NONE ) { - this->current_operation = this->compute_direction(this->target_position_,this->position); + if (this->fsm_state_ == STATE_IDLE && (this->target_position_ != TARGET_NONE || this->target_tilt_ != TARGET_NONE)) { + if (this->target_position_ != TARGET_NONE) { + this->current_operation = this->compute_direction(this->target_position_, this->position); } else { - this->current_operation = this->compute_direction(this->target_tilt_,this->tilt); + this->current_operation = this->compute_direction(this->target_tilt_, this->tilt); } // interlocking support - if ( this->current_operation == this->interlocked_direction - && now - this->interlocked_time < this->interlock_wait_time_ ) return; + if (this->current_operation == this->interlocked_direction && + now - this->interlocked_time < this->interlock_wait_time_) + return; Trigger<> *trig = this->current_operation == COVER_OPERATION_CLOSING ? this->close_trigger_ : this->open_trigger_; @@ -110,43 +111,44 @@ void TimeBasedTiltCover::loop() { return; } - //moving state - if ( this->fsm_state_ == STATE_MOVING ) { - + // moving state + if (this->fsm_state_ == STATE_MOVING) { auto travel_time = now - this->last_recompute_time_; this->last_recompute_time_ = now; - float dir_factor = this->current_operation == COVER_OPERATION_CLOSING ? -1.0 : 1.0 ; - auto inertia_time = this->current_operation == COVER_OPERATION_CLOSING ? this->inertia_close_time_ : this->inertia_open_time_ ; + float dir_factor = this->current_operation == COVER_OPERATION_CLOSING ? -1.0 : 1.0; + auto inertia_time = + this->current_operation == COVER_OPERATION_CLOSING ? this->inertia_close_time_ : this->inertia_open_time_; - if ( inertia_time > 0 && this->inertia * dir_factor < 0.5f ) { // inertia before movement + if (inertia_time > 0 && this->inertia * dir_factor < 0.5f) { // inertia before movement auto inertia_step = dir_factor * travel_time / inertia_time; this->inertia += inertia_step; - auto rest = this->inertia - clamp( this->inertia , -0.5f, 0.5f); - this->inertia = clamp( this->inertia, -0.5f, 0.5f); + auto rest = this->inertia - clamp(this->inertia, -0.5f, 0.5f); + this->inertia = clamp(this->inertia, -0.5f, 0.5f); - if ( ! rest ) return; // the movement has not yet actually started - travel_time = dir_factor * rest * inertia_time; // actual movement time taking inertia into account + if (!rest) + return; // the movement has not yet actually started + travel_time = dir_factor * rest * inertia_time; // actual movement time taking inertia into account } - auto tilt_time = this->current_operation == COVER_OPERATION_CLOSING ? this->tilt_close_duration_ : this->tilt_open_duration_; + auto tilt_time = + this->current_operation == COVER_OPERATION_CLOSING ? this->tilt_close_duration_ : this->tilt_open_duration_; - if ( tilt_time > 0 && ( this->tilt - 0.5f ) * dir_factor < 0.5f ) { // tilting before movement - auto tilt_step = dir_factor * travel_time / tilt_time; + if (tilt_time > 0 && (this->tilt - 0.5f) * dir_factor < 0.5f) { // tilting before movement + auto tilt_step = dir_factor * travel_time / tilt_time; this->tilt += tilt_step; - auto rest = this->tilt - 0.5f - clamp( this->tilt - 0.5f , -0.5f, 0.5f); - this->tilt = clamp( this->tilt , 0.0f, 1.0f); + auto rest = this->tilt - 0.5f - clamp(this->tilt - 0.5f, -0.5f, 0.5f); + this->tilt = clamp(this->tilt, 0.0f, 1.0f); - if (this->target_position_ == TARGET_NONE && this->is_at_target_tilt_()) { // only tilting w/o position change + if (this->target_position_ == TARGET_NONE && this->is_at_target_tilt_()) { // only tilting w/o position change this->last_recompute_time_ = now; this->target_tilt_ = TARGET_NONE; - this->last_publish_time_= now; + this->last_publish_time_ = now; // If the cover is in extreme positions, run recalibration - if ( this->recalibration_time_ > 0 && - (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || - (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) - { + if (this->recalibration_time_ > 0 && + (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || + (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; this->publish_state(false); } else { @@ -156,34 +158,34 @@ void TimeBasedTiltCover::loop() { return; // only tilting w/o position change so no need to recompute position } - if ( now - this->last_publish_time_ > (( tilt_time / 5 ) > 1000 ? 1000 : ( tilt_time / 5 )) ) { + if (now - this->last_publish_time_ > ((tilt_time / 5) > 1000 ? 1000 : (tilt_time / 5))) { this->publish_state(false); - this->last_publish_time_= now; + this->last_publish_time_ = now; } - if ( ! rest ) return; // the movement has not yet actually started + if (!rest) + return; // the movement has not yet actually started - travel_time = dir_factor * rest * tilt_time; // actual movement time taking tilt into account + travel_time = dir_factor * rest * tilt_time; // actual movement time taking tilt into account } - auto move_time = this->current_operation == COVER_OPERATION_CLOSING ? this->close_duration_ : this->open_duration_ ; + auto move_time = this->current_operation == COVER_OPERATION_CLOSING ? this->close_duration_ : this->open_duration_; - if ( move_time > 0 && ( this->position - 0.5f ) * dir_factor < 0.5f ) { - auto move_step = dir_factor * travel_time / move_time; + if (move_time > 0 && (this->position - 0.5f) * dir_factor < 0.5f) { + auto move_step = dir_factor * travel_time / move_time; this->position += move_step; - this->position = clamp( this->position , 0.0f, 1.0f); + this->position = clamp(this->position, 0.0f, 1.0f); } if (this->is_at_target_position_()) { this->last_recompute_time_ = now; this->target_position_ = TARGET_NONE; - this->last_publish_time_= now; + this->last_publish_time_ = now; // If the cover is in extreme positions, run recalibration - if ( this->recalibration_time_ > 0 && - (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || - (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) - { + if (this->recalibration_time_ > 0 && + (((this->position == COVER_CLOSED && (tilt_time == 0 || this->tilt == COVER_CLOSED)) || + (this->position == COVER_OPEN && (tilt_time == 0 || this->tilt == COVER_OPEN))))) { this->fsm_state_ = STATE_CALIBRATING; this->publish_state(false); } else { @@ -191,19 +193,18 @@ void TimeBasedTiltCover::loop() { } } - if ( now - this->last_publish_time_ > 1000 ) { - this->publish_state(false); - this->last_publish_time_= now; + if (now - this->last_publish_time_ > 1000) { + this->publish_state(false); + this->last_publish_time_ = now; } } - } float TimeBasedTiltCover::get_setup_priority() const { return setup_priority::DATA; } CoverTraits TimeBasedTiltCover::get_traits() { auto traits = CoverTraits(); traits.set_supports_position(true); - traits.set_supports_tilt(this->tilt_close_duration_ !=0 && this->tilt_open_duration_ !=0); + traits.set_supports_tilt(this->tilt_close_duration_ != 0 && this->tilt_open_duration_ != 0); traits.set_supports_toggle(true); traits.set_supports_stop(true); traits.set_is_assumed_state(this->assumed_state_); @@ -212,82 +213,81 @@ CoverTraits TimeBasedTiltCover::get_traits() { void TimeBasedTiltCover::control(const CoverCall &call) { if (call.get_stop()) { this->target_position_ = TARGET_NONE; - this->target_tilt_= TARGET_NONE; + this->target_tilt_ = TARGET_NONE; this->fsm_state_ = STATE_STOPPING; return; } - if (call.get_position().has_value() && call.get_tilt().has_value() ) { - auto pos = *call.get_position(); - auto til = *call.get_tilt(); + if (call.get_position().has_value() && call.get_tilt().has_value()) { + auto pos = *call.get_position(); + auto til = *call.get_tilt(); - if (this->round_position(pos) == this->round_position(this->position)) - pos = TARGET_NONE; - if (this->round_position(til) == this->round_position(this->tilt)) - til = TARGET_NONE; + if (this->round_position(pos) == this->round_position(this->position)) + pos = TARGET_NONE; + if (this->round_position(til) == this->round_position(this->tilt)) + til = TARGET_NONE; - this->target_position_ = pos; - this->target_tilt_ = til; + this->target_position_ = pos; + this->target_tilt_ = til; - if (this->fsm_state_ == STATE_MOVING) { - auto direction = COVER_OPERATION_IDLE; - if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { - direction = this->compute_direction(this->target_position_ , this->position ); - } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { - direction = this->compute_direction( this->target_tilt_ , this->tilt ); - } - - if (direction != this->current_operation ) - { - this->fsm_state_ = STATE_STOPPING; - } + if (this->fsm_state_ == STATE_MOVING) { + auto direction = COVER_OPERATION_IDLE; + if (this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { + direction = this->compute_direction(this->target_position_, this->position); + } else if (this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { + direction = this->compute_direction(this->target_tilt_, this->tilt); } + + if (direction != this->current_operation) { + this->fsm_state_ = STATE_STOPPING; + } + } } else if (call.get_position().has_value()) { - auto pos = *call.get_position(); + auto pos = *call.get_position(); - if ( pos == COVER_CLOSED && this->position == COVER_CLOSED && this->tilt != COVER_CLOSED ) { - pos = TARGET_NONE; - this->target_tilt_ = COVER_CLOSED; - } else if ( pos == COVER_OPEN && this->position == COVER_OPEN && this->tilt != COVER_OPEN ) { - pos = TARGET_NONE; - this->target_tilt_ = COVER_OPEN; - } else if ( this->round_position(pos) == this->round_position(this->position) ) { - pos = TARGET_NONE; - } + if (pos == COVER_CLOSED && this->position == COVER_CLOSED && this->tilt != COVER_CLOSED) { + pos = TARGET_NONE; + this->target_tilt_ = COVER_CLOSED; + } else if (pos == COVER_OPEN && this->position == COVER_OPEN && this->tilt != COVER_OPEN) { + pos = TARGET_NONE; + this->target_tilt_ = COVER_OPEN; + } else if (this->round_position(pos) == this->round_position(this->position)) { + pos = TARGET_NONE; + } - this->target_position_ = pos; + this->target_position_ = pos; - if (this->fsm_state_ == STATE_MOVING) { - auto direction = COVER_OPERATION_IDLE; - if ( this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { - direction = this->compute_direction(this->target_position_ , this->position ); - this->target_tilt_ = TARGET_NONE; // unset previous target tilt - } else if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { - direction = this->compute_direction( this->target_tilt_ , this->tilt ); - } - - if (direction != this->current_operation ) { - this->fsm_state_ = STATE_STOPPING; - } + if (this->fsm_state_ == STATE_MOVING) { + auto direction = COVER_OPERATION_IDLE; + if (this->target_position_ != TARGET_NONE && this->target_position_ != this->position) { + direction = this->compute_direction(this->target_position_, this->position); + this->target_tilt_ = TARGET_NONE; // unset previous target tilt + } else if (this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { + direction = this->compute_direction(this->target_tilt_, this->tilt); } - } else if (call.get_tilt().has_value()) { - auto til = *call.get_tilt(); - if ( this->round_position(til) == this->round_position(this->tilt) ) { - til = TARGET_NONE; - } - this->target_tilt_ = til; - - if (this->fsm_state_ == STATE_MOVING) { - auto direction = COVER_OPERATION_IDLE; - if ( this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { - direction = this->compute_direction( this->target_tilt_ , this->tilt ); - this->target_position_ = TARGET_NONE; - } - - if (direction != this->current_operation ) { - this->fsm_state_ = STATE_STOPPING; - } + if (direction != this->current_operation) { + this->fsm_state_ = STATE_STOPPING; } + } + } else if (call.get_tilt().has_value()) { + auto til = *call.get_tilt(); + if (this->round_position(til) == this->round_position(this->tilt)) { + til = TARGET_NONE; + } + + this->target_tilt_ = til; + + if (this->fsm_state_ == STATE_MOVING) { + auto direction = COVER_OPERATION_IDLE; + if (this->target_tilt_ != TARGET_NONE && this->target_tilt_ != this->tilt) { + direction = this->compute_direction(this->target_tilt_, this->tilt); + this->target_position_ = TARGET_NONE; + } + + if (direction != this->current_operation) { + this->fsm_state_ = STATE_STOPPING; + } + } } if (call.get_toggle().has_value()) { @@ -296,11 +296,11 @@ void TimeBasedTiltCover::control(const CoverCall &call) { this->target_position_ = TARGET_NONE; this->target_tilt_ = TARGET_NONE; } else { - if ( this->position == COVER_CLOSED && this->tilt == COVER_CLOSED ) { + if (this->position == COVER_CLOSED && this->tilt == COVER_CLOSED) { this->target_position_ = COVER_OPEN; - } else if ( this->position == COVER_OPEN && this->tilt == COVER_OPEN ) { + } else if (this->position == COVER_OPEN && this->tilt == COVER_OPEN) { this->target_position_ = COVER_CLOSED; - } else if ( this->last_operation_ == COVER_OPERATION_CLOSING ) { + } else if (this->last_operation_ == COVER_OPERATION_CLOSING) { if (this->position != COVER_OPEN) { this->target_position_ = COVER_OPEN; } else { diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.h b/esphome/components/time_based_tilt/time_based_tilt_cover.h index 137f93be77..7aaeaa5c85 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.h +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.h @@ -25,8 +25,10 @@ class TimeBasedTiltCover : public cover::Cover, public Component { void set_recalibration_time(uint32_t recalibration_time) { this->recalibration_time_ = recalibration_time; } void set_inertia_open_time(uint32_t inertia_time) { this->inertia_open_time_ = inertia_time; } void set_inertia_close_time(uint32_t inertia_time) { this->inertia_close_time_ = inertia_time; } - cover::CoverOperation compute_direction(float target, float current) { return target < current ? cover::COVER_OPERATION_CLOSING : cover::COVER_OPERATION_OPENING ; }; - float round_position(float pos) { return round(100 * pos)/100; }; + cover::CoverOperation compute_direction(float target, float current) { + return target < current ? cover::COVER_OPERATION_CLOSING : cover::COVER_OPERATION_OPENING; + }; + float round_position(float pos) { return round(100 * pos) / 100; }; cover::CoverTraits get_traits() override; void set_assumed_state(bool value) { this->assumed_state_ = value; } @@ -51,12 +53,7 @@ class TimeBasedTiltCover : public cover::Cover, public Component { uint32_t inertia_close_time_; const static float TARGET_NONE; - enum State : uint8_t { - STATE_IDLE, - STATE_MOVING, - STATE_STOPPING, - STATE_CALIBRATING - }; + enum State : uint8_t { STATE_IDLE, STATE_MOVING, STATE_STOPPING, STATE_CALIBRATING }; uint32_t last_recompute_time_{0}; uint32_t last_publish_time_{0}; From 6ce030e66f41ce7fcd6a6ea5cc8186049074a788 Mon Sep 17 00:00:00 2001 From: klaudiusz223 Date: Sun, 28 Jan 2024 17:02:18 +0100 Subject: [PATCH 14/14] cleaning up --- .../time_based_tilt/time_based_tilt_cover.cpp | 18 +++++++++--------- .../time_based_tilt/time_based_tilt_cover.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp index 24a0f28212..dde95891b9 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.cpp +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.cpp @@ -77,11 +77,11 @@ void TimeBasedTiltCover::loop() { if (this->fsm_state_ == STATE_STOPPING) { this->stop_trigger_->trigger(); if (this->current_operation != COVER_OPERATION_IDLE) { - this->interlocked_time = millis(); - this->interlocked_direction = + this->interlocked_time_ = millis(); + this->interlocked_direction_ = this->current_operation == COVER_OPERATION_CLOSING ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING; } else { - this->interlocked_direction = COVER_OPERATION_IDLE; + this->interlocked_direction_ = COVER_OPERATION_IDLE; } this->fsm_state_ = STATE_IDLE; this->last_operation_ = this->current_operation; @@ -98,8 +98,8 @@ void TimeBasedTiltCover::loop() { this->current_operation = this->compute_direction(this->target_tilt_, this->tilt); } // interlocking support - if (this->current_operation == this->interlocked_direction && - now - this->interlocked_time < this->interlock_wait_time_) + if (this->current_operation == this->interlocked_direction_ && + now - this->interlocked_time_ < this->interlock_wait_time_) return; Trigger<> *trig = this->current_operation == COVER_OPERATION_CLOSING ? this->close_trigger_ : this->open_trigger_; @@ -120,11 +120,11 @@ void TimeBasedTiltCover::loop() { auto inertia_time = this->current_operation == COVER_OPERATION_CLOSING ? this->inertia_close_time_ : this->inertia_open_time_; - if (inertia_time > 0 && this->inertia * dir_factor < 0.5f) { // inertia before movement + if (inertia_time > 0 && this->inertia_ * dir_factor < 0.5f) { // inertia before movement auto inertia_step = dir_factor * travel_time / inertia_time; - this->inertia += inertia_step; - auto rest = this->inertia - clamp(this->inertia, -0.5f, 0.5f); - this->inertia = clamp(this->inertia, -0.5f, 0.5f); + this->inertia_ += inertia_step; + auto rest = this->inertia_ - clamp(this->inertia_, -0.5f, 0.5f); + this->inertia_ = clamp(this->inertia_, -0.5f, 0.5f); if (!rest) return; // the movement has not yet actually started diff --git a/esphome/components/time_based_tilt/time_based_tilt_cover.h b/esphome/components/time_based_tilt/time_based_tilt_cover.h index 7aaeaa5c85..9384c26b7e 100644 --- a/esphome/components/time_based_tilt/time_based_tilt_cover.h +++ b/esphome/components/time_based_tilt/time_based_tilt_cover.h @@ -59,13 +59,13 @@ class TimeBasedTiltCover : public cover::Cover, public Component { uint32_t last_publish_time_{0}; float target_position_{TARGET_NONE}; float target_tilt_{TARGET_NONE}; - float inertia{0.0f}; + float inertia_{0.0f}; bool has_built_in_endstop_{false}; bool assumed_state_{false}; cover::CoverOperation last_operation_{cover::COVER_OPERATION_OPENING}; State fsm_state_{STATE_IDLE}; - cover::CoverOperation interlocked_direction{cover::COVER_OPERATION_IDLE}; - uint32_t interlocked_time{0}; + cover::CoverOperation interlocked_direction_{cover::COVER_OPERATION_IDLE}; + uint32_t interlocked_time_{0}; }; } // namespace time_based_tilt