mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
Add cover toggle support (#1809)
* Add cover toggle support Step through open/stop/close/stop sequence with every toggle * Move the cover toggle logic to perform() * Add clang-tidy CI suggestion * Implement cover toggle action as cover trait * Handle toggle correctly if cover fully closed on POR * Fix CI finding * Add deprecated warning * Don't add already deprecated interface Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl> * Don't add already deprecated interface Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl> * Don't add already deprecated interface Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl> Co-authored-by: Mueller, Daniel <daniel.mueller@karlstorz.com> Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
parent
e30f17f64f
commit
2eb5f89d82
8 changed files with 70 additions and 1 deletions
|
@ -59,6 +59,7 @@ validate_cover_operation = cv.enum(COVER_OPERATIONS, upper=True)
|
|||
OpenAction = cover_ns.class_("OpenAction", automation.Action)
|
||||
CloseAction = cover_ns.class_("CloseAction", automation.Action)
|
||||
StopAction = cover_ns.class_("StopAction", automation.Action)
|
||||
ToggleAction = cover_ns.class_("ToggleAction", automation.Action)
|
||||
ControlAction = cover_ns.class_("ControlAction", automation.Action)
|
||||
CoverPublishAction = cover_ns.class_("CoverPublishAction", automation.Action)
|
||||
CoverIsOpenCondition = cover_ns.class_("CoverIsOpenCondition", Condition)
|
||||
|
@ -119,6 +120,12 @@ async def cover_stop_to_code(config, action_id, template_arg, args):
|
|||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action("cover.toggle", ToggleAction, COVER_ACTION_SCHEMA)
|
||||
def cover_toggle_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
COVER_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(Cover),
|
||||
|
|
|
@ -37,6 +37,16 @@ template<typename... Ts> class StopAction : public Action<Ts...> {
|
|||
Cover *cover_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class ToggleAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit ToggleAction(Cover *cover) : cover_(cover) {}
|
||||
|
||||
void play(Ts... x) override { this->cover_->make_call().set_command_toggle().perform(); }
|
||||
|
||||
protected:
|
||||
Cover *cover_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class ControlAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit ControlAction(Cover *cover) : cover_(cover) {}
|
||||
|
|
|
@ -43,6 +43,8 @@ CoverCall &CoverCall::set_command(const char *command) {
|
|||
this->set_command_close();
|
||||
} else if (strcasecmp(command, "STOP") == 0) {
|
||||
this->set_command_stop();
|
||||
} else if (strcasecmp(command, "TOGGLE") == 0) {
|
||||
this->set_command_toggle();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized command %s", this->parent_->get_name().c_str(), command);
|
||||
}
|
||||
|
@ -60,6 +62,10 @@ CoverCall &CoverCall::set_command_stop() {
|
|||
this->stop_ = true;
|
||||
return *this;
|
||||
}
|
||||
CoverCall &CoverCall::set_command_toggle() {
|
||||
this->toggle_ = true;
|
||||
return *this;
|
||||
}
|
||||
CoverCall &CoverCall::set_position(float position) {
|
||||
this->position_ = position;
|
||||
return *this;
|
||||
|
@ -85,10 +91,14 @@ void CoverCall::perform() {
|
|||
if (this->tilt_.has_value()) {
|
||||
ESP_LOGD(TAG, " Tilt: %.0f%%", *this->tilt_ * 100.0f);
|
||||
}
|
||||
if (this->toggle_.has_value()) {
|
||||
ESP_LOGD(TAG, " Command: TOGGLE");
|
||||
}
|
||||
this->parent_->control(*this);
|
||||
}
|
||||
const optional<float> &CoverCall::get_position() const { return this->position_; }
|
||||
const optional<float> &CoverCall::get_tilt() const { return this->tilt_; }
|
||||
const optional<bool> &CoverCall::get_toggle() const { return this->toggle_; }
|
||||
void CoverCall::validate_() {
|
||||
auto traits = this->parent_->get_traits();
|
||||
if (this->position_.has_value()) {
|
||||
|
@ -111,6 +121,12 @@ void CoverCall::validate_() {
|
|||
this->tilt_ = clamp(tilt, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
if (this->toggle_.has_value()) {
|
||||
if (!traits.get_supports_toggle()) {
|
||||
ESP_LOGW(TAG, "'%s' - This cover device does not support toggle!", this->parent_->get_name().c_str());
|
||||
this->toggle_.reset();
|
||||
}
|
||||
}
|
||||
if (this->stop_) {
|
||||
if (this->position_.has_value()) {
|
||||
ESP_LOGW(TAG, "Cannot set position when stopping a cover!");
|
||||
|
@ -120,6 +136,10 @@ void CoverCall::validate_() {
|
|||
ESP_LOGW(TAG, "Cannot set tilt when stopping a cover!");
|
||||
this->tilt_.reset();
|
||||
}
|
||||
if (this->toggle_.has_value()) {
|
||||
ESP_LOGW(TAG, "Cannot set toggle when stopping a cover!");
|
||||
this->toggle_.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
CoverCall &CoverCall::set_stop(bool stop) {
|
||||
|
|
|
@ -29,7 +29,7 @@ class CoverCall {
|
|||
public:
|
||||
CoverCall(Cover *parent);
|
||||
|
||||
/// Set the command as a string, "STOP", "OPEN", "CLOSE".
|
||||
/// Set the command as a string, "STOP", "OPEN", "CLOSE", "TOGGLE".
|
||||
CoverCall &set_command(const char *command);
|
||||
/// Set the command to open the cover.
|
||||
CoverCall &set_command_open();
|
||||
|
@ -37,6 +37,8 @@ class CoverCall {
|
|||
CoverCall &set_command_close();
|
||||
/// Set the command to stop the cover.
|
||||
CoverCall &set_command_stop();
|
||||
/// Set the command to toggle the cover.
|
||||
CoverCall &set_command_toggle();
|
||||
/// Set the call to a certain target position.
|
||||
CoverCall &set_position(float position);
|
||||
/// Set the call to a certain target tilt.
|
||||
|
@ -50,6 +52,7 @@ class CoverCall {
|
|||
const optional<float> &get_position() const;
|
||||
bool get_stop() const;
|
||||
const optional<float> &get_tilt() const;
|
||||
const optional<bool> &get_toggle() const;
|
||||
|
||||
protected:
|
||||
void validate_();
|
||||
|
@ -58,6 +61,7 @@ class CoverCall {
|
|||
bool stop_{false};
|
||||
optional<float> position_{};
|
||||
optional<float> tilt_{};
|
||||
optional<bool> toggle_{};
|
||||
};
|
||||
|
||||
/// Struct used to store the restored state of a cover
|
||||
|
|
|
@ -13,11 +13,14 @@ class CoverTraits {
|
|||
void set_supports_position(bool supports_position) { this->supports_position_ = supports_position; }
|
||||
bool get_supports_tilt() const { return this->supports_tilt_; }
|
||||
void set_supports_tilt(bool supports_tilt) { this->supports_tilt_ = supports_tilt; }
|
||||
bool get_supports_toggle() const { return this->supports_toggle_; }
|
||||
void set_supports_toggle(bool supports_toggle) { this->supports_toggle_ = supports_toggle; }
|
||||
|
||||
protected:
|
||||
bool is_assumed_state_{false};
|
||||
bool supports_position_{false};
|
||||
bool supports_tilt_{false};
|
||||
bool supports_toggle_{false};
|
||||
};
|
||||
|
||||
} // namespace cover
|
||||
|
|
|
@ -52,6 +52,7 @@ float TimeBasedCover::get_setup_priority() const { return setup_priority::DATA;
|
|||
CoverTraits TimeBasedCover::get_traits() {
|
||||
auto traits = CoverTraits();
|
||||
traits.set_supports_position(true);
|
||||
traits.set_supports_toggle(true);
|
||||
traits.set_is_assumed_state(this->assumed_state_);
|
||||
return traits;
|
||||
}
|
||||
|
@ -60,6 +61,20 @@ void TimeBasedCover::control(const CoverCall &call) {
|
|||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->publish_state();
|
||||
}
|
||||
if (call.get_toggle().has_value()) {
|
||||
if (this->current_operation != COVER_OPERATION_IDLE) {
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->publish_state();
|
||||
} else {
|
||||
if (this->position == COVER_CLOSED || this->last_operation_ == COVER_OPERATION_CLOSING) {
|
||||
this->target_position_ = COVER_OPEN;
|
||||
this->start_direction_(COVER_OPERATION_OPENING);
|
||||
} else {
|
||||
this->target_position_ = COVER_CLOSED;
|
||||
this->start_direction_(COVER_OPERATION_CLOSING);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (call.get_position().has_value()) {
|
||||
auto pos = *call.get_position();
|
||||
if (pos == this->position) {
|
||||
|
@ -105,9 +120,11 @@ void TimeBasedCover::start_direction_(CoverOperation dir) {
|
|||
trig = this->stop_trigger_;
|
||||
break;
|
||||
case COVER_OPERATION_OPENING:
|
||||
this->last_operation_ = dir;
|
||||
trig = this->open_trigger_;
|
||||
break;
|
||||
case COVER_OPERATION_CLOSING:
|
||||
this->last_operation_ = dir;
|
||||
trig = this->close_trigger_;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -45,6 +45,7 @@ class TimeBasedCover : public cover::Cover, public Component {
|
|||
float target_position_{0};
|
||||
bool has_built_in_endstop_{false};
|
||||
bool assumed_state_{false};
|
||||
cover::CoverOperation last_operation_{cover::COVER_OPERATION_OPENING};
|
||||
};
|
||||
|
||||
} // namespace time_based
|
||||
|
|
|
@ -729,6 +729,12 @@ binary_sensor:
|
|||
id: r0_sensor
|
||||
name: 'R0 Sensor'
|
||||
component_name: page0.r0
|
||||
- platform: template
|
||||
id: 'cover_toggle'
|
||||
on_press:
|
||||
then:
|
||||
- cover.toggle: time_based_cover
|
||||
|
||||
globals:
|
||||
- id: my_global_string
|
||||
type: std::string
|
||||
|
@ -1018,6 +1024,7 @@ cover:
|
|||
max_duration: 10min
|
||||
- platform: time_based
|
||||
name: Time Based Cover
|
||||
id: time_based_cover
|
||||
stop_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
open_action:
|
||||
|
|
Loading…
Reference in a new issue