ESPHome 2026.3.3
Loading...
Searching...
No Matches
time_based_cover.cpp
Go to the documentation of this file.
1#include "time_based_cover.h"
2#include "esphome/core/log.h"
3#include "esphome/core/hal.h"
5
6namespace esphome {
7namespace time_based {
8
9static const char *const TAG = "time_based.cover";
10
11using namespace esphome::cover;
12
14 LOG_COVER("", "Time Based Cover", this);
15 ESP_LOGCONFIG(TAG,
16 " Open Duration: %.1fs\n"
17 " Close Duration: %.1fs",
18 this->open_duration_ / 1e3f, this->close_duration_ / 1e3f);
19}
21 auto restore = this->restore_state_();
22 if (restore.has_value()) {
23 restore->apply(this);
24 } else {
25 this->position = 0.5f;
26 }
27}
30 return;
31
33
34 // Recompute position every loop cycle
35 this->recompute_position_();
36
37 if (this->is_at_target_()) {
38 if (this->has_built_in_endstop_ &&
39 (this->target_position_ == COVER_OPEN || this->target_position_ == COVER_CLOSED)) {
40 // Don't trigger stop, let the cover stop by itself.
42 } else {
44 }
45 this->publish_state();
46 }
47
48 // Send current position every second
49 if (now - this->last_publish_time_ > 1000) {
50 this->publish_state(false);
51 this->last_publish_time_ = now;
52 }
53}
54
56 auto traits = CoverTraits();
57 traits.set_supports_stop(true);
58 traits.set_supports_position(true);
59 traits.set_supports_toggle(true);
60 traits.set_is_assumed_state(this->assumed_state_);
61 return traits;
62}
64 if (call.get_stop()) {
66 this->publish_state();
67 }
68 if (call.get_toggle().has_value()) {
71 this->publish_state();
72 } else {
73 if (this->position == COVER_CLOSED || this->last_operation_ == COVER_OPERATION_CLOSING) {
74 this->target_position_ = COVER_OPEN;
76 } else {
77 this->target_position_ = COVER_CLOSED;
79 }
80 }
81 }
82 auto pos_val = call.get_position();
83 if (pos_val.has_value()) {
84 auto pos = *pos_val;
85 if (pos == this->position) {
86 // already at target
87 if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
88 // for covers with manual control switch, we can't rely on the computed position, so if
89 // the command triggered again, we'll assume it's in the opposite direction anyway.
90 auto op = pos == COVER_CLOSED ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
91 this->position = pos == COVER_CLOSED ? COVER_OPEN : COVER_CLOSED;
92 this->target_position_ = pos;
93 this->start_direction_(op);
94 }
95 // for covers with built in end stop, we should send the command again
96 if (this->has_built_in_endstop_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
97 auto op = pos == COVER_CLOSED ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
98 this->target_position_ = pos;
99 this->start_direction_(op);
100 }
101 } else {
103 if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
104 this->position = pos == COVER_CLOSED ? COVER_OPEN : COVER_CLOSED;
105 }
106 this->target_position_ = pos;
107 this->start_direction_(op);
108 }
109 }
110}
112 if (this->prev_command_trigger_ != nullptr) {
114 this->prev_command_trigger_ = nullptr;
115 }
116}
118 switch (this->current_operation) {
120 return this->position >= this->target_position_;
122 return this->position <= this->target_position_;
124 default:
125 return true;
126 }
127}
129 if (dir == this->current_operation && dir != COVER_OPERATION_IDLE)
130 return;
131
132 this->recompute_position_();
133 Trigger<> *trig;
134 switch (dir) {
136 trig = &this->stop_trigger_;
137 break;
139 this->last_operation_ = dir;
140 trig = &this->open_trigger_;
141 break;
143 this->last_operation_ = dir;
144 trig = &this->close_trigger_;
145 break;
146 default:
147 return;
148 }
149
150 this->current_operation = dir;
151
152 const uint32_t now = millis();
153 this->start_dir_time_ = now;
154 this->last_recompute_time_ = now;
155
156 this->stop_prev_trigger_();
157 trig->trigger();
158 this->prev_command_trigger_ = trig;
159}
162 return;
163
164 float dir;
165 float action_dur;
166 switch (this->current_operation) {
168 dir = 1.0f;
169 action_dur = this->open_duration_;
170 break;
172 dir = -1.0f;
173 action_dur = this->close_duration_;
174 break;
175 default:
176 return;
177 }
178
179 const uint32_t now = millis();
180 this->position += dir * (now - this->last_recompute_time_) / action_dur;
181 this->position = clamp(this->position, 0.0f, 1.0f);
182
183 this->last_recompute_time_ = now;
184}
185
186} // namespace time_based
187} // namespace esphome
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void trigger(const Ts &...x)
Inform the parent automation that the event has triggered.
Definition automation.h:325
void stop_action()
Stop any action connected to this trigger.
Definition automation.h:333
const optional< bool > & get_toggle() const
Definition cover.cpp:94
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
float position
The position of the cover from 0.0 (fully closed) to 1.0 (fully open).
Definition cover.h:121
cover::CoverTraits get_traits() override
void start_direction_(cover::CoverOperation dir)
void control(const cover::CoverCall &call) override
CoverOperation
Enum encoding the current operation of a cover.
Definition cover.h:79
@ COVER_OPERATION_OPENING
The cover is currently opening.
Definition cover.h:83
@ COVER_OPERATION_CLOSING
The cover is currently closing.
Definition cover.h:85
@ COVER_OPERATION_IDLE
The cover is currently idle (not moving)
Definition cover.h:81
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
size_t size_t pos
Definition helpers.h:929
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:26
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t