ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
cover.cpp
Go to the documentation of this file.
1#include "cover.h"
4#include "esphome/core/log.h"
6
7#include <strings.h>
8
9namespace esphome::cover {
10
11ESPHOME_LOG_TAG(TAG, "cover");
12
13const LogString *cover_command_to_str(float pos) {
14 if (pos == COVER_OPEN) {
15 return LOG_STR("OPEN");
16 } else if (pos == COVER_CLOSED) {
17 return LOG_STR("CLOSE");
18 } else {
19 return LOG_STR("UNKNOWN");
20 }
21}
22// Cover operation strings indexed by CoverOperation enum (0-2): IDLE, OPENING, CLOSING, plus UNKNOWN
23PROGMEM_STRING_TABLE(CoverOperationStrings, "IDLE", "OPENING", "CLOSING", "UNKNOWN");
24
26 return CoverOperationStrings::get_log_str(static_cast<uint8_t>(op), CoverOperationStrings::LAST_INDEX);
27}
28
29Cover::Cover() : position{COVER_OPEN} {}
30
31CoverCall::CoverCall(Cover *parent) : parent_(parent) {}
32CoverCall &CoverCall::set_command(const char *command) {
33 if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("OPEN")) == 0) {
34 this->set_command_open();
35 } else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("CLOSE")) == 0) {
36 this->set_command_close();
37 } else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("STOP")) == 0) {
38 this->set_command_stop();
39 } else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("TOGGLE")) == 0) {
40 this->set_command_toggle();
41 } else {
42 ESP_LOGW(TAG, "'%s' - Unrecognized command %s", LOG_STR_ARG(this->parent_->get_log_name()), command);
43 }
44 return *this;
45}
47 this->position_ = COVER_OPEN;
48 return *this;
49}
51 this->position_ = COVER_CLOSED;
52 return *this;
53}
55 this->stop_ = true;
56 return *this;
57}
59 this->stop_tilt_ = true;
60 return *this;
61}
63 this->toggle_ = true;
64 return *this;
65}
67 this->position_ = position;
68 return *this;
69}
71 this->tilt_ = tilt;
72 return *this;
73}
75 ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
76 auto traits = this->parent_->get_traits();
77 this->validate_();
78 if (this->stop_) {
79 ESP_LOGV(TAG, " Command: STOP");
80 }
81 if (this->stop_tilt_) {
82 ESP_LOGV(TAG, " Command: STOP_TILT");
83 }
84 if (this->position_.has_value()) {
85 if (traits.get_supports_position()) {
86 ESP_LOGV(TAG, " Position: %.0f%%", *this->position_ * 100.0f);
87 } else {
88 ESP_LOGV(TAG, " Command: %s", LOG_STR_ARG(cover_command_to_str(*this->position_)));
89 }
90 }
91 if (this->tilt_.has_value()) {
92 ESP_LOGV(TAG, " Tilt: %.0f%%", *this->tilt_ * 100.0f);
93 }
94 if (this->toggle_.has_value()) {
95 ESP_LOGV(TAG, " Command: TOGGLE");
96 }
97 this->parent_->control(*this);
98}
99const optional<float> &CoverCall::get_position() const { return this->position_; }
100const optional<float> &CoverCall::get_tilt() const { return this->tilt_; }
101const optional<bool> &CoverCall::get_toggle() const { return this->toggle_; }
103 auto traits = this->parent_->get_traits();
104 const char *name = LOG_STR_ARG(this->parent_->get_log_name());
105
106 if (this->position_.has_value()) {
107 auto pos = *this->position_;
108 if (!traits.get_supports_position() && pos != COVER_OPEN && pos != COVER_CLOSED) {
109 ESP_LOGW(TAG, "'%s': position unsupported", name);
110 this->position_.reset();
111 } else if (pos < 0.0f || pos > 1.0f) {
112 ESP_LOGW(TAG, "'%s': position %.2f out of range", name, pos);
113 this->position_ = clamp(pos, 0.0f, 1.0f);
114 }
115 }
116 if (this->tilt_.has_value()) {
117 auto tilt = *this->tilt_;
118 if (!traits.get_supports_tilt()) {
119 ESP_LOGW(TAG, "'%s': tilt unsupported", name);
120 this->tilt_.reset();
121 } else if (tilt < 0.0f || tilt > 1.0f) {
122 ESP_LOGW(TAG, "'%s': tilt %.2f out of range", name, tilt);
123 this->tilt_ = clamp(tilt, 0.0f, 1.0f);
124 }
125 }
126 if (this->toggle_.has_value()) {
127 if (!traits.get_supports_toggle()) {
128 ESP_LOGW(TAG, "'%s': toggle unsupported", name);
129 this->toggle_.reset();
130 }
131 }
132 if (this->stop_tilt_) {
133 if (!traits.get_supports_stop_tilt()) {
134 ESP_LOGW(TAG, "'%s': stop tilt unsupported", name);
135 this->stop_tilt_ = false;
136 } else if (this->tilt_.has_value()) {
137 ESP_LOGW(TAG, "'%s': cannot tilt when stopping tilt", name);
138 this->tilt_.reset();
139 }
140 }
141 if (this->stop_) {
142 if (this->position_.has_value() || this->tilt_.has_value() || this->toggle_.has_value()) {
143 ESP_LOGW(TAG, "'%s': cannot position/tilt/toggle when stopping", name);
144 this->position_.reset();
145 this->tilt_.reset();
146 this->toggle_.reset();
147 }
148 }
149}
151 this->stop_ = stop;
152 return *this;
153}
155 this->stop_tilt_ = stop_tilt;
156 return *this;
157}
158void Cover::publish_state(bool save) {
159 this->position = clamp(this->position, 0.0f, 1.0f);
160 this->tilt = clamp(this->tilt, 0.0f, 1.0f);
161
162 ESP_LOGV(TAG, "'%s' >>", LOG_STR_ARG(this->get_log_name()));
163 auto traits = this->get_traits();
164 if (traits.get_supports_position()) {
165 ESP_LOGV(TAG, " Position: %.0f%%", this->position * 100.0f);
166 } else {
167 if (this->position == COVER_OPEN) {
168 ESP_LOGV(TAG, " State: OPEN");
169 } else if (this->position == COVER_CLOSED) {
170 ESP_LOGV(TAG, " State: CLOSED");
171 } else {
172 ESP_LOGV(TAG, " State: UNKNOWN");
173 }
174 }
175 if (traits.get_supports_tilt()) {
176 ESP_LOGV(TAG, " Tilt: %.0f%%", this->tilt * 100.0f);
177 }
178 ESP_LOGV(TAG, " Current Operation: %s", LOG_STR_ARG(cover_operation_to_str(this->current_operation)));
179
180 this->state_callback_.call();
181#if defined(USE_COVER) && defined(USE_CONTROLLER_REGISTRY)
182 ControllerRegistry::notify_cover_update(this);
183#endif
184
185 if (save) {
186 CoverRestoreState restore{};
187 memset(&restore, 0, sizeof(restore));
188 restore.position = this->position;
189 if (traits.get_supports_tilt()) {
190 restore.tilt = this->tilt;
191 }
192 this->rtc_.save(&restore);
193 }
194}
195optional<CoverRestoreState> Cover::restore_state_() {
197 CoverRestoreState recovered{};
198 if (!this->rtc_.load(&recovered))
199 return {};
200 return recovered;
201}
202
204 auto call = cover->make_call();
205 auto traits = cover->get_traits();
206 call.set_position(this->position);
207 if (traits.get_supports_tilt())
208 call.set_tilt(this->tilt);
209 return call;
210}
212 cover->position = this->position;
213 cover->tilt = this->tilt;
214 cover->publish_state();
215}
216
217} // namespace esphome::cover
const LogString * get_log_name() const
Get the name for a "%s" log argument (LOG_STR_ARG).
ESPPreferenceObject make_entity_preference(uint32_t version=0)
Create a preference object for storing this entity's state/settings.
const optional< float > & get_tilt() const
Definition cover.cpp:100
CoverCall & set_command_toggle()
Set the command to toggle the cover.
Definition cover.cpp:62
const optional< bool > & get_toggle() const
Definition cover.cpp:101
optional< float > tilt_
Definition cover.h:68
CoverCall & set_command_open()
Set the command to open the cover.
Definition cover.cpp:46
CoverCall & set_command_close()
Set the command to close the cover.
Definition cover.cpp:50
CoverCall & set_command(const char *command)
Set the command as a string, "STOP", "OPEN", "CLOSE", "TOGGLE".
Definition cover.cpp:32
void perform()
Perform the cover call.
Definition cover.cpp:74
CoverCall & set_position(float position)
Set the call to a certain target position.
Definition cover.cpp:66
CoverCall & set_command_stop()
Set the command to stop the cover.
Definition cover.cpp:54
CoverCall & set_stop_tilt(bool stop_tilt)
Set whether this cover call should stop the cover tilt.
Definition cover.cpp:154
optional< float > position_
Definition cover.h:67
CoverCall & set_command_stop_tilt()
Set the command to stop the cover tilt.
Definition cover.cpp:58
const optional< float > & get_position() const
Definition cover.cpp:99
CoverCall(Cover *parent)
Definition cover.cpp:31
CoverCall & set_tilt(float tilt)
Set the call to a certain target tilt.
Definition cover.cpp:70
optional< bool > toggle_
Definition cover.h:69
CoverCall & set_stop(bool stop)
Set whether this cover call should stop the cover.
Definition cover.cpp:150
Base class for all cover devices.
Definition cover.h:115
CoverOperation current_operation
The current operation of the cover (idle, opening, closing).
Definition cover.h:120
optional< CoverRestoreState > restore_state_()
Definition cover.cpp:195
void publish_state(bool save=true)
Publish the current state of the cover.
Definition cover.cpp:158
CoverCall make_call()
Construct a new cover call used to control the cover.
Definition cover.h:131
LazyCallbackManager< void()> state_callback_
Definition cover.h:158
float tilt
The current tilt value of the cover from 0.0 to 1.0.
Definition cover.h:128
float position
The position of the cover from 0.0 (fully closed) to 1.0 (fully open).
Definition cover.h:126
ESPPreferenceObject rtc_
Definition cover.h:160
virtual CoverTraits get_traits()=0
virtual void control(const CoverCall &call)=0
float position
Definition cover.h:0
float tilt
Definition cover.h:1
const LogString * cover_operation_to_str(CoverOperation op)
Definition cover.cpp:25
ESPHOME_LOG_TAG(TAG, "cover")
const LogString * cover_command_to_str(float pos)
Definition cover.cpp:13
CoverOperation
Enum encoding the current operation of a cover.
Definition cover.h:84
PROGMEM_STRING_TABLE(CoverOperationStrings, "IDLE", "OPENING", "CLOSING", "UNKNOWN")
size_t size_t pos
Definition helpers.h:1255
Struct used to store the restored state of a cover.
Definition cover.h:73
void apply(Cover *cover)
Apply these settings to the cover.
Definition cover.cpp:211
CoverCall to_call(Cover *cover)
Convert this struct to a cover call that can be performed.
Definition cover.cpp:203