ESPHome 2026.3.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
11static const char *const 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", this->parent_->get_name().c_str(), 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->toggle_ = true;
60 return *this;
61}
63 this->position_ = position;
64 return *this;
65}
67 this->tilt_ = tilt;
68 return *this;
69}
71 ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
72 auto traits = this->parent_->get_traits();
73 this->validate_();
74 if (this->stop_) {
75 ESP_LOGD(TAG, " Command: STOP");
76 }
77 if (this->position_.has_value()) {
78 if (traits.get_supports_position()) {
79 ESP_LOGD(TAG, " Position: %.0f%%", *this->position_ * 100.0f);
80 } else {
81 ESP_LOGD(TAG, " Command: %s", LOG_STR_ARG(cover_command_to_str(*this->position_)));
82 }
83 }
84 if (this->tilt_.has_value()) {
85 ESP_LOGD(TAG, " Tilt: %.0f%%", *this->tilt_ * 100.0f);
86 }
87 if (this->toggle_.has_value()) {
88 ESP_LOGD(TAG, " Command: TOGGLE");
89 }
90 this->parent_->control(*this);
91}
92const optional<float> &CoverCall::get_position() const { return this->position_; }
93const optional<float> &CoverCall::get_tilt() const { return this->tilt_; }
94const optional<bool> &CoverCall::get_toggle() const { return this->toggle_; }
96 auto traits = this->parent_->get_traits();
97 const char *name = this->parent_->get_name().c_str();
98
99 if (this->position_.has_value()) {
100 auto pos = *this->position_;
101 if (!traits.get_supports_position() && pos != COVER_OPEN && pos != COVER_CLOSED) {
102 ESP_LOGW(TAG, "'%s': position unsupported", name);
103 this->position_.reset();
104 } else if (pos < 0.0f || pos > 1.0f) {
105 ESP_LOGW(TAG, "'%s': position %.2f out of range", name, pos);
106 this->position_ = clamp(pos, 0.0f, 1.0f);
107 }
108 }
109 if (this->tilt_.has_value()) {
110 auto tilt = *this->tilt_;
111 if (!traits.get_supports_tilt()) {
112 ESP_LOGW(TAG, "'%s': tilt unsupported", name);
113 this->tilt_.reset();
114 } else if (tilt < 0.0f || tilt > 1.0f) {
115 ESP_LOGW(TAG, "'%s': tilt %.2f out of range", name, tilt);
116 this->tilt_ = clamp(tilt, 0.0f, 1.0f);
117 }
118 }
119 if (this->toggle_.has_value()) {
120 if (!traits.get_supports_toggle()) {
121 ESP_LOGW(TAG, "'%s': toggle unsupported", name);
122 this->toggle_.reset();
123 }
124 }
125 if (this->stop_) {
126 if (this->position_.has_value() || this->tilt_.has_value() || this->toggle_.has_value()) {
127 ESP_LOGW(TAG, "'%s': cannot position/tilt/toggle when stopping", name);
128 this->position_.reset();
129 this->tilt_.reset();
130 this->toggle_.reset();
131 }
132 }
133}
135 this->stop_ = stop;
136 return *this;
137}
138bool CoverCall::get_stop() const { return this->stop_; }
139
140CoverCall Cover::make_call() { return {this}; }
141
142void Cover::add_on_state_callback(std::function<void()> &&f) { this->state_callback_.add(std::move(f)); }
143void Cover::publish_state(bool save) {
144 this->position = clamp(this->position, 0.0f, 1.0f);
145 this->tilt = clamp(this->tilt, 0.0f, 1.0f);
146
147 ESP_LOGD(TAG, "'%s' >>", this->name_.c_str());
148 auto traits = this->get_traits();
149 if (traits.get_supports_position()) {
150 ESP_LOGD(TAG, " Position: %.0f%%", this->position * 100.0f);
151 } else {
152 if (this->position == COVER_OPEN) {
153 ESP_LOGD(TAG, " State: OPEN");
154 } else if (this->position == COVER_CLOSED) {
155 ESP_LOGD(TAG, " State: CLOSED");
156 } else {
157 ESP_LOGD(TAG, " State: UNKNOWN");
158 }
159 }
160 if (traits.get_supports_tilt()) {
161 ESP_LOGD(TAG, " Tilt: %.0f%%", this->tilt * 100.0f);
162 }
163 ESP_LOGD(TAG, " Current Operation: %s", LOG_STR_ARG(cover_operation_to_str(this->current_operation)));
164
165 this->state_callback_.call();
166#if defined(USE_COVER) && defined(USE_CONTROLLER_REGISTRY)
168#endif
169
170 if (save) {
171 CoverRestoreState restore{};
172 memset(&restore, 0, sizeof(restore));
173 restore.position = this->position;
174 if (traits.get_supports_tilt()) {
175 restore.tilt = this->tilt;
176 }
177 this->rtc_.save(&restore);
178 }
179}
182 CoverRestoreState recovered{};
183 if (!this->rtc_.load(&recovered))
184 return {};
185 return recovered;
186}
187
188bool Cover::is_fully_open() const { return this->position == COVER_OPEN; }
189bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; }
190
192 auto call = cover->make_call();
193 auto traits = cover->get_traits();
194 call.set_position(this->position);
195 if (traits.get_supports_tilt())
196 call.set_tilt(this->tilt);
197 return call;
198}
200 cover->position = this->position;
201 cover->tilt = this->tilt;
202 cover->publish_state();
203}
204
205} // namespace esphome::cover
static void notify_cover_update(cover::Cover *obj)
bool save(const T *src)
Definition preferences.h:21
const StringRef & get_name() const
ESPPreferenceObject make_entity_preference(uint32_t version=0)
Create a preference object for storing this entity's state/settings.
constexpr const char * c_str() const
Definition string_ref.h:73
const optional< float > & get_tilt() const
Definition cover.cpp:93
CoverCall & set_command_toggle()
Set the command to toggle the cover.
Definition cover.cpp:58
const optional< bool > & get_toggle() const
Definition cover.cpp:94
optional< float > tilt_
Definition cover.h:63
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:70
CoverCall & set_position(float position)
Set the call to a certain target position.
Definition cover.cpp:62
CoverCall & set_command_stop()
Set the command to stop the cover.
Definition cover.cpp:54
bool get_stop() const
Definition cover.cpp:138
optional< float > position_
Definition cover.h:62
const optional< float > & get_position() const
Definition cover.cpp:92
CoverCall(Cover *parent)
Definition cover.cpp:31
CoverCall & set_tilt(float tilt)
Set the call to a certain target tilt.
Definition cover.cpp:66
optional< bool > toggle_
Definition cover.h:64
CoverCall & set_stop(bool stop)
Set whether this cover call should stop the cover.
Definition cover.cpp:134
Base class for all cover devices.
Definition cover.h:110
CoverOperation current_operation
The current operation of the cover (idle, opening, closing).
Definition cover.h:115
optional< CoverRestoreState > restore_state_()
Definition cover.cpp:180
void publish_state(bool save=true)
Publish the current state of the cover.
Definition cover.cpp:143
void add_on_state_callback(std::function< void()> &&f)
Definition cover.cpp:142
CoverCall make_call()
Construct a new cover call used to control the cover.
Definition cover.cpp:140
LazyCallbackManager< void()> state_callback_
Definition cover.h:153
float tilt
The current tilt value of the cover from 0.0 to 1.0.
Definition cover.h:123
float position
The position of the cover from 0.0 (fully closed) to 1.0 (fully open).
Definition cover.h:121
bool is_fully_closed() const
Helper method to check if the cover is fully closed. Equivalent to comparing .position against 0....
Definition cover.cpp:189
ESPPreferenceObject rtc_
Definition cover.h:155
virtual CoverTraits get_traits()=0
bool is_fully_open() const
Helper method to check if the cover is fully open. Equivalent to comparing .position against 1....
Definition cover.cpp:188
virtual void control(const CoverCall &call)=0
bool has_value() const
Definition optional.h:92
float position
Definition cover.h:0
float tilt
Definition cover.h:1
const LogString * cover_operation_to_str(CoverOperation op)
Definition cover.cpp:25
const LogString * cover_command_to_str(float pos)
Definition cover.cpp:13
CoverOperation
Enum encoding the current operation of a cover.
Definition cover.h:79
PROGMEM_STRING_TABLE(CoverOperationStrings, "IDLE", "OPENING", "CLOSING", "UNKNOWN")
size_t size_t pos
Definition helpers.h:854
Struct used to store the restored state of a cover.
Definition cover.h:68
void apply(Cover *cover)
Apply these settings to the cover.
Definition cover.cpp:199
CoverCall to_call(Cover *cover)
Convert this struct to a cover call that can be performed.
Definition cover.cpp:191