ESPHome  2024.10.0
lvgl_esphome.h
Go to the documentation of this file.
1 #pragma once
2 #include "esphome/core/defines.h"
3 
4 #ifdef USE_BINARY_SENSOR
6 #endif // USE_BINARY_SENSOR
7 #ifdef USE_LVGL_ROTARY_ENCODER
9 #endif // USE_LVGL_ROTARY_ENCODER
10 
11 // required for clang-tidy
12 #ifndef LV_CONF_H
13 #define LV_CONF_SKIP 1 // NOLINT
14 #endif // LV_CONF_H
15 
18 #include "esphome/core/component.h"
19 #include "esphome/core/log.h"
20 #include <lvgl.h>
21 #include <vector>
22 #include <map>
23 #ifdef USE_LVGL_IMAGE
25 #endif // USE_LVGL_IMAGE
26 
27 #ifdef USE_LVGL_FONT
29 #endif // USE_LVGL_FONT
30 #ifdef USE_LVGL_TOUCHSCREEN
32 #endif // USE_LVGL_TOUCHSCREEN
33 
34 #if defined(USE_LVGL_BUTTONMATRIX) || defined(USE_LVGL_KEYBOARD)
36 #endif // USE_LVGL_BUTTONMATRIX
37 
38 namespace esphome {
39 namespace lvgl {
40 
41 extern lv_event_code_t lv_api_event; // NOLINT
42 extern lv_event_code_t lv_update_event; // NOLINT
43 extern std::string lv_event_code_name_for(uint8_t event_code);
44 extern bool lv_is_pre_initialise();
45 #if LV_COLOR_DEPTH == 16
47 #elif LV_COLOR_DEPTH == 32
49 #else // LV_COLOR_DEPTH
51 #endif // LV_COLOR_DEPTH
52 
53 // Parent class for things that wrap an LVGL object
54 class LvCompound {
55  public:
56  virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; }
57  lv_obj_t *obj{};
58 };
59 
60 class LvPageType {
61  public:
62  LvPageType(bool skip) : skip(skip) {}
63 
64  void setup(size_t index) {
65  this->index = index;
66  this->obj = lv_obj_create(nullptr);
67  }
68  lv_obj_t *obj{};
69  size_t index{};
70  bool skip;
71 };
72 
73 using LvLambdaType = std::function<void(lv_obj_t *)>;
74 using set_value_lambda_t = std::function<void(float)>;
75 using event_callback_t = void(_lv_event_t *);
76 using text_lambda_t = std::function<const char *()>;
77 
78 template<typename... Ts> class ObjUpdateAction : public Action<Ts...> {
79  public:
80  explicit ObjUpdateAction(std::function<void(Ts...)> &&lamb) : lamb_(std::move(lamb)) {}
81 
82  void play(Ts... x) override { this->lamb_(x...); }
83 
84  protected:
85  std::function<void(Ts...)> lamb_;
86 };
87 #ifdef USE_LVGL_FONT
88 class FontEngine {
89  public:
90  FontEngine(font::Font *esp_font);
91  const lv_font_t *get_lv_font();
92 
93  const font::GlyphData *get_glyph_data(uint32_t unicode_letter);
94  uint16_t baseline{};
95  uint16_t height{};
96  uint8_t bpp{};
97 
98  protected:
99  font::Font *font_{};
100  uint32_t last_letter_{};
101  const font::GlyphData *last_data_{};
102  lv_font_t lv_font_{};
103 };
104 #endif // USE_LVGL_FONT
105 #ifdef USE_LVGL_ANIMIMG
106 void lv_animimg_stop(lv_obj_t *obj);
107 #endif // USE_LVGL_ANIMIMG
108 
110  constexpr static const char *const TAG = "lvgl";
111 
112  public:
113  static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
114 
115  float get_setup_priority() const override { return setup_priority::PROCESSOR; }
116  void setup() override;
117  void update() override;
118  void loop() override;
119  void add_on_idle_callback(std::function<void(uint32_t)> &&callback) {
120  this->idle_callbacks_.add(std::move(callback));
121  }
122  void add_display(display::Display *display) { this->displays_.push_back(display); }
123  void add_init_lambda(const std::function<void(LvglComponent *)> &lamb) { this->init_lambdas_.push_back(lamb); }
124  void dump_config() override;
125  void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; }
126  bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; }
127  void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; }
128  lv_disp_t *get_disp() { return this->disp_; }
129  void set_paused(bool paused, bool show_snow);
130  void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event);
131  void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2);
132  void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2,
133  lv_event_code_t event3);
134  bool is_paused() const { return this->paused_; }
135  void add_page(LvPageType *page);
136  void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time);
137  void show_next_page(lv_scr_load_anim_t anim, uint32_t time);
138  void show_prev_page(lv_scr_load_anim_t anim, uint32_t time);
139  void set_page_wrap(bool wrap) { this->page_wrap_ = wrap; }
140  void set_focus_mark(lv_group_t *group) { this->focus_marks_[group] = lv_group_get_focused(group); }
141  void restore_focus_mark(lv_group_t *group) {
142  auto *mark = this->focus_marks_[group];
143  if (mark != nullptr) {
144  lv_group_focus_obj(mark);
145  }
146  }
147 
148  protected:
149  void write_random_();
150  void draw_buffer_(const lv_area_t *area, const uint8_t *ptr);
151  void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
152  std::vector<display::Display *> displays_{};
153  lv_disp_draw_buf_t draw_buf_{};
154  lv_disp_drv_t disp_drv_{};
155  lv_disp_t *disp_{};
156  bool paused_{};
157  std::vector<LvPageType *> pages_{};
158  size_t current_page_{0};
159  bool show_snow_{};
160  lv_coord_t snow_line_{};
161  bool page_wrap_{true};
162  std::map<lv_group_t *, lv_obj_t *> focus_marks_{};
163 
164  std::vector<std::function<void(LvglComponent *lv_component)>> init_lambdas_;
166  size_t buffer_frac_{1};
167  bool full_refresh_{};
168 };
169 
170 class IdleTrigger : public Trigger<> {
171  public:
172  explicit IdleTrigger(LvglComponent *parent, TemplatableValue<uint32_t> timeout);
173 
174  protected:
176  bool is_idle_{};
177 };
178 
179 template<typename... Ts> class LvglAction : public Action<Ts...>, public Parented<LvglComponent> {
180  public:
181  explicit LvglAction(std::function<void(LvglComponent *)> &&lamb) : action_(std::move(lamb)) {}
182  void play(Ts... x) override { this->action_(this->parent_); }
183 
184  protected:
185  std::function<void(LvglComponent *)> action_{};
186 };
187 
188 template<typename... Ts> class LvglCondition : public Condition<Ts...>, public Parented<LvglComponent> {
189  public:
190  LvglCondition(std::function<bool(LvglComponent *)> &&condition_lambda)
191  : condition_lambda_(std::move(condition_lambda)) {}
192  bool check(Ts... x) override { return this->condition_lambda_(this->parent_); }
193 
194  protected:
195  std::function<bool(LvglComponent *)> condition_lambda_{};
196 };
197 
198 #ifdef USE_LVGL_TOUCHSCREEN
199 class LVTouchListener : public touchscreen::TouchListener, public Parented<LvglComponent> {
200  public:
201  LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time);
202  void update(const touchscreen::TouchPoints_t &tpoints) override;
203  void release() override { touch_pressed_ = false; }
204  lv_indev_drv_t *get_drv() { return &this->drv_; }
205 
206  protected:
207  lv_indev_drv_t drv_{};
208  touchscreen::TouchPoint touch_point_{};
209  bool touch_pressed_{};
210 };
211 #endif // USE_LVGL_TOUCHSCREEN
212 
213 #ifdef USE_LVGL_KEY_LISTENER
214 class LVEncoderListener : public Parented<LvglComponent> {
215  public:
216  LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt);
217 
219  left_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_LEFT, state); });
220  }
222  right_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_RIGHT, state); });
223  }
224 
226  enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); });
227  }
228 
229 #ifdef USE_LVGL_ROTARY_ENCODER
231  sensor->register_listener([this](int32_t count) { this->set_count(count); });
232  }
233 #endif // USE_LVGL_ROTARY_ENCODER
234 
235  void event(int key, bool pressed) {
236  if (!this->parent_->is_paused()) {
237  this->pressed_ = pressed;
238  this->key_ = key;
239  }
240  }
241 
242  void set_count(int32_t count) {
243  if (!this->parent_->is_paused())
244  this->count_ = count;
245  }
246 
247  lv_indev_drv_t *get_drv() { return &this->drv_; }
248 
249  protected:
250  lv_indev_drv_t drv_{};
251  bool pressed_{};
252  int32_t count_{};
253  int32_t last_count_{};
254  int key_{};
255 };
256 #endif // USE_LVGL_KEY_LISTENER
257 
258 #ifdef USE_LVGL_BUTTONMATRIX
260  public:
261  void set_obj(lv_obj_t *lv_obj) override;
262  uint16_t get_selected() { return lv_btnmatrix_get_selected_btn(this->obj); }
263  void set_key(size_t idx, uint8_t key) { this->key_map_[idx] = key; }
264 
265  protected:
266  std::map<size_t, uint8_t> key_map_{};
267 };
268 #endif // USE_LVGL_BUTTONMATRIX
269 
270 #ifdef USE_LVGL_KEYBOARD
272  public:
273  void set_obj(lv_obj_t *lv_obj) override;
274 };
275 #endif // USE_LVGL_KEYBOARD
276 } // namespace lvgl
277 } // namespace esphome
void setup()
std::string lv_event_code_name_for(uint8_t event_code)
void add_on_idle_callback(std::function< void(uint32_t)> &&callback)
Definition: lvgl_esphome.h:119
void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor)
Definition: lvgl_esphome.h:230
void loop()
LvglCondition(std::function< bool(LvglComponent *)> &&condition_lambda)
Definition: lvgl_esphome.h:190
bool check(Ts... x) override
Definition: lvgl_esphome.h:192
std::vector< TouchPoint > TouchPoints_t
Definition: touchscreen.h:30
bool is_idle(uint32_t idle_ms)
Definition: lvgl_esphome.h:126
void register_listener(std::function< void(uint32_t)> listener)
interface for components that provide keypresses
Definition: key_provider.h:10
MediaPlayerStateTrigger< MediaPlayerState::MEDIA_PLAYER_STATE_IDLE > IdleTrigger
Definition: automation.h:56
float get_setup_priority() const override
Definition: lvgl_esphome.h:115
void set_full_refresh(bool full_refresh)
Definition: lvgl_esphome.h:125
lv_indev_drv_t * get_drv()
Definition: lvgl_esphome.h:204
uint16_t x
Definition: tt21100.cpp:17
void play(Ts... x) override
Definition: lvgl_esphome.h:182
STL namespace.
This class simplifies creating components that periodically check a state.
Definition: component.h:283
void add_display(display::Display *display)
Definition: lvgl_esphome.h:122
std::vector< std::function< void(LvglComponent *lv_component)> > init_lambdas_
Definition: lvgl_esphome.h:164
void(_lv_event_t *) event_callback_t
Definition: lvgl_esphome.h:75
void set_left_button(binary_sensor::BinarySensor *left_button)
Definition: lvgl_esphome.h:218
lv_event_code_t lv_update_event
std::function< void(float)> set_value_lambda_t
Definition: lvgl_esphome.h:74
lv_event_code_t lv_api_event
void restore_focus_mark(lv_group_t *group)
Definition: lvgl_esphome.h:141
void set_right_button(binary_sensor::BinarySensor *right_button)
Definition: lvgl_esphome.h:221
void set_enter_button(binary_sensor::BinarySensor *enter_button)
Definition: lvgl_esphome.h:225
void setup(size_t index)
Definition: lvgl_esphome.h:64
virtual void set_obj(lv_obj_t *lv_obj)
Definition: lvgl_esphome.h:56
Base class for all automation conditions.
Definition: automation.h:74
void set_page_wrap(bool wrap)
Definition: lvgl_esphome.h:139
std::function< void(Ts...)> lamb_
Definition: lvgl_esphome.h:85
LvglAction(std::function< void(LvglComponent *)> &&lamb)
Definition: lvgl_esphome.h:181
uint8_t type
bool lv_is_pre_initialise()
const float PROCESSOR
For components that use data from sensors like displays.
Definition: component.cpp:20
TemplatableValue< uint32_t > timeout_
Definition: lvgl_esphome.h:175
std::function< void(lv_obj_t *)> LvLambdaType
Definition: lvgl_esphome.h:73
void set_key(size_t idx, uint8_t key)
Definition: lvgl_esphome.h:263
void event(int key, bool pressed)
Definition: lvgl_esphome.h:235
void add_init_lambda(const std::function< void(LvglComponent *)> &lamb)
Definition: lvgl_esphome.h:123
std::function< const char *()> text_lambda_t
Definition: lvgl_esphome.h:76
void add_on_state_callback(std::function< void(bool)> &&callback)
Add a callback to be notified of state changes.
void set_focus_mark(lv_group_t *group)
Definition: lvgl_esphome.h:140
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
Base class for all binary_sensor-type classes.
Definition: binary_sensor.h:37
void set_count(int32_t count)
Definition: lvgl_esphome.h:242
void set_buffer_frac(size_t frac)
Definition: lvgl_esphome.h:127
void lv_animimg_stop(lv_obj_t *obj)
ObjUpdateAction(std::function< void(Ts...)> &&lamb)
Definition: lvgl_esphome.h:80
esphome::sensor::Sensor * sensor
Definition: statsd.h:37
Helper class to easily give an object a parent of type T.
Definition: helpers.h:521
void play(Ts... x) override
Definition: lvgl_esphome.h:82
bool state
Definition: fan.h:34