10 static const char *
const TAG =
"lvgl";
13 static void log_cb(
const char *buf) {
14 esp_log_printf_(ESPHOME_LOG_LEVEL_INFO, TAG, 0,
"%.*s", (
int) strlen(buf) - 1, buf);
18 static const char *
const EVENT_NAMES[] = {
25 "LONG_PRESSED_REPEAT",
56 "SCREEN_UNLOAD_START",
67 if (event_code <
sizeof(EVENT_NAMES) /
sizeof(EVENT_NAMES[0])) {
68 return EVENT_NAMES[event_code];
72 static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) {
91 if (!paused && lv_scr_act() !=
nullptr) {
92 lv_disp_trig_activity(this->
disp_);
93 lv_obj_invalidate(lv_scr_act());
97 lv_obj_add_event_cb(obj, callback, event,
this);
100 lv_event_code_t event2) {
105 lv_event_code_t event2, lv_event_code_t event3) {
111 this->
pages_.push_back(page);
115 if (index >= this->
pages_.size())
138 display->draw_pixels_at(area->x1, area->y1, lv_area_get_width(area), lv_area_get_height(area), ptr,
147 ESP_LOGV(TAG,
"flush_cb, area=%d/%d, %d/%d took %dms", area->x1, area->y1, lv_area_get_width(area),
148 lv_area_get_height(area), (
int) (
millis() - now));
150 lv_disp_flush_ready(disp_drv);
163 #ifdef USE_LVGL_TOUCHSCREEN 165 lv_indev_drv_init(&this->drv_);
166 this->drv_.long_press_repeat_time = long_press_repeat_time;
167 this->drv_.long_press_time = long_press_time;
168 this->drv_.type = LV_INDEV_TYPE_POINTER;
169 this->drv_.user_data =
this;
170 this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) {
172 if (
l->touch_pressed_) {
173 data->point.x =
l->touch_point_.x;
174 data->point.y =
l->touch_point_.y;
175 data->state = LV_INDEV_STATE_PRESSED;
177 data->state = LV_INDEV_STATE_RELEASED;
182 this->touch_pressed_ = !this->parent_->is_paused() && !tpoints.empty();
183 if (this->touch_pressed_)
184 this->touch_point_ = tpoints[0];
186 #endif // USE_LVGL_TOUCHSCREEN 188 #ifdef USE_LVGL_KEY_LISTENER 190 lv_indev_drv_init(&this->drv_);
191 this->drv_.type =
type;
192 this->drv_.user_data =
this;
193 this->drv_.long_press_time = lpt;
194 this->drv_.long_press_repeat_time = lprt;
195 this->drv_.read_cb = [](lv_indev_drv_t *d, lv_indev_data_t *data) {
197 data->state =
l->pressed_ ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
199 data->enc_diff = (int16_t) (
l->count_ -
l->last_count_);
200 l->last_count_ =
l->count_;
201 data->continue_reading =
false;
204 #endif // USE_LVGL_KEY_LISTENER 206 #ifdef USE_LVGL_BUTTONMATRIX 211 [](lv_event_t *event) {
213 if (self->key_callback_.size() == 0)
215 auto key_idx = lv_btnmatrix_get_selected_btn(self->obj);
216 if (key_idx == LV_BTNMATRIX_BTN_NONE)
218 if (self->key_map_.count(key_idx) != 0) {
219 self->send_key_(self->key_map_[key_idx]);
222 const auto *str = lv_btnmatrix_get_btn_text(self->obj, key_idx);
223 auto len = strlen(str);
225 self->send_key_(*str++);
227 LV_EVENT_PRESSED,
this);
229 #endif // USE_LVGL_BUTTONMATRIX 231 #ifdef USE_LVGL_KEYBOARD 232 static const char *
const KB_SPECIAL_KEYS[] = {
241 [](lv_event_t *event) {
243 if (self->key_callback_.size() == 0)
246 auto key_idx = lv_btnmatrix_get_selected_btn(self->obj);
247 if (key_idx == LV_BTNMATRIX_BTN_NONE)
249 const char *txt = lv_btnmatrix_get_btn_text(self->obj, key_idx);
252 for (
const auto *kb_special_key : KB_SPECIAL_KEYS) {
253 if (strcmp(txt, kb_special_key) == 0)
257 self->send_key_(*txt++);
259 LV_EVENT_PRESSED,
this);
261 #endif // USE_LVGL_KEYBOARD 266 size_t line_len = this->disp_drv_.hor_res * LV_COLOR_DEPTH / 8 / 4 * 2;
267 for (
size_t i = 0; i != line_len; i++) {
272 area.x2 = this->disp_drv_.hor_res - 1;
273 if (this->snow_line_ == this->disp_drv_.ver_res / 2) {
274 area.y1 =
static_cast<lv_coord_t
>(
random_uint32() % (this->disp_drv_.ver_res / 2) * 2);
276 area.y1 = this->snow_line_++ * 2;
279 area.y2 = area.y1 + 1;
280 this->draw_buffer_(&area, (
const uint8_t *) this->draw_buf_.buf1);
284 ESP_LOGCONFIG(TAG,
"LVGL Setup starts");
286 lv_log_register_print_cb(log_cb);
289 lv_update_event =
static_cast<lv_event_code_t
>(lv_event_register_id());
290 lv_api_event =
static_cast<lv_event_code_t
>(lv_event_register_id());
291 auto *display = this->displays_[0];
292 size_t buffer_pixels = display->get_width() * display->get_height() / this->buffer_frac_;
293 auto buf_bytes = buffer_pixels * LV_COLOR_DEPTH / 8;
295 if (buf ==
nullptr) {
296 #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR 297 ESP_LOGE(TAG,
"Malloc failed to allocate %zu bytes", buf_bytes);
300 this->status_set_error(
"Memory allocation failure");
303 lv_disp_draw_buf_init(&this->draw_buf_, buf,
nullptr, buffer_pixels);
304 lv_disp_drv_init(&this->disp_drv_);
305 this->disp_drv_.draw_buf = &this->draw_buf_;
306 this->disp_drv_.user_data =
this;
307 this->disp_drv_.full_refresh = this->full_refresh_;
308 this->disp_drv_.flush_cb = static_flush_cb;
309 this->disp_drv_.rounder_cb = rounder_cb;
310 switch (display->get_rotation()) {
314 this->disp_drv_.sw_rotate =
true;
315 this->disp_drv_.rotated = LV_DISP_ROT_90;
318 this->disp_drv_.sw_rotate =
true;
319 this->disp_drv_.rotated = LV_DISP_ROT_180;
322 this->disp_drv_.sw_rotate =
true;
323 this->disp_drv_.rotated = LV_DISP_ROT_270;
327 this->disp_drv_.hor_res = (lv_coord_t) display->get_width();
328 this->disp_drv_.ver_res = (lv_coord_t) display->get_height();
329 ESP_LOGV(TAG,
"sw_rotate = %d, rotated=%d", this->disp_drv_.sw_rotate, this->disp_drv_.rotated);
330 this->disp_ = lv_disp_drv_register(&this->disp_drv_);
331 for (
const auto &v : this->init_lambdas_)
333 this->show_page(0, LV_SCR_LOAD_ANIM_NONE, 0);
334 lv_disp_trig_activity(this->disp_);
335 ESP_LOGCONFIG(TAG,
"LVGL Setup complete");
342 this->idle_callbacks_.call(lv_disp_get_inactive_time(this->disp_));
346 if (this->show_snow_)
347 this->write_random_();
349 lv_timer_handler_run_in_period(5);
352 if (!lv_is_initialized()) {
353 ESP_LOGE(TAG,
"LVGL call before component is initialised");
359 #ifdef USE_LVGL_ANIMIMG 361 auto *animg = (lv_animimg_t *) obj;
362 int32_t duration = animg->anim.time;
363 lv_animimg_set_duration(obj, 0);
364 lv_animimg_start(obj);
365 lv_animimg_set_duration(obj, duration);
369 reinterpret_cast<LvglComponent *
>(disp_drv->user_data)->flush_cb_(disp_drv, area, color_p);
376 #if defined(USE_HOST) || defined(USE_RP2040) || defined(USE_ESP8266) 378 auto *ptr = malloc(size);
379 if (ptr ==
nullptr) {
380 #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR 381 esphome::ESP_LOGE(esphome::lvgl::TAG,
"Failed to allocate %zu bytes", size);
389 static unsigned cap_bits = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
393 ptr = heap_caps_malloc(size, cap_bits);
394 if (ptr ==
nullptr) {
395 cap_bits = MALLOC_CAP_8BIT;
396 ptr = heap_caps_malloc(size, cap_bits);
398 if (ptr ==
nullptr) {
399 #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_ERROR 400 esphome::ESP_LOGE(esphome::lvgl::TAG,
"Failed to allocate %zu bytes", size);
404 #ifdef ESPHOME_LOG_HAS_VERBOSE 405 esphome::ESP_LOGV(esphome::lvgl::TAG,
"allocate %zu - > %p", size, ptr);
411 #ifdef ESPHOME_LOG_HAS_VERBOSE 412 esphome::ESP_LOGV(esphome::lvgl::TAG,
"free %p", ptr);
420 #ifdef ESPHOME_LOG_HAS_VERBOSE 421 esphome::ESP_LOGV(esphome::lvgl::TAG,
"realloc %p: %zu", ptr, size);
423 return heap_caps_realloc(ptr, size, cap_bits);
void add_event_cb(lv_obj_t *obj, event_callback_t callback, lv_event_code_t event)
std::string lv_event_code_name_for(uint8_t event_code)
void add_on_idle_callback(std::function< void(uint32_t)> &&callback)
void set_paused(bool paused, bool show_snow)
std::vector< TouchPoint > TouchPoints_t
void * lv_custom_mem_alloc(size_t size)
void flush_cb_(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
LVTouchListener(uint16_t long_press_time, uint16_t long_press_repeat_time)
void dump_config() override
LVEncoderListener(lv_indev_type_t type, uint16_t lpt, uint16_t lprt)
void(_lv_event_t *) event_callback_t
uint32_t IRAM_ATTR HOT millis()
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
void lv_custom_mem_free(void *ptr)
lv_event_code_t lv_update_event
lv_event_code_t lv_api_event
void update(const touchscreen::TouchPoints_t &tpoints) override
virtual void set_obj(lv_obj_t *lv_obj)
std::string str_sprintf(const char *fmt,...)
void add_page(LvPageType *page)
bool lv_is_pre_initialise()
void set_obj(lv_obj_t *lv_obj) override
static void static_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
void HOT esp_log_printf_(int level, const char *tag, int line, const char *format,...)
IdleTrigger(LvglComponent *parent, TemplatableValue< uint32_t > timeout)
TemplatableValue< uint32_t > timeout_
void draw_buffer_(const lv_area_t *area, const uint8_t *ptr)
std::vector< LvPageType * > pages_
void * lv_custom_mem_realloc(void *ptr, size_t size)
void show_next_page(lv_scr_load_anim_t anim, uint32_t time)
Implementation of SPI Controller mode.
void show_page(size_t index, lv_scr_load_anim_t anim, uint32_t time)
void show_prev_page(lv_scr_load_anim_t anim, uint32_t time)
void lv_animimg_stop(lv_obj_t *obj)
std::vector< display::Display * > displays_