ESPHome 2025.6.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
32 const uint32_t now = App.get_loop_component_start_time();
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_ &&
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}
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 {
76 } else {
79 }
80 }
81 }
82 if (call.get_position().has_value()) {
83 auto pos = *call.get_position();
84 if (pos == this->position) {
85 // already at target
86 if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
87 // for covers with manual control switch, we can't rely on the computed position, so if
88 // the command triggered again, we'll assume it's in the opposite direction anyway.
91 this->target_position_ = pos;
92 this->start_direction_(op);
93 }
94 // for covers with built in end stop, we should send the command again
95 if (this->has_built_in_endstop_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
97 this->target_position_ = pos;
98 this->start_direction_(op);
99 }
100 } else {
102 if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
103 this->position = pos == COVER_CLOSED ? COVER_OPEN : COVER_CLOSED;
104 }
105 this->target_position_ = pos;
106 this->start_direction_(op);
107 }
108 }
109}
111 if (this->prev_command_trigger_ != nullptr) {
113 this->prev_command_trigger_ = nullptr;
114 }
115}
117 switch (this->current_operation) {
119 return this->position >= this->target_position_;
121 return this->position <= this->target_position_;
123 default:
124 return true;
125 }
126}
128 if (dir == this->current_operation && dir != COVER_OPERATION_IDLE)
129 return;
130
131 this->recompute_position_();
132 Trigger<> *trig;
133 switch (dir) {
135 trig = this->stop_trigger_;
136 break;
138 this->last_operation_ = dir;
139 trig = this->open_trigger_;
140 break;
142 this->last_operation_ = dir;
143 trig = this->close_trigger_;
144 break;
145 default:
146 return;
147 }
148
149 this->current_operation = dir;
150
151 const uint32_t now = millis();
152 this->start_dir_time_ = now;
153 this->last_recompute_time_ = now;
154
155 this->stop_prev_trigger_();
156 trig->trigger();
157 this->prev_command_trigger_ = trig;
158}
161 return;
162
163 float dir;
164 float action_dur;
165 switch (this->current_operation) {
167 dir = 1.0f;
168 action_dur = this->open_duration_;
169 break;
171 dir = -1.0f;
172 action_dur = this->close_duration_;
173 break;
174 default:
175 return;
176 }
177
178 const uint32_t now = millis();
179 this->position += dir * (now - this->last_recompute_time_) / action_dur;
180 this->position = clamp(this->position, 0.0f, 1.0f);
181
182 this->last_recompute_time_ = now;
183}
184
185} // namespace time_based
186} // 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 stop_action()
Stop any action connected to this trigger.
Definition automation.h:104
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:96
const optional< bool > & get_toggle() const
Definition cover.cpp:99
const optional< float > & get_position() const
Definition cover.cpp:97
CoverOperation current_operation
The current operation of the cover (idle, opening, closing).
Definition cover.h:116
optional< CoverRestoreState > restore_state_()
Definition cover.cpp:200
void publish_state(bool save=true)
Publish the current state of the cover.
Definition cover.cpp:166
float position
The position of the cover from 0.0 (fully closed) to 1.0 (fully open).
Definition cover.h:122
bool has_value() const
Definition optional.h:87
cover::CoverTraits get_traits() override
float get_setup_priority() const override
void start_direction_(cover::CoverOperation dir)
void control(const cover::CoverCall &call) override
const float COVER_CLOSED
Definition cover.cpp:10
const float COVER_OPEN
Definition cover.cpp:9
CoverOperation
Enum encoding the current operation of a cover.
Definition cover.h:80
@ COVER_OPERATION_OPENING
The cover is currently opening.
Definition cover.h:84
@ COVER_OPERATION_CLOSING
The cover is currently closing.
Definition cover.h:86
@ COVER_OPERATION_IDLE
The cover is currently idle (not moving)
Definition cover.h:82
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:20
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28
Application App
Global storage of Application pointer - only one Application can exist.
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition helpers.h:102