From 9630c60f4d2f4cb37550ea3f728fb27777c46ce0 Mon Sep 17 00:00:00 2001 From: Adam Bogocz Date: Wed, 6 Nov 2024 22:33:57 +0000 Subject: [PATCH] [time_based] : Implemented support for time based tilt --- esphome/components/time_based/cover.py | 11 +++++-- .../time_based/time_based_cover.cpp | 31 ++++++++++++++++++- .../components/time_based/time_based_cover.h | 2 ++ tests/components/time_based/common.yaml | 1 + 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/esphome/components/time_based/cover.py b/esphome/components/time_based/cover.py index a14a08ccad..0a9eb683e9 100644 --- a/esphome/components/time_based/cover.py +++ b/esphome/components/time_based/cover.py @@ -1,15 +1,15 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import automation +import esphome.codegen as cg from esphome.components import cover +import esphome.config_validation as cv from esphome.const import ( + CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, CONF_ID, CONF_OPEN_ACTION, CONF_OPEN_DURATION, CONF_STOP_ACTION, - CONF_ASSUMED_STATE, ) time_based_ns = cg.esphome_ns.namespace("time_based") @@ -17,6 +17,7 @@ TimeBasedCover = time_based_ns.class_("TimeBasedCover", cover.Cover, cg.Componen CONF_HAS_BUILT_IN_ENDSTOP = "has_built_in_endstop" CONF_MANUAL_CONTROL = "manual_control" +CONF_TILT_DURATION = "tilt_duration" CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( { @@ -29,6 +30,9 @@ CONFIG_SCHEMA = cover.COVER_SCHEMA.extend( cv.Optional(CONF_HAS_BUILT_IN_ENDSTOP, default=False): cv.boolean, cv.Optional(CONF_MANUAL_CONTROL, default=False): cv.boolean, cv.Optional(CONF_ASSUMED_STATE, default=True): cv.boolean, + cv.Optional( + CONF_TILT_DURATION, default=0 + ): cv.positive_time_period_milliseconds, } ).extend(cv.COMPONENT_SCHEMA) @@ -55,3 +59,4 @@ async def to_code(config): cg.add(var.set_has_built_in_endstop(config[CONF_HAS_BUILT_IN_ENDSTOP])) cg.add(var.set_manual_control(config[CONF_MANUAL_CONTROL])) cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE])) + cg.add(var.set_tilt_duration(config[CONF_TILT_DURATION])) diff --git a/esphome/components/time_based/time_based_cover.cpp b/esphome/components/time_based/time_based_cover.cpp index e1936d5ee1..661916f9e4 100644 --- a/esphome/components/time_based/time_based_cover.cpp +++ b/esphome/components/time_based/time_based_cover.cpp @@ -13,6 +13,9 @@ void TimeBasedCover::dump_config() { LOG_COVER("", "Time Based Cover", this); ESP_LOGCONFIG(TAG, " Open Duration: %.1fs", this->open_duration_ / 1e3f); ESP_LOGCONFIG(TAG, " Close Duration: %.1fs", this->close_duration_ / 1e3f); + + if (this->tilt_duration_ > 0) + ESP_LOGCONFIG(TAG, " Tilt Duration: %ums", this->tilt_duration_); } void TimeBasedCover::setup() { auto restore = this->restore_state_(); @@ -54,6 +57,7 @@ CoverTraits TimeBasedCover::get_traits() { traits.set_supports_stop(true); traits.set_supports_position(true); traits.set_supports_toggle(true); + traits.set_supports_tilt(this->tilt_duration_ > 0); traits.set_is_assumed_state(this->assumed_state_); return traits; } @@ -103,6 +107,26 @@ void TimeBasedCover::control(const CoverCall &call) { this->start_direction_(op); } } + + if (call.get_tilt().has_value()) { + auto requested_tilt = *call.get_tilt(); + if (requested_tilt != this->tilt) { + CoverOperation op; + uint32_t operation_duration_ms; + if (requested_tilt < this->tilt) { + op = COVER_OPERATION_CLOSING; + operation_duration_ms = this->close_duration_; + } else { + op = COVER_OPERATION_OPENING; + operation_duration_ms = this->open_duration_; + } + + const auto tilt_change_duration_ms = (requested_tilt - this->tilt) * this->tilt_duration_; + const auto new_pos = tilt_change_duration_ms / operation_duration_ms; + this->target_position_ += new_pos; + this->start_direction_(op); + } + } } void TimeBasedCover::stop_prev_trigger_() { if (this->prev_command_trigger_ != nullptr) { @@ -173,9 +197,14 @@ void TimeBasedCover::recompute_position_() { } const uint32_t now = millis(); - this->position += dir * (now - this->last_recompute_time_) / action_dur; + const uint32_t step_duration = now - this->last_recompute_time_; + + this->position += dir * (step_duration) / action_dur; this->position = clamp(this->position, 0.0f, 1.0f); + this->tilt += dir * (step_duration) / this->tilt_duration_; + this->tilt = clamp(this->tilt, 0.0f, 1.0f); + this->last_recompute_time_ = now; } diff --git a/esphome/components/time_based/time_based_cover.h b/esphome/components/time_based/time_based_cover.h index 42cf66c2ab..f2f7518909 100644 --- a/esphome/components/time_based/time_based_cover.h +++ b/esphome/components/time_based/time_based_cover.h @@ -19,6 +19,7 @@ class TimeBasedCover : public cover::Cover, public Component { 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_duration(uint32_t tilt_duration_ms) { this->tilt_duration_ = tilt_duration_ms; } cover::CoverTraits get_traits() override; void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; } void set_manual_control(bool value) { this->manual_control_ = value; } @@ -39,6 +40,7 @@ class TimeBasedCover : public cover::Cover, public Component { Trigger<> *close_trigger_{new Trigger<>()}; uint32_t close_duration_; Trigger<> *stop_trigger_{new Trigger<>()}; + uint32_t tilt_duration_; Trigger<> *prev_command_trigger_{nullptr}; uint32_t last_recompute_time_{0}; diff --git a/tests/components/time_based/common.yaml b/tests/components/time_based/common.yaml index 48c86de90f..ff3f36b3bb 100644 --- a/tests/components/time_based/common.yaml +++ b/tests/components/time_based/common.yaml @@ -10,3 +10,4 @@ cover: close_action: - logger.log: close_action close_duration: 4.5min + tilt_duration: 1s