ESPHome 2026.8.0-dev
Loading...
Searching...
No Matches
animation.h
Go to the documentation of this file.
1#pragma once
3
4#ifdef USE_LVGL_ANIMATION
5#include "lvgl_esphome.h"
6#include "esphome/core/hal.h"
7
8namespace esphome::lvgl {
9
10enum class AnimationState {
11 STOPPED,
12 STARTED,
13 RUNNING,
14};
15
17 public:
18 // Map progress in the range [0, 1]
19 virtual float map_progress(float value) = 0;
20};
21
23 public:
24 float map_progress(float value) override {
25 value *= 2.0f;
26 if (value > 1.0f)
27 return 2.0f - value;
28 return value;
29 }
30};
31
33 public:
34 LvAnimationTimingGravity(float acceleration, float bounce) : acceleration_(acceleration), bounce_(bounce) {}
35 float map_progress(float value) override {
36 if (value == 0.0f) {
37 this->initial_position_ = 0.0f;
38 this->initial_speed_ = 0.0f;
39 this->initial_time_ = 0.0f;
40 }
41 auto position = this->calc_pos_(value);
42 if (position > 1.0f) {
43 auto initial_time = this->calc_end_time_();
44 this->initial_speed_ = -this->calc_speed_(initial_time) * this->bounce_;
45 this->initial_position_ = 1.0f;
46 this->initial_time_ = initial_time;
47 position = calc_pos_(value);
48 if (position > 1.0f) {
49 position = 1.0f;
50 }
51 }
52 return position;
53 }
54
55 protected:
56 float calc_pos_(float value) const {
57 value -= this->initial_time_;
58 return (0.5 * value * this->acceleration_ + this->initial_speed_) * value + this->initial_position_;
59 }
60
61 float calc_speed_(float value) const {
62 value -= this->initial_time_;
63 return this->acceleration_ * value + this->initial_speed_;
64 }
65
66 float calc_end_time_() const {
67 return (-this->initial_speed_ + std::sqrt(this->initial_speed_ * this->initial_speed_ -
68 4.0f * this->acceleration_ / 2.0 * (this->initial_position_ - 1.0f))) /
69 this->acceleration_ +
70 this->initial_time_;
71 }
72
74 float bounce_;
75 float initial_position_{0.0f};
76 float initial_time_{0.0f};
77 float initial_speed_{0.0f};
78};
79
81 public:
82 LvAnimationTimingEaseInOut(float slope) : slope_(slope) {}
83 float map_progress(float value) override {
84 float sqr = value * value;
85 sqr = sqr / (2.0f * (sqr - value) + 1.0f);
86 return this->slope_ * sqr + (1.0 - this->slope_) * value;
87 }
88
89 protected:
90 float slope_;
91};
92
93template<size_t DATA_SIZE, bool AUTO_START = false> class LvAnimation : public Component {
94 public:
95 LvAnimation(void (*update_callback)(const lv_coord_t *data), std::vector<TemplatableValue<lv_coord_t>> from,
96 std::vector<TemplatableValue<lv_coord_t>> to)
97 : update_callback_(update_callback) {
98 std::copy(from.begin(), from.end(), this->from_);
99 std::copy(to.begin(), to.end(), this->to_);
100 }
101
102 void start() {
104 this->stop();
105 if (this->duration_ == 0)
106 return;
107 // evaluate any lambdas
108 for (size_t i = 0; i != DATA_SIZE; i++) {
109 this->data_from_[i] = this->from_[i].value();
110 this->data_to_[i] = this->to_[i].value();
111 }
112 this->start_time_ = millis();
114 this->loop();
115 this->start_callback_.call();
116 }
117
118 void stop() {
119 // Only fire the stop callback on a genuine running -> stopped transition, so that
120 // repeated stop() calls (e.g. start() pre-clearing a stopped animation) don't re-fire it.
121 if (this->state_ == AnimationState::STOPPED)
122 return;
124 this->stop_callback_.call();
125 }
126
127 void setup() override {
128 if constexpr (AUTO_START)
129 this->start();
130 }
131
132 void loop() override {
133 if (this->state_ == AnimationState::STOPPED)
134 return;
135 uint32_t elapsed = millis() - this->start_time_;
136 float progress = static_cast<float>(elapsed) / static_cast<float>(this->duration_);
137 switch (this->state_) {
139 if (elapsed < this->start_delay_)
140 return;
142 this->start_time_ = millis();
143 progress = 0.0f;
144 break;
146 if (progress >= 1.0f) {
147 progress = 1.0f;
148 this->stop();
149 if (this->loop_)
150 this->start();
151 }
152 break;
153 default:
154 return;
155 }
156
157 for (auto *timing : this->timings_) {
158 progress = timing->map_progress(progress);
159 }
160 lv_coord_t data[DATA_SIZE];
161 for (size_t i = 0; i != DATA_SIZE; i++) {
162 data[i] = static_cast<lv_coord_t>(
163 roundf(this->data_from_[i] + static_cast<lv_coord_t>(this->data_to_[i] - this->data_from_[i]) * progress));
164 }
165 this->update_callback_(data);
166 }
167
168 float get_setup_priority() const override { return setup_priority::PROCESSOR - 20.0; }
170 void set_start_delay(uint32_t start_delay) { this->start_delay_ = start_delay; }
171 void add_timing(LvAnimationTiming *timing) { this->timings_.push_back(timing); }
172 void set_loop(bool loop) { this->loop_ = loop; }
173
174 template<typename F> void add_on_start_callback(F &&callback) {
175 this->start_callback_.add(std::forward<F>(callback));
176 }
177 template<typename F> void add_on_stop_callback(F &&callback) { this->stop_callback_.add(std::forward<F>(callback)); }
178
179 protected:
180 void (*const update_callback_)(const lv_coord_t *data);
188 lv_coord_t data_from_[DATA_SIZE]{0};
189 lv_coord_t data_to_[DATA_SIZE]{0};
191 std::vector<LvAnimationTiming *> timings_{};
192 bool loop_{false};
193};
194
195} // namespace esphome::lvgl
196
197#endif // USE_LVGL_ANIMATION
Primary TemplatableValue: stores either a constant value or a function pointer.
Definition automation.h:94
T value(X... x) const
Definition automation.h:175
void add_timing(LvAnimationTiming *timing)
Definition animation.h:171
lv_coord_t data_to_[DATA_SIZE]
Definition animation.h:189
void(*const update_callback_)(const lv_coord_t *data)
Definition animation.h:180
void set_loop(bool loop)
Definition animation.h:172
LazyCallbackManager< void()> start_callback_
Definition animation.h:181
LazyCallbackManager< void()> stop_callback_
Definition animation.h:182
std::vector< LvAnimationTiming * > timings_
Definition animation.h:191
void set_duration(uint32_t duration)
Definition animation.h:169
void setup() override
Definition animation.h:127
TemplatableValue< lv_coord_t > to_[DATA_SIZE]
Definition animation.h:184
LvAnimation(void(*update_callback)(const lv_coord_t *data), std::vector< TemplatableValue< lv_coord_t > > from, std::vector< TemplatableValue< lv_coord_t > > to)
Definition animation.h:95
lv_coord_t data_from_[DATA_SIZE]
Definition animation.h:188
void set_start_delay(uint32_t start_delay)
Definition animation.h:170
float get_setup_priority() const override
Definition animation.h:168
void add_on_start_callback(F &&callback)
Definition animation.h:174
void add_on_stop_callback(F &&callback)
Definition animation.h:177
TemplatableValue< lv_coord_t > from_[DATA_SIZE]
Definition animation.h:183
float map_progress(float value) override
Definition animation.h:83
LvAnimationTimingGravity(float acceleration, float bounce)
Definition animation.h:34
float map_progress(float value) override
Definition animation.h:35
float calc_pos_(float value) const
Definition animation.h:56
float calc_speed_(float value) const
Definition animation.h:61
virtual float map_progress(float value)=0
float map_progress(float value) override
Definition animation.h:24
float position
Definition cover.h:0
uint8_t duration
Definition msa3xx.h:0
constexpr float PROCESSOR
For components that use data from sensors like displays.
Definition component.h:47
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:28
static void uint32_t