ESPHome 2026.9.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 // moving_length_ is the fraction of progress spent moving in each direction, in (0, 0.5].
25 // Callers must pass pause in [0, 1) -- pause == 1.0 would make moving_length_ zero and divide by zero below.
26 LvAnimationTimingRoundTrip(float pause) : moving_length_((1.0f - pause) / 2.0f) {}
27 float map_progress(float value) override {
28 if (value < this->moving_length_) {
29 return value / this->moving_length_;
30 }
31 if (value > 1.0f - this->moving_length_) {
32 return (1.0f - value) / this->moving_length_;
33 }
34 // pause in the middle
35 return 1.0f;
36 }
37
38 protected:
40};
41
43 public:
44 LvAnimationTimingGravity(float acceleration, float bounce) : acceleration_(acceleration), bounce_(bounce) {}
45 float map_progress(float value) override {
46 if (value == 0.0f) {
47 this->initial_position_ = 0.0f;
48 this->initial_speed_ = 0.0f;
49 this->initial_time_ = 0.0f;
50 }
51 auto position = this->calc_pos_(value);
52 if (position > 1.0f) {
53 auto initial_time = this->calc_end_time_();
54 this->initial_speed_ = -this->calc_speed_(initial_time) * this->bounce_;
55 this->initial_position_ = 1.0f;
56 this->initial_time_ = initial_time;
57 position = calc_pos_(value);
58 if (position > 1.0f) {
59 position = 1.0f;
60 }
61 }
62 return position;
63 }
64
65 protected:
66 float calc_pos_(float value) const {
67 value -= this->initial_time_;
68 return (0.5 * value * this->acceleration_ + this->initial_speed_) * value + this->initial_position_;
69 }
70
71 float calc_speed_(float value) const {
72 value -= this->initial_time_;
73 return this->acceleration_ * value + this->initial_speed_;
74 }
75
76 float calc_end_time_() const {
77 return (-this->initial_speed_ + std::sqrt(this->initial_speed_ * this->initial_speed_ -
78 4.0f * this->acceleration_ / 2.0 * (this->initial_position_ - 1.0f))) /
79 this->acceleration_ +
80 this->initial_time_;
81 }
82
84 float bounce_;
85 float initial_position_{0.0f};
86 float initial_time_{0.0f};
87 float initial_speed_{0.0f};
88};
89
91 public:
92 LvAnimationTimingEaseInOut(float slope) : slope_(slope) {}
93 float map_progress(float value) override {
94 float sqr = value * value;
95 sqr = sqr / (2.0f * (sqr - value) + 1.0f);
96 return this->slope_ * sqr + (1.0 - this->slope_) * value;
97 }
98
99 protected:
100 float slope_;
101};
102
103template<size_t DATA_SIZE, bool AUTO_START = false> class LvAnimation : public Component {
104 public:
105 LvAnimation(void (*update_callback)(const lv_coord_t *data), std::vector<TemplatableValue<lv_coord_t>> from,
106 std::vector<TemplatableValue<lv_coord_t>> to)
107 : update_callback_(update_callback) {
108 std::copy(from.begin(), from.end(), this->from_);
109 std::copy(to.begin(), to.end(), this->to_);
110 }
111
112 void start() {
114 this->stop();
115 if (this->duration_ == 0)
116 return;
117 // evaluate any lambdas
118 for (size_t i = 0; i != DATA_SIZE; i++) {
119 this->data_from_[i] = this->from_[i].value();
120 this->data_to_[i] = this->to_[i].value();
121 }
122 this->start_time_ = millis();
124 this->loop();
125 this->start_callback_.call();
126 }
127
128 void stop() {
129 // Only fire the stop callback on a genuine running -> stopped transition, so that
130 // repeated stop() calls (e.g. start() pre-clearing a stopped animation) don't re-fire it.
131 if (this->state_ == AnimationState::STOPPED)
132 return;
134 this->stop_callback_.call();
135 }
136
137 void setup() override {
138 if constexpr (AUTO_START)
139 this->start();
140 }
141
142 void loop() override {
143 if (this->state_ == AnimationState::STOPPED)
144 return;
145 uint32_t elapsed = millis() - this->start_time_;
146 float progress = static_cast<float>(elapsed) / static_cast<float>(this->duration_);
147 switch (this->state_) {
149 if (elapsed < this->start_delay_)
150 return;
152 this->start_time_ = millis();
153 progress = 0.0f;
154 break;
156 if (progress >= 1.0f) {
157 progress = 1.0f;
158 this->stop();
159 if (this->loop_)
160 this->start();
161 }
162 break;
163 default:
164 return;
165 }
166
167 for (auto *timing : this->timings_) {
168 progress = timing->map_progress(progress);
169 }
170 lv_coord_t data[DATA_SIZE];
171 for (size_t i = 0; i != DATA_SIZE; i++) {
172 data[i] = static_cast<lv_coord_t>(
173 roundf(this->data_from_[i] + static_cast<lv_coord_t>(this->data_to_[i] - this->data_from_[i]) * progress));
174 }
175 this->update_callback_(data);
176 }
177
178 float get_setup_priority() const override { return setup_priority::PROCESSOR - 20.0; }
180 void set_start_delay(uint32_t start_delay) { this->start_delay_ = start_delay; }
181 void add_timing(LvAnimationTiming *timing) { this->timings_.push_back(timing); }
182 void set_loop(bool loop) { this->loop_ = loop; }
183
184 template<typename F> void add_on_start_callback(F &&callback) {
185 this->start_callback_.add(std::forward<F>(callback));
186 }
187 template<typename F> void add_on_stop_callback(F &&callback) { this->stop_callback_.add(std::forward<F>(callback)); }
188
189 protected:
190 void (*const update_callback_)(const lv_coord_t *data);
198 lv_coord_t data_from_[DATA_SIZE]{0};
199 lv_coord_t data_to_[DATA_SIZE]{0};
201 std::vector<LvAnimationTiming *> timings_{};
202 bool loop_{false};
203};
204
205} // namespace esphome::lvgl
206
207#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:181
lv_coord_t data_to_[DATA_SIZE]
Definition animation.h:199
void(*const update_callback_)(const lv_coord_t *data)
Definition animation.h:190
void set_loop(bool loop)
Definition animation.h:182
LazyCallbackManager< void()> start_callback_
Definition animation.h:191
LazyCallbackManager< void()> stop_callback_
Definition animation.h:192
std::vector< LvAnimationTiming * > timings_
Definition animation.h:201
void set_duration(uint32_t duration)
Definition animation.h:179
void setup() override
Definition animation.h:137
TemplatableValue< lv_coord_t > to_[DATA_SIZE]
Definition animation.h:194
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:105
lv_coord_t data_from_[DATA_SIZE]
Definition animation.h:198
void set_start_delay(uint32_t start_delay)
Definition animation.h:180
float get_setup_priority() const override
Definition animation.h:178
void add_on_start_callback(F &&callback)
Definition animation.h:184
void add_on_stop_callback(F &&callback)
Definition animation.h:187
TemplatableValue< lv_coord_t > from_[DATA_SIZE]
Definition animation.h:193
float map_progress(float value) override
Definition animation.h:93
LvAnimationTimingGravity(float acceleration, float bounce)
Definition animation.h:44
float map_progress(float value) override
Definition animation.h:45
float calc_pos_(float value) const
Definition animation.h:66
float calc_speed_(float value) const
Definition animation.h:71
virtual float map_progress(float value)=0
float map_progress(float value) override
Definition animation.h:27
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