Thanks, full uninstall and reinstall fixed it
Anybody getting boot loop recently? I have not changed my code, seems to have happened at some point after ESPHome update. I’ve been reading something about version 2.0.14 being the last one working:
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
version: 2.0.14
but that doesn’t work for me, all kinds of issues compiling it.
My suggestion is to check out my updated code - I’ve gone over to
framework:
type: esp-idf
version: recommended
as well as LVGL and - painful as converting over was - not looking back. Most of my stability issues were due to running out of memory, and migrating over to esp-idf has freed up a noticeable amount of memory making them more responsive. I do have one device that reboots every now and then, but as I have a number of them and the one has issues I think that is a hardware fault.
Thanks for the code, I got the device back to life now. Using lvgl now. Also the screen seems to be more responsive. I was using some early touchscreen and display platforms before. I was about to throw it away, but it’s usable again. I might still be tempted to get Waveshare ESP32-C6 1.47inch.
I’m getting an error suggesting the display is not initialized properly. Copilot says in such cases LVGL might still work, and it does, I can draw in LVGL even with that error still there.
But when not using LVGL the display is just covered with random dots and the display initialization error is also shown in logs.
I already tried data_rate: 4MHz and update_interval: 1s
substitutions:
screenstart: ALWAYS_ON
#GPIO pins for the LCD screen
repin: GPIO1
dcpin: GPIO2
bkpin: GPIO3
clpin: GPIO6
mopin: GPIO7
cspin: GPIO10
# GPIO pins for the touch screen
sdapin: GPIO4
sclpin: GPIO5
intpin: GPIO8
display:
- platform: ili9xxx
model: GC9A01A
id: watchface
invert_colors: true
reset_pin: $repin
cs_pin: $cspin
dc_pin:
number: $dcpin
ignore_strapping_warning: true
update_interval: 200ms
pages:
- id: page1
lambda: |-
it.image(0, 00, id(bathroom2));
spi:
mosi_pin: $mopin
clk_pin: $clpin
miso_pin: GPIO8 # free pin, not connected
i2c:
sda: $sdapin
scl: $sclpin
esp32:
board: esp32-c3-devkitm-1
framework:
type: esp-idf
version: recommended
[15:10:09.378][C][ili9xxx:089]: ili9xxx
[15:10:09.378][C][ili9xxx:089]: Rotations: 0 °
[15:10:09.378][C][ili9xxx:089]: Dimensions: 240px x 240px
[15:10:09.378][C][ili9xxx:090]: Width Offset: 0
[15:10:09.378][C][ili9xxx:090]: Height Offset: 0
[15:10:09.380][C][ili9xxx:099]: Color mode: 16bit
[15:10:09.383][C][ili9xxx:108]: Data rate: 8MHz
[15:10:09.385][C][ili9xxx:111]: CS Pin: GPIO10
[15:10:09.388][C][ili9xxx:112]: DC Pin: GPIO2
[15:10:09.391][C][ili9xxx:114]: Color order: BGR
[15:10:09.391][C][ili9xxx:114]: Swap_xy: NO
[15:10:09.391][C][ili9xxx:114]: Mirror_x: YES
[15:10:09.391][C][ili9xxx:114]: Mirror_y: NO
[15:10:09.391][C][ili9xxx:114]: Invert colors: YES
[15:10:09.398][C][ili9xxx:124]: => Failed to init Memory: YES!
[15:10:09.398][C][ili9xxx:362]: Update Interval: 1.0s
[15:10:09.399][E][component:154]: display is marked FAILED: unspecified
[15:10:09.452][C][light:088]: Light 'Display Backlight'
[15:10:09.454][C][light:091]: Default Transition Length: 1.0s
[15:10:09.454][C][light:091]: Gamma Correct: 2.80
Hmmmm… AI is a handy tool, and in general is getting better, but can still be misleading. First thing I’d do would be to do a ‘clean build files’ and recompile just in case. If the error is still there then can investigate further! ![]()
[FWIW I just recompiled my code under esphome 2025.10.5 and HA 2025.11.2, and no errors…]
Use the mipi_spi driver instead of ili9xxx, it will cope better with limited memory as it can use a partial buffer.
Thanks - that fixed it.
First I replaced ili9xxx with mipi_spi with no other changes and LVGL still worked, but no more memory initialization error.
Then I replaced LVGL with Display Lambda to show a picture and that also worked.
Did you get this working?
I am looking to do something similar using Music Assistant.
If your willing to share your code that would be amazing.
As an aside, FWIW I think this has a lot of promise to help generate a decent looking display:
substitutions:
friendly_name: Round Display
screensaver: 30s
esphome:
name: round_display
friendly_name: $friendly_name
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
logger:
level: INFO
baud_rate: 0
api:
ota:
- platform: esphome
wifi:
ssid: "123"
password: "123123123"
ap:
ssid: "RDisplay Fallback Hotspot"
password: "123123123"
captive_portal:
web_server:
version: 3
local: True
log: False
time:
- platform: sntp
id: esptime
timezone: "Europe/Moscow"
servers:
- time.apple.com
- time.google.com
- 1.pool.ntp.org
globals:
- id: is_day
type: bool
restore_value: false
initial_value: 'true'
- id: touch_start_x
type: int
initial_value: '0'
- id: touch_start_y
type: int
initial_value: '0'
- id: touch_end_x
type: int
initial_value: '0'
- id: touch_end_y
type: int
initial_value: '0'
- id: touch_start_time
type: unsigned long
initial_value: '0'
sensor:
- platform: scd4x
update_interval: 20s
co2:
name: "SCD41 CO2"
id: scd41_co2
temperature:
name: "SCD41 Temperature"
id: scd41_temp
humidity:
name: "SCD41 Humidity"
id: scd41_hum
- platform: bh1750
name: "BH1750 Illuminance"
id: bh1750_lux
address: 0x23
update_interval: 20s
- platform: bmp085
temperature:
name: "BMP180 Temperature"
id: bmp180_temp
pressure:
name: "BMP180 Pressure"
id: bmp180_pres
update_interval: 20s
- platform: htu21d
model: htu21d
temperature:
name: "HTU21D Temperature"
id: htu21d_temp
humidity:
name: "HTU21D Humidity"
id: htu21d_hum
update_interval: 20s
spi:
mosi_pin: GPIO7
clk_pin: GPIO6
i2c:
sda: GPIO20
scl: GPIO21
frequency: 100kHz
scan: true
id: touchscreen_i2c
# Using native CST816 touchscreen platform
touchscreen:
- platform: cst816
id: my_touchscreen
address: 0x15
reset_pin: GPIO8
skip_probe: true
i2c_id: touchscreen_i2c
transform:
mirror_x: false
mirror_y: false
swap_xy: false
on_touch:
then:
- lambda: |-
ESP_LOGI("TOUCH", "=== TOUCH x=%d, y=%d ===", touch.x, touch.y);
id(touch_start_x) = touch.x;
id(touch_start_y) = touch.y;
id(touch_end_x) = touch.x;
id(touch_end_y) = touch.y;
id(touch_start_time) = millis();
- script.execute: screentime
on_release:
then:
- lambda: |-
ESP_LOGI("TOUCH", "=== RELEASE ===");
unsigned long touch_duration = millis() - id(touch_start_time);
int delta_x = id(touch_end_x) - id(touch_start_x);
int delta_y = id(touch_end_y) - id(touch_start_y);
int abs_delta_x = abs(delta_x);
int abs_delta_y = abs(delta_y);
ESP_LOGI("TOUCH", "Duration=%lu ms, delta_x=%d, delta_y=%d",
touch_duration, delta_x, delta_y);
// CST816 в polling mode генерирует только одно событие touch
// Используем ДЛИТЕЛЬНОСТЬ касания и ПОЛОЖЕНИЕ для определения жестов:
// - Касание в верхней части экрана (y < 60) = SWIPE UP
// - Касание в нижней части (y > 180) = SWIPE DOWN
// - Касание слева (x < 60) = SWIPE LEFT
// - Касание справа (x > 180) = SWIPE RIGHT
// - В центре экрана - клик или долгое нажатие
int touch_x = id(touch_start_x);
int touch_y = id(touch_start_y);
if (touch_duration > 500) {
// Длинное нажатие
ESP_LOGI("TOUCH", "Gesture: LONG PRESS");
id(my_touch_screen).publish_state("LONG PRESS");
} else if (touch_y < 60) {
// Верхняя часть экрана
ESP_LOGI("TOUCH", "Gesture: SWIPE UP (top area)");
id(my_touch_screen).publish_state("SWIPE UP");
} else if (touch_y > 180) {
// Нижняя часть экрана
ESP_LOGI("TOUCH", "Gesture: SWIPE DOWN (bottom area)");
id(my_touch_screen).publish_state("SWIPE DOWN");
} else if (touch_x < 60) {
// Левая часть экрана
ESP_LOGI("TOUCH", "Gesture: SWIPE LEFT (left area)");
id(my_touch_screen).publish_state("SWIPE LEFT");
} else if (touch_x > 180) {
// Правая часть экрана
ESP_LOGI("TOUCH", "Gesture: SWIPE RIGHT (right area)");
id(my_touch_screen).publish_state("SWIPE RIGHT");
} else {
// Центр экрана - короткое нажатие
ESP_LOGI("TOUCH", "Gesture: SINGLE CLICK (center)");
id(my_touch_screen).publish_state("SINGLE CLICK");
}
# скрипт управления подсветкой
script:
- id: screentime
mode: restart
then:
- light.control:
id: back_light
brightness: 100%
- delay: $screensaver
- if:
condition:
lambda: 'return id(is_day);'
then:
- light.control:
id: back_light
brightness: 100%
else:
- light.control:
id: back_light
brightness: 20%
text_sensor:
- platform: template
id: my_touch_screen
name: "Touch Gesture"
internal: true
on_value:
then:
- script.execute: screentime
- if:
condition:
text_sensor.state:
id: my_touch_screen
state: 'SINGLE CLICK'
then:
- logger.log: "Single click detected"
- if:
condition:
text_sensor.state:
id: my_touch_screen
state: 'SWIPE RIGHT'
then:
- display.page.show_next: watchface
- component.update: watchface
- logger.log: "Swiped right, next page"
- if:
condition:
text_sensor.state:
id: my_touch_screen
state: 'SWIPE LEFT'
then:
- display.page.show_previous: watchface
- delay: 0.5s
- component.update: watchface
- logger.log: "Swiped left, previous page"
- if:
condition:
and:
- text_sensor.state:
id: my_touch_screen
state: 'LONG PRESS'
- display.is_displaying_page: page2
then:
- logger.log: "Long press on page2"
- display.page.show: page2
- component.update: watchface
output:
- platform: ledc
pin: GPIO3
id: gpio_3_backlight_pwm
frequency: 1000Hz
light:
- platform: monochromatic
output: gpio_3_backlight_pwm
name: "Display Backlight"
id: back_light
restore_mode: RESTORE_DEFAULT_ON
font:
- file: "gfonts://Roboto"
id: font_12
size: 12
- file: "gfonts://Roboto"
id: font_16
size: 16
- file: "gfonts://Roboto"
id: font_20
size: 20
- file: "gfonts://Roboto"
id: font_24
size: 24
- file: "gfonts://Roboto"
id: font_32
size: 32
- file: "gfonts://Roboto"
id: font_64
size: 64
- file: "gfonts://Material Design Icons"
id: icon_font_24
size: 24
glyphs: [
"\U000F0E0E", # mdi:air-filter (CO2)
"\U000F0E02", # mdi:thermometer (температура)
"\U000F058E", # mdi:water-percent (влажность)
"\U000F0F55", # mdi:gauge (давление)
"\U000F0335", # mdi:brightness-6 (освещенность)
"\U000F0954" # mdi:clock-outline (время)
]
- file: "gfonts://Material Design Icons"
id: icon_font_16
size: 16
glyphs: [
"\U000F0E0E", # mdi:air-filter (CO2)
"\U000F0E02", # mdi:thermometer (температура)
"\U000F058E", # mdi:water-percent (влажность)
"\U000F0F55", # mdi:gauge (давление)
"\U000F0335", # mdi:brightness-6 (освещенность)
"\U000F0954" # mdi:clock-outline (время)
]
color:
- id: my_red
hex: FF0000
- id: my_green
hex: 008000
- id: my_blue
hex: 0000FF
- id: my_yellow
hex: FFFF00
- id: my_cyan
hex: 00FFFF
- id: my_white
hex: FFFFFF
display:
- platform: ili9xxx
invert_colors: true
model: GC9A01A
id: watchface
reset_pin: GPIO1
cs_pin: GPIO10
dc_pin:
number: GPIO2
ignore_strapping_warning: true
update_interval: 1s
pages:
- id: page1
lambda: |-
// CO2 с иконкой
it.printf(60, 65, id(icon_font_24), id(my_yellow), TextAlign::CENTER, "\U000F0E0E");
it.printf(180, 65, id(font_32), id(my_yellow), TextAlign::CENTER, "%.0f ppm", id(scd41_co2).state);
// Время с иконкой
it.printf(60, 120, id(icon_font_24), id(my_yellow), TextAlign::CENTER, "\U000F0954");
it.strftime(180, 120, id(font_64), TextAlign::CENTER, "%H:%M:%S", id(esptime).now());
// Температура с иконкой
it.printf(60, 170, id(icon_font_24), id(my_yellow), TextAlign::CENTER, "\U000F0E02");
it.printf(180, 170, id(font_32), id(my_yellow), TextAlign::CENTER, "%.1f°C", id(scd41_temp).state);
// Влажность с иконкой
it.printf(60, 205, id(icon_font_24), id(my_yellow), TextAlign::CENTER, "\U000F058E");
it.printf(180, 205, id(font_32), id(my_yellow), TextAlign::CENTER, "%.1f%%", id(scd41_hum).state);
it.circle(120, 120, 119, id(my_yellow));
- id: page2
lambda: |-
// CO2 с иконкой
it.printf(60, 65, id(icon_font_24), id(my_red), TextAlign::CENTER, "\U000F0E0E");
it.printf(180, 65, id(font_32), id(my_red), TextAlign::CENTER, "%.0f ppm", id(scd41_co2).state);
// Время с иконкой
it.printf(60, 120, id(icon_font_24), id(my_red), TextAlign::CENTER, "\U000F0954");
it.strftime(180, 120, id(font_32), TextAlign::CENTER, "%H:%M:%S", id(esptime).now());
// Температура HTU21D с иконкой
it.printf(60, 170, id(icon_font_24), id(my_red), TextAlign::CENTER, "\U000F0E02");
it.printf(180, 170, id(font_32), id(my_red), TextAlign::CENTER, "%.1f°C", id(htu21d_temp).state);
// Влажность HTU21D с иконкой
it.printf(60, 205, id(icon_font_24), id(my_red), TextAlign::CENTER, "\U000F058E");
it.printf(180, 205, id(font_32), id(my_red), TextAlign::CENTER, "%.1f%%", id(htu21d_hum).state);
it.circle(120, 120, 119, id(my_red));
- id: page3
lambda: |-
// Заголовок
it.printf(120, 15, id(font_20), id(my_cyan), TextAlign::CENTER, "ALL SENSORS");
// SCD41 данные с иконками
it.printf(20, 40, id(icon_font_16), id(my_white), TextAlign::CENTER, "\U000F0E0E");
it.printf(50, 40, id(font_16), id(my_white), TextAlign::LEFT, "CO2: %.0f ppm", id(scd41_co2).state);
it.printf(20, 58, id(icon_font_16), id(my_white), TextAlign::CENTER, "\U000F0E02");
it.printf(50, 58, id(font_16), id(my_white), TextAlign::LEFT, "T: %.1f°C", id(scd41_temp).state);
it.printf(140, 58, id(icon_font_16), id(my_white), TextAlign::CENTER, "\U000F058E");
it.printf(170, 58, id(font_16), id(my_white), TextAlign::LEFT, "H: %.1f%%", id(scd41_hum).state);
// HTU21D данные с иконками
it.printf(20, 85, id(icon_font_16), id(my_green), TextAlign::CENTER, "\U000F0E02");
it.printf(50, 85, id(font_16), id(my_green), TextAlign::LEFT, "HTU T: %.1f°C", id(htu21d_temp).state);
it.printf(20, 103, id(icon_font_16), id(my_green), TextAlign::CENTER, "\U000F058E");
it.printf(50, 103, id(font_16), id(my_green), TextAlign::LEFT, "HTU H: %.1f%%", id(htu21d_hum).state);
// BMP180 данные с иконками
it.printf(20, 130, id(icon_font_16), id(my_yellow), TextAlign::CENTER, "\U000F0E02");
it.printf(50, 130, id(font_16), id(my_yellow), TextAlign::LEFT, "BMP T: %.1f°C", id(bmp180_temp).state);
it.printf(20, 148, id(icon_font_16), id(my_yellow), TextAlign::CENTER, "\U000F0F55");
it.printf(50, 148, id(font_16), id(my_yellow), TextAlign::LEFT, "P: %.0f hPa", id(bmp180_pres).state);
it.printf(20, 175, id(icon_font_16), id(my_blue), TextAlign::CENTER, "\U000F0335");
it.printf(50, 175, id(font_16), id(my_blue), TextAlign::LEFT, "Light: %.0f lx", id(bh1750_lux).state);
// Время с иконкой
it.printf(80, 210, id(icon_font_16), id(my_cyan), TextAlign::CENTER, "\U000F0954");
it.strftime(160, 210, id(font_20), id(my_cyan), TextAlign::CENTER, "%H:%M:%S", id(esptime).now());
// Рамка
it.circle(120, 120, 119, id(my_cyan));
sun:
latitude: 10.00
longitude: 20.00
on_sunrise:
- then:
- globals.set:
id: is_day
value: 'true'
- light.control:
id: back_light
brightness: 100%
- logger.log: "Sunrise: brightness set to 100%"
on_sunset:
- elevation: -1
then:
- globals.set:
id: is_day
value: 'false'
- light.control:
id: back_light
brightness: 20%
- logger.log: "Sunset: brightness set to 20%"
I spent the whole evening trying to get the display to work on the new version of esphome %)