ESPHome  2024.9.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_IMAGE
106 lv_img_dsc_t *lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc = nullptr);
107 #endif // USE_LVGL_IMAGE
108 
109 #ifdef USE_LVGL_ANIMIMG
110 void lv_animimg_stop(lv_obj_t *obj);
111 #endif // USE_LVGL_ANIMIMG
112 
114  constexpr static const char *const TAG = "lvgl";
115 
116  public:
117  static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
118 
119  float get_setup_priority() const override { return setup_priority::PROCESSOR; }
120  void setup() override;
121  void update() override;
122  void loop() override;
123  void add_on_idle_callback(std::function<void(uint32_t)> &&callback) {
124  this->idle_callbacks_.add(std::move(callback));
125  }
126  void add_display(display::Display *display) { this->displays_.push_back(display); }
127  void add_init_lambda(const std::function<void(LvglComponent *)> &lamb) { this->init_lambdas_.push_back(lamb); }
128  void dump_config() override;
129  void set_full_refresh(bool full_refresh) { this->full_refresh_ = full_refresh; }
130  bool is_idle(uint32_t idle_ms) { return lv_disp_get_inactive_time(this->disp_) > idle_ms; }
131  void set_buffer_frac(size_t frac) { this->buffer_frac_ = frac; }
132  lv_disp_t *get_disp() { return this->disp_; }
133  void set_paused(bool paused, bool show_snow);
134  void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event);
135  void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2);
136  void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event1, lv_event_code_t event2,
137  lv_event_code_t event3);
138  bool is_paused() const { return this->paused_; }
139  void add_page(LvPageType *page);
140  void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time);
141  void show_next_page(lv_scr_load_anim_t anim, uint32_t time);
142  void show_prev_page(lv_scr_load_anim_t anim, uint32_t time);
143  void set_page_wrap(bool wrap) { this->page_wrap_ = wrap; }
144  void set_focus_mark(lv_group_t *group) { this->focus_marks_[group] = lv_group_get_focused(group); }
145  void restore_focus_mark(lv_group_t *group) {
146  auto *mark = this->focus_marks_[group];
147  if (mark != nullptr) {
148  lv_group_focus_obj(mark);
149  }
150  }
151 
152  protected:
153  void write_random_();
154  void draw_buffer_(const lv_area_t *area, const uint8_t *ptr);
155  void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
156  std::vector<display::Display *> displays_{};
157  lv_disp_draw_buf_t draw_buf_{};
158  lv_disp_drv_t disp_drv_{};
159  lv_disp_t *disp_{};
160  bool paused_{};
161  std::vector<LvPageType *> pages_{};
162  size_t current_page_{0};
163  bool show_snow_{};
164  lv_coord_t snow_line_{};
165  bool page_wrap_{true};
166  std::map<lv_group_t *, lv_obj_t *> focus_marks_{};
167 
168  std::vector<std::function<void(LvglComponent *lv_component)>> init_lambdas_;
170  size_t buffer_frac_{1};
171  bool full_refresh_{};
172 };
173 
174 class IdleTrigger : public Trigger<> {
175  public:
176  explicit IdleTrigger(LvglComponent *parent, TemplatableValue<uint32_t> timeout);
177 
178  protected:
180  bool is_idle_{};
181 };
182 
183 template<typename... Ts> class LvglAction : public Action<Ts...>, public Parented<LvglComponent> {
184  public:
185  explicit LvglAction(std::function<void(LvglComponent *)> &&lamb) : action_(std::move(lamb)) {}
186  void play(Ts... x) override { this->action_(this->parent_); }
187 
188  protected:
189  std::function<void(LvglComponent *)> action_{};
190 };
191 
192 template<typename... Ts> class LvglCondition : public Condition<Ts...>, public Parented<LvglComponent> {
193  public:
194  LvglCondition(std::function<bool(LvglComponent *)> &&condition_lambda)
195  : condition_lambda_(std::move(condition_lambda)) {}
196  bool check(Ts... x) override { return this->condition_lambda_(this->parent_); }
197 
198  protected:
199  std::function<bool(LvglComponent *)> condition_lambda_{};
200 };
201 
202 #ifdef USE_LVGL_TOUCHSCREEN
203 class LVTouchListener : public touchscreen::TouchListener, public Parented<LvglComponent> {
204  public:
205  LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time);
206  void update(const touchscreen::TouchPoints_t &tpoints) override;
207  void release() override { touch_pressed_ = false; }
208  lv_indev_drv_t *get_drv() { return &this->drv_; }
209 
210  protected:
211  lv_indev_drv_t drv_{};
212  touchscreen::TouchPoint touch_point_{};
213  bool touch_pressed_{};
214 };
215 #endif // USE_LVGL_TOUCHSCREEN
216 
217 #ifdef USE_LVGL_KEY_LISTENER
218 class LVEncoderListener : public Parented<LvglComponent> {
219  public:
220  LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt);
221 
223  left_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_LEFT, state); });
224  }
226  right_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_RIGHT, state); });
227  }
228 
230  enter_button->add_on_state_callback([this](bool state) { this->event(LV_KEY_ENTER, state); });
231  }
232 
233 #ifdef USE_LVGL_ROTARY_ENCODER
235  sensor->register_listener([this](int32_t count) { this->set_count(count); });
236  }
237 #endif // USE_LVGL_ROTARY_ENCODER
238 
239  void event(int key, bool pressed) {
240  if (!this->parent_->is_paused()) {
241  this->pressed_ = pressed;
242  this->key_ = key;
243  }
244  }
245 
246  void set_count(int32_t count) {
247  if (!this->parent_->is_paused())
248  this->count_ = count;
249  }
250 
251  lv_indev_drv_t *get_drv() { return &this->drv_; }
252 
253  protected:
254  lv_indev_drv_t drv_{};
255  bool pressed_{};
256  int32_t count_{};
257  int32_t last_count_{};
258  int key_{};
259 };
260 #endif // USE_LVGL_KEY_LISTENER
261 
262 #ifdef USE_LVGL_BUTTONMATRIX
264  public:
265  void set_obj(lv_obj_t *lv_obj) override;
266  uint16_t get_selected() { return lv_btnmatrix_get_selected_btn(this->obj); }
267  void set_key(size_t idx, uint8_t key) { this->key_map_[idx] = key; }
268 
269  protected:
270  std::map<size_t, uint8_t> key_map_{};
271 };
272 #endif // USE_LVGL_BUTTONMATRIX
273 
274 #ifdef USE_LVGL_KEYBOARD
276  public:
277  void set_obj(lv_obj_t *lv_obj) override;
278 };
279 #endif // USE_LVGL_KEYBOARD
280 } // namespace lvgl
281 } // 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:123
void set_sensor(rotary_encoder::RotaryEncoderSensor *sensor)
Definition: lvgl_esphome.h:234
void loop()
LvglCondition(std::function< bool(LvglComponent *)> &&condition_lambda)
Definition: lvgl_esphome.h:194
bool check(Ts... x) override
Definition: lvgl_esphome.h:196
std::vector< TouchPoint > TouchPoints_t
Definition: touchscreen.h:30
bool is_idle(uint32_t idle_ms)
Definition: lvgl_esphome.h:130
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:119
void set_full_refresh(bool full_refresh)
Definition: lvgl_esphome.h:129
lv_indev_drv_t * get_drv()
Definition: lvgl_esphome.h:208
uint16_t x
Definition: tt21100.cpp:17
void play(Ts... x) override
Definition: lvgl_esphome.h:186
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:126
std::vector< std::function< void(LvglComponent *lv_component)> > init_lambdas_
Definition: lvgl_esphome.h:168
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:222
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:145
void set_right_button(binary_sensor::BinarySensor *right_button)
Definition: lvgl_esphome.h:225
void set_enter_button(binary_sensor::BinarySensor *enter_button)
Definition: lvgl_esphome.h:229
void setup(size_t index)
Definition: lvgl_esphome.h:64
virtual void set_obj(lv_obj_t *lv_obj)
Definition: lvgl_esphome.h:56
lv_img_dsc_t * lv_img_from(image::Image *src, lv_img_dsc_t *img_dsc)
Base class for all automation conditions.
Definition: automation.h:74
void set_page_wrap(bool wrap)
Definition: lvgl_esphome.h:143
std::function< void(Ts...)> lamb_
Definition: lvgl_esphome.h:85
LvglAction(std::function< void(LvglComponent *)> &&lamb)
Definition: lvgl_esphome.h:185
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:179
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:267
void event(int key, bool pressed)
Definition: lvgl_esphome.h:239
void add_init_lambda(const std::function< void(LvglComponent *)> &lamb)
Definition: lvgl_esphome.h:127
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:144
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:246
void set_buffer_frac(size_t frac)
Definition: lvgl_esphome.h:131
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