feedback component: Support for overshoot_duration

Allows the cover to overshoot max open-closed positions by some specific duration
This commit is contained in:
Achilleas Kotsis 2024-09-23 00:23:38 +03:00
parent 1829e68730
commit d99347404c
3 changed files with 34 additions and 7 deletions

View file

@ -1,18 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation from esphome import automation
import esphome.codegen as cg
from esphome.components import binary_sensor, cover from esphome.components import binary_sensor, cover
import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ASSUMED_STATE, CONF_ASSUMED_STATE,
CONF_CLOSE_ACTION, CONF_CLOSE_ACTION,
CONF_CLOSE_DURATION, CONF_CLOSE_DURATION,
CONF_CLOSE_ENDSTOP, CONF_CLOSE_ENDSTOP,
CONF_ID, CONF_ID,
CONF_MAX_DURATION,
CONF_OPEN_ACTION, CONF_OPEN_ACTION,
CONF_OPEN_DURATION, CONF_OPEN_DURATION,
CONF_OPEN_ENDSTOP, CONF_OPEN_ENDSTOP,
CONF_STOP_ACTION, CONF_STOP_ACTION,
CONF_MAX_DURATION,
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
) )
@ -24,6 +24,7 @@ CONF_HAS_BUILT_IN_ENDSTOP = "has_built_in_endstop"
CONF_INFER_ENDSTOP_FROM_MOVEMENT = "infer_endstop_from_movement" CONF_INFER_ENDSTOP_FROM_MOVEMENT = "infer_endstop_from_movement"
CONF_DIRECTION_CHANGE_WAIT_TIME = "direction_change_wait_time" CONF_DIRECTION_CHANGE_WAIT_TIME = "direction_change_wait_time"
CONF_ACCELERATION_WAIT_TIME = "acceleration_wait_time" CONF_ACCELERATION_WAIT_TIME = "acceleration_wait_time"
CONF_OVERSHOOT_DURATION = "overshoot_duration"
CONF_OBSTACLE_ROLLBACK = "obstacle_rollback" CONF_OBSTACLE_ROLLBACK = "obstacle_rollback"
endstop_ns = cg.esphome_ns.namespace("feedback") endstop_ns = cg.esphome_ns.namespace("feedback")
@ -77,6 +78,9 @@ CONFIG_FEEDBACK_COVER_BASE_SCHEMA = cover.COVER_SCHEMA.extend(
cv.Optional( cv.Optional(
CONF_ACCELERATION_WAIT_TIME, "0s" CONF_ACCELERATION_WAIT_TIME, "0s"
): cv.positive_time_period_milliseconds, ): cv.positive_time_period_milliseconds,
cv.Optional(
CONF_OVERSHOOT_DURATION, "0s"
): cv.positive_time_period_milliseconds,
cv.Optional(CONF_OBSTACLE_ROLLBACK, default="10%"): cv.percentage, cv.Optional(CONF_OBSTACLE_ROLLBACK, default="10%"): cv.percentage,
}, },
).extend(cv.COMPONENT_SCHEMA) ).extend(cv.COMPONENT_SCHEMA)
@ -154,4 +158,5 @@ async def to_code(config):
var.set_direction_change_waittime(config[CONF_DIRECTION_CHANGE_WAIT_TIME]) var.set_direction_change_waittime(config[CONF_DIRECTION_CHANGE_WAIT_TIME])
) )
cg.add(var.set_acceleration_wait_time(config[CONF_ACCELERATION_WAIT_TIME])) cg.add(var.set_acceleration_wait_time(config[CONF_ACCELERATION_WAIT_TIME]))
cg.add(var.set_overshoot_duration(config[CONF_OVERSHOOT_DURATION]))
cg.add(var.set_obstacle_rollback(config[CONF_OBSTACLE_ROLLBACK])) cg.add(var.set_obstacle_rollback(config[CONF_OBSTACLE_ROLLBACK]))

View file

@ -77,6 +77,9 @@ void FeedbackCover::dump_config() {
if (this->acceleration_wait_time_) { if (this->acceleration_wait_time_) {
ESP_LOGCONFIG(TAG, " Acceleration wait time: %.1fs", this->acceleration_wait_time_ / 1e3f); ESP_LOGCONFIG(TAG, " Acceleration wait time: %.1fs", this->acceleration_wait_time_ / 1e3f);
} }
if (this->overshoot_duration_) {
ESP_LOGCONFIG(TAG, " Overshoot duration: %.1fs", this->overshoot_duration_ / 1e3f);
}
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
if (this->obstacle_rollback_ && (this->open_obstacle_ != nullptr || this->close_obstacle_ != nullptr)) { if (this->obstacle_rollback_ && (this->open_obstacle_ != nullptr || this->close_obstacle_ != nullptr)) {
ESP_LOGCONFIG(TAG, " Obstacle rollback: %.1f%%", this->obstacle_rollback_ * 100); ESP_LOGCONFIG(TAG, " Obstacle rollback: %.1f%%", this->obstacle_rollback_ * 100);
@ -229,11 +232,26 @@ void FeedbackCover::loop() {
// (stoping from endstop sensor is handled in callback) // (stoping from endstop sensor is handled in callback)
if (this->current_trigger_operation_ != COVER_OPERATION_IDLE) { if (this->current_trigger_operation_ != COVER_OPERATION_IDLE) {
if (this->is_at_target_()) { if (this->is_at_target_()) {
if (this->has_built_in_endstop_ && if (this->target_position_ == COVER_OPEN || this->target_position_ == COVER_CLOSED) {
(this->target_position_ == COVER_OPEN || this->target_position_ == COVER_CLOSED)) { if (this->has_built_in_endstop_) {
// Don't trigger stop, let the cover stop by itself. // Don't trigger stop, let the cover stop by itself.
this->set_current_operation_(COVER_OPERATION_IDLE, true); this->set_current_operation_(COVER_OPERATION_IDLE, true);
} else if (this->overshoot_duration_) {
// We want to overshoot a bit on cover being totaly open or closed, in order to make sure cover is synced
if (!this->start_overshoot_time_) {
// We just started overshooting, save time for comparison
this->start_overshoot_time_ = now;
} else if (now - this->start_overshoot_time_ > this->overshoot_duration_) {
// We overshot enough, stop the cover
ESP_LOGD(TAG, "'%s' - Overshoot duration reached. Stopping cover.", this->name_.c_str());
this->start_direction_(COVER_OPERATION_IDLE);
}
} else { } else {
// No overshoot_duration, stop immediately at open-close
this->start_direction_(COVER_OPERATION_IDLE);
}
} else {
// Not on open-close position, stop immediately
this->start_direction_(COVER_OPERATION_IDLE); this->start_direction_(COVER_OPERATION_IDLE);
} }
} else if (now - this->start_dir_time_ > this->max_duration_) { } else if (now - this->start_dir_time_ > this->max_duration_) {
@ -335,6 +353,7 @@ void FeedbackCover::start_direction_(CoverOperation dir) {
switch (dir) { switch (dir) {
case COVER_OPERATION_IDLE: case COVER_OPERATION_IDLE:
trig = this->stop_trigger_; trig = this->stop_trigger_;
this->start_overshoot_time_ = 0;
break; break;
case COVER_OPERATION_OPENING: case COVER_OPERATION_OPENING:
this->last_operation_ = dir; this->last_operation_ = dir;

View file

@ -35,6 +35,7 @@ class FeedbackCover : public cover::Cover, public Component {
void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; } void set_has_built_in_endstop(bool value) { this->has_built_in_endstop_ = value; }
void set_assumed_state(bool value) { this->assumed_state_ = value; } void set_assumed_state(bool value) { this->assumed_state_ = value; }
void set_max_duration(uint32_t max_duration) { this->max_duration_ = max_duration; } void set_max_duration(uint32_t max_duration) { this->max_duration_ = max_duration; }
void set_overshoot_duration(uint32_t overshoot_duration) { this->overshoot_duration_ = overshoot_duration; }
void set_obstacle_rollback(float obstacle_rollback) { this->obstacle_rollback_ = obstacle_rollback; } void set_obstacle_rollback(float obstacle_rollback) { this->obstacle_rollback_ = obstacle_rollback; }
void set_update_interval(uint32_t interval) { this->update_interval_ = interval; } void set_update_interval(uint32_t interval) { this->update_interval_ = interval; }
void set_infer_endstop(bool infer_endstop) { this->infer_endstop_ = infer_endstop; } void set_infer_endstop(bool infer_endstop) { this->infer_endstop_ = infer_endstop; }
@ -69,6 +70,7 @@ class FeedbackCover : public cover::Cover, public Component {
uint32_t open_duration_{0}; uint32_t open_duration_{0};
uint32_t close_duration_{0}; uint32_t close_duration_{0};
uint32_t max_duration_{UINT32_MAX}; uint32_t max_duration_{UINT32_MAX};
uint32_t overshoot_duration_{0};
optional<uint32_t> direction_change_waittime_{}; optional<uint32_t> direction_change_waittime_{};
uint32_t acceleration_wait_time_{0}; uint32_t acceleration_wait_time_{0};
bool has_built_in_endstop_{false}; bool has_built_in_endstop_{false};
@ -82,6 +84,7 @@ class FeedbackCover : public cover::Cover, public Component {
uint32_t last_recompute_time_{0}; uint32_t last_recompute_time_{0};
uint32_t start_dir_time_{0}; uint32_t start_dir_time_{0};
uint32_t last_publish_time_{0}; uint32_t last_publish_time_{0};
uint32_t start_overshoot_time_{0};
float target_position_{0}; float target_position_{0};
uint32_t update_interval_{1000}; uint32_t update_interval_{1000};
}; };