-
-
Save clydebarrow/ef89e9a93bd44771483b9144ae9042a1 to your computer and use it in GitHub Desktop.
# Gitignore settings for ESPHome | |
# This is an example and may include too much for your use-case. | |
# You can modify this file to suit your needs. | |
/.esphome/ | |
/secrets.yaml | |
/wifi.yaml |
time: | |
- platform: sntp | |
id: time_comp | |
on_time_sync: | |
then: | |
- script.execute: time_update | |
script: | |
- id: time_update | |
then: | |
- lvgl.indicator.line.update: | |
id: minute_hand | |
value: !lambda |- | |
return id(time_comp).now().minute; | |
- lvgl.indicator.line.update: | |
id: hour_hand | |
value: !lambda |- | |
auto now = id(time_comp).now(); | |
return std::fmod(now.hour, 12) * 60 + now.minute; | |
- lvgl.label.update: | |
id: date_label | |
text: | |
format: "%s %2d" | |
args: | |
- '(new const char *[12]{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"})[id(time_comp).now().month-1]' | |
- 'id(time_comp).now().day_of_month' | |
- lvgl.label.update: | |
id: day_label | |
text: | |
format: "%s" | |
args: | |
- '(new const char *[7]{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"})[id(time_comp).now().day_of_week-1]' | |
font: | |
- file: "gfonts://Roboto" | |
id: roboto10 | |
size: 10 | |
bpp: 4 | |
interval: | |
- interval: 1min | |
then: | |
- script.execute: time_update | |
lvgl: | |
style_definitions: | |
- id: date_style | |
text_font: roboto10 | |
align: center | |
text_color: 0x000000 | |
bg_opa: cover | |
radius: 4 | |
pad_all: 2 | |
widgets: | |
- obj: # Clock container | |
height: 170 | |
width: 170 | |
align: center | |
pad_all: 4 | |
widgets: | |
- meter: # Gradient color arc | |
height: 100% | |
width: 100% | |
align: center | |
bg_color: 0 | |
scales: | |
angle_range: 360 | |
rotation: 255 | |
range_from: 0 | |
range_to: 12 | |
ticks: | |
width: 35 | |
count: 13 | |
length: 8 | |
indicators: | |
- ticks: | |
local: true | |
start_value: 0 | |
end_value: 12 | |
color_start: 0xFF0000 | |
color_end: 0x0000FF | |
- meter: | |
height: 100% | |
width: 100% | |
align: center | |
bg_opa: TRANSP | |
text_color: 0xFFFFFF | |
scales: | |
- ticks: | |
width: 1 | |
count: 61 | |
length: 10 | |
color: 0xFFFFFF | |
range_from: 0 | |
range_to: 60 | |
angle_range: 360 | |
rotation: 270 | |
indicators: | |
- line: | |
id: minute_hand | |
width: 3 | |
color: 0xE0E0E0 | |
r_mod: -1 | |
- | |
angle_range: 330 | |
rotation: 300 | |
range_from: 1 | |
range_to: 12 | |
ticks: | |
width: 1 | |
count: 12 | |
length: 1 | |
major: | |
stride: 1 | |
width: 4 | |
length: 8 | |
color: 0xC0C0C0 | |
label_gap: 6 | |
- angle_range: 360 | |
rotation: 270 | |
range_from: 0 | |
range_to: 720 | |
indicators: | |
- line: | |
id: hour_hand | |
width: 4 | |
color: 0xA0A0A0 | |
r_mod: -20 | |
- label: | |
styles: date_style | |
id: day_label | |
y: -20 | |
- label: | |
id: date_label | |
styles: date_style | |
y: +20 | |
--- | |
substitutions: | |
name: indicator | |
friendly_name: "Indicator LVGL" | |
esphome: | |
name: indicator | |
friendly_name: "${friendly_name}" | |
name_add_mac_suffix: false | |
platformio_options: | |
build_unflags: -Werror=all | |
esp32: | |
board: esp32-s3-devkitc-1 | |
variant: esp32s3 | |
framework: | |
type: esp-idf | |
# Required to get the latest RGB driver | |
platform_version: 6.3.2 | |
version: 5.0.2 | |
# Required to achieve sufficient PSRAM bandwidth | |
sdkconfig_options: | |
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y | |
CONFIG_ESP32S3_DATA_CACHE_64KB: y | |
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y | |
CONFIG_SPIRAM_RODATA: y | |
wifi: !include wifi.yaml | |
external_components: | |
- source: github://clydebarrow/esphome@lvgl | |
refresh: 10min | |
components: [lvgl, font, display, ft5x06] | |
- source: github://pr#5872 | |
refresh: 10min | |
components: [st7701s] | |
packages: | |
lvgl: !include lvgl-package.yaml | |
psram: | |
mode: octal | |
speed: 80MHz | |
logger: | |
level: DEBUG | |
hardware_uart: UART0 | |
output: | |
- platform: ledc | |
pin: | |
number: GPIO45 | |
ignore_strapping_warning: true | |
id: ledc_gpio4 | |
frequency: 100Hz | |
light: | |
- platform: monochromatic | |
output: ledc_gpio4 | |
name: Display Backlight | |
id: display_backlight | |
restore_mode: ALWAYS_ON | |
spi: | |
- id: lcd_spi | |
clk_pin: 41 | |
mosi_pin: 48 | |
i2c: | |
sda: 39 | |
scl: 40 | |
scan: false | |
id: bus_a | |
# I/O expander. Touchscreen RESET and INTERRUPT are not used. | |
pca9554: | |
- id: p_c_a | |
pin_count: 16 | |
address: 0x20 | |
touchscreen: | |
- platform: ft5x06 | |
id: ft5x06_touchscreen | |
transform: | |
mirror_x: true | |
mirror_y: true | |
on_release: | |
then: | |
- if: | |
condition: lvgl.is_paused | |
then: | |
- light.turn_on: display_backlight | |
- lvgl.resume: | |
- lvgl.widget.redraw: | |
display: | |
- platform: st7701s | |
auto_clear_enabled: false | |
update_interval: never | |
spi_mode: MODE3 | |
color_order: RGB | |
dimensions: | |
width: 480 | |
height: 480 | |
invert_colors: true | |
transform: | |
mirror_x: true | |
mirror_y: true | |
cs_pin: | |
pca9554: p_c_a | |
number: 4 | |
reset_pin: | |
pca9554: p_c_a | |
number: 5 | |
de_pin: 18 | |
hsync_pin: 16 | |
vsync_pin: 17 | |
pclk_pin: 21 | |
# Init sequence can be one of the defaults and/or custom sequences. | |
init_sequence: | |
- 1 # select canned init sequence number 1 | |
# Custom sequences are an array, first byte is command, the rest are data. | |
- [ 0xE0, 0x1F ] # Set sunlight readable enhancement | |
data_pins: | |
red: | |
- 4 #r1 | |
- 3 #r2 | |
- 2 #r3 | |
- 1 #r4 | |
- 0 #r5 | |
green: | |
- 10 #g0 | |
- 9 #g1 | |
- 8 #g2 | |
- 7 #g3 | |
- 6 #g4 | |
- 5 #g5 | |
blue: | |
- 15 #b1 | |
- 14 #b2 | |
- 13 #b3 | |
- 12 #b4 | |
- 11 #b5 | |
lvgl: | |
touchscreens: ft5x06_touchscreen | |
on_idle: | |
timeout: 120s | |
then: | |
- logger.log: "LVGL is idle" | |
- lvgl.pause: | |
- light.turn_off: | |
id: display_backlight | |
transition_length: 5s |
--- | |
# A random collection of LVGL stuff. | |
substitutions: | |
light_recessed: "\U000F179B" | |
wall_sconce_round: "\U000F0748" | |
gas_burner: "\U000F1A1B" | |
home_icon: "\U000F02DC" | |
menu_left: "\U000F0A02" | |
menu_right: "\U000F035F" | |
close: "\U000F0156" | |
delete: "\U000F01B4" | |
backspace: "\U000F006E" | |
check: "\U000F012C" | |
arrow_down: "\U000F004B" | |
esphome: | |
on_boot: | |
then: | |
- light.turn_on: | |
id: lv_light | |
brightness: 100% | |
red: 100% | |
green: 0 | |
blue: 0 | |
#sensor: | |
# - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB | |
# name: "WiFi Signal dB" | |
# id: wifi_signal_db | |
# update_interval: 20s | |
# entity_category: "diagnostic" | |
# on_value: | |
# then: | |
# - lvgl.label.update: | |
# id: wifi_label | |
# text: !lambda |- | |
# static char buf[10]; | |
# snprintf(buf, 10, "%.0fdBm", id(wifi_signal_db).get_state()); | |
# return buf; | |
light: | |
- platform: lvgl | |
name: LVGL LED | |
id: lv_light | |
led: lv_led | |
effects: | |
- pulse: | |
name: "Slow Pulse" | |
# transition_length: 1s # defaults to 1s | |
update_interval: 2s | |
- strobe: | |
- strobe: | |
name: Strobe Effect With Custom Values | |
colors: | |
- state: true | |
brightness: 100% | |
red: 100% | |
green: 90% | |
blue: 0% | |
duration: 500ms | |
- state: false | |
duration: 250ms | |
- state: true | |
brightness: 100% | |
red: 0% | |
green: 100% | |
blue: 0% | |
duration: 500ms | |
number: | |
- platform: lvgl | |
widget: lv_slider | |
id: lvgl_slider_sensor | |
name: LVGL Slider | |
- platform: lvgl | |
widget: lv_arc | |
id: lvgl_arc_sensor | |
name: LVGL Arc | |
- platform: lvgl | |
widget: lv_bar | |
id: lvgl_bar_sensor | |
name: LVGL Bar | |
# on_value: | |
# then: | |
# - if: | |
# condition: | |
# number.in_range: | |
# id: lvgl_arc_sensor | |
# below: 50 | |
# then: | |
# - lvgl.slider.update: | |
# id: lv_slider | |
# knob: | |
# bg_color: 0xFF0000 | |
# - lvgl.img.update: | |
# id: lv_img | |
# src: cat_image | |
# else: | |
# - lvgl.slider.update: | |
# id: lv_slider | |
# knob: | |
# bg_color: 0x00FF00 | |
# - lvgl.img.update: | |
# id: lv_img | |
# src: dog_img | |
binary_sensor: | |
- platform: lvgl | |
name: Pressbutton | |
widget: lv_page1_button | |
publish_initial_state: true | |
- platform: lvgl | |
name: ButtonMatrix button | |
widget: button_a | |
- platform: lvgl | |
id: switch_d | |
name: Matrix switch D | |
widget: button_d | |
on_click: | |
then: | |
- lvgl.page.previous: | |
animation: move_right | |
time: 600ms | |
- platform: lvgl | |
id: button_checker | |
name: LVGL button | |
widget: lv_button | |
on_state: | |
then: | |
- lvgl.checkbox.update: | |
id: lv_checkbox | |
state: | |
checked: !lambda return x; | |
text: Unchecked | |
- platform: lvgl | |
name: LVGL checkbox | |
widget: lv_checkbox | |
font: | |
- file: "gfonts://Roboto" | |
id: roboto20 | |
size: 20 | |
extras: | |
- file: 'materialdesignicons-webfont.ttf' | |
glyphs: [ | |
"\U000F004B", | |
"\U0000f0ed", | |
"\U000F006E", | |
"\U000F012C", | |
"\U000F179B", | |
"\U000F0748", | |
"\U000F1A1B", | |
"\U000F02DC", | |
"\U000F0A02", | |
"\U000F035F", | |
"\U000F0156", | |
"\U000F0C5F", | |
"\U000f0084", | |
"\U000f0091", | |
] | |
- file: "gfonts://Roboto" | |
id: roboto10 | |
size: 10 | |
bpp: 4 | |
extras: | |
- file: 'materialdesignicons-webfont.ttf' | |
glyphs: [ | |
"\U000F004B", | |
"\U0000f0ed", | |
"\U000F006E", | |
"\U000F012C", | |
"\U000F179B", | |
"\U000F0748", | |
"\U000F1A1B", | |
"\U000F02DC", | |
"\U000F0A02", | |
"\U000F035F", | |
"\U000F0156", | |
"\U000F0C5F", | |
"\U000f0084", | |
"\U000f0091", | |
] | |
- file: "gfonts://Helvetica" | |
id: helv20 | |
bpp: 2 | |
size: 20 | |
extras: | |
- file: 'materialdesignicons-webfont.ttf' | |
glyphs: [ | |
"\U000F004B", | |
"\U0000f0ed", | |
"\U000F006E", | |
"\U000F012C", | |
"\U000F179B", | |
"\U000F0748", | |
"\U000F1A1B", | |
"\U000F02DC", | |
"\U000F0A02", | |
"\U000F035F", | |
"\U000F0156", | |
"\U000F0C5F", | |
"\U000f0084", | |
"\U000f0091", | |
] | |
- file: 'gfonts://Roboto Condensed' | |
id: roboto42 | |
size: 28 | |
bpp: 4 | |
glyphs: 'aAbBcCxXyYzZáÁéÉíÍóÓőŐúÚűŰ' | |
- file: montserrat.ttf | |
id: mont20 | |
glyphs: 'aAbBDcCxXyYzZáÁéÉíÍóÓőŐúÚűŰ0' | |
size: 20 | |
bpp: 4 | |
image: | |
- file: cat.jpg | |
id: cat_image | |
resize: 100x100 | |
type: RGB565 | |
- file: cat.jpg | |
id: disp_bg | |
resize: 200x200 | |
type: RGB565 | |
- file: dog.jpg | |
id: dog_img | |
resize: 100x100 | |
type: RGB565 | |
color: | |
- id: color_back | |
hex: FF0000 | |
- id: color_blue | |
hex: 0000FF | |
select: | |
- platform: lvgl | |
widget: lv_dropdown | |
name: LVGL Dropdown | |
- platform: lvgl | |
widget: lv_roller | |
name: LVGL Roller | |
switch: | |
- platform: lvgl | |
name: Button switch | |
widget: lv_button | |
on_turn_on: | |
then: | |
- lvgl.widget.disable: lv_arc | |
- lvgl.widget.hide: button_c | |
on_turn_off: | |
then: | |
- lvgl.widget.show: button_c | |
- lvgl.widget.enable: lv_arc | |
- platform: lvgl | |
name: Matrix switch | |
widget: button_a | |
- platform: lvgl | |
name: Switch switch | |
widget: lv_switch | |
lvgl: | |
buffer_size: 100% | |
#default_font: roboto20 | |
msgboxes: | |
- id: message_box | |
close_button: true | |
title: Messagebox | |
body: | |
text: This is a sample messagebox | |
bg_color: 0x808080 | |
buttons: | |
- id: msgbox_close | |
text: close | |
- id: msgbox_apply | |
text: "Close" | |
on_click: | |
then: | |
- lvgl.widget.hide: message_box | |
on_idle: | |
- timeout: 10s | |
then: | |
- logger.log: idle timeout | |
- if: | |
condition: | |
lvgl.is_idle: | |
timeout: 5s | |
then: | |
- logger.log: LVGL is idle | |
- timeout: 15s | |
then: | |
- logger.log: idle 15s timeout | |
#- lvgl.pause: | |
#- light.turn_off: | |
# id: display_backlight | |
# transition_length: 5s | |
log_level: INFO | |
color_depth: 16 | |
disp_bg_image: disp_bg | |
bg_opa: TRANSP | |
style_definitions: | |
- id: style_line | |
line_color: color_blue | |
line_width: 8 | |
line_rounded: true | |
- id: date_style | |
text_font: roboto10 | |
align: center | |
text_color: 0x000000 | |
bg_opa: cover | |
radius: 4 | |
pad_all: 2 | |
theme: | |
arc: | |
scroll_on_focus: true | |
group: general | |
slider: | |
scroll_on_focus: true | |
group: general | |
btn: | |
text_font: roboto10 | |
scroll_on_focus: true | |
group: general | |
border_width: 2 | |
border_side: left | |
outline_pad: 6 | |
text_color: 0x000000 | |
checked: | |
text_color: 0xFF0000 | |
pressed: | |
border_color: 0xFF0000 | |
text_color: 0xFFFFFF | |
focused: | |
border_color: 0x00FF00 | |
checkbox: | |
border_color: 0xC0C0C0 | |
indicator: | |
text_font: montserrat_14 | |
checked: | |
bg_color: 0xC0C0C0 | |
top_layer: | |
text_font: helv20 | |
widgets: | |
btnmatrix: | |
width: 100% | |
height: 10% | |
align: bottom_mid | |
pad_all: 5 | |
outline_width: 0 | |
shadow_width: 0 | |
id: top_layer | |
rows: | |
- buttons: | |
- id: top_prev | |
text: "${menu_left}" | |
width: 1 | |
on_click: | |
then: | |
lvgl.page.previous: | |
- id: top_home | |
text: "${home_icon}" | |
width: 1 | |
on_click: | |
then: | |
lvgl.page.show: main_page | |
- id: top_next | |
text: "${menu_right}" | |
width: 1 | |
on_click: | |
then: | |
lvgl.page.next: | |
page_wrap: true | |
pages: | |
- id: main_page | |
skip: true | |
layout: flex | |
width: 100% | |
bg_color: 0x808080 | |
bg_opa: TRANSP | |
pad_all: 10 | |
widgets: | |
- btn: | |
text_color: 0x000000 | |
pressed: | |
border_color: color_blue | |
text_color: 0xFFFFFF | |
checkable: true | |
id: lv_button | |
pad_left: 20px | |
pad_top: 20px | |
pad_bottom: 8px | |
pad_right: 8px | |
widgets: | |
- img: | |
src: cat_image | |
bg_opa: TRANSP | |
align: bottom_right | |
- label: | |
styles: date_style | |
align: bottom_right | |
x: -20 | |
y: -20 | |
text: "Label text" | |
long_mode: dot | |
id: wifi_label | |
- checkbox: | |
scroll_on_focus: true | |
group: general | |
id: lv_checkbox | |
align: center | |
text: Checkbox | |
- switch: | |
id: lv_switch | |
- bar: | |
id: lv_bar | |
width: 50px | |
on_value: | |
then: | |
- logger.log: | |
format: "Bar value is %f" | |
args: [ x ] | |
- arc: | |
id: lv_arc | |
adjustable: true | |
#on_release: | |
#then: | |
#- lambda: |- | |
#esph_log_d("lvgl", "on_release %f", x); | |
on_value: | |
then: | |
- logger.log: | |
format: "Arc value is %f" | |
args: [ x ] | |
group: general | |
scroll_on_focus: true | |
value: 75 | |
min_value: 1 | |
max_value: 100 | |
arc_color: 0xFF0000 | |
indicator: | |
arc_color: 0xF000FF | |
pressed: | |
arc_color: 0xFFFF00 | |
focused: | |
arc_color: 0x808080 | |
- slider: | |
knob: | |
focused: | |
bg_color: 0x808080 | |
group: general | |
scroll_on_focus: true | |
id: lv_slider | |
height: 30% | |
align: center | |
width: 20 | |
min_value: 0 | |
max_value: 50 | |
on_value: | |
- logger.log: | |
format: "Value on_value: %.0f" | |
args: [ 'x' ] | |
on_release: | |
- logger.log: | |
format: "Value on_release: %.0f" | |
args: [ 'x' ] | |
- dropdown: | |
indicator: | |
text_font: helv20 | |
id: lv_dropdown | |
options: | |
- First | |
- Second | |
- Third | |
selected_index: 2 | |
dir: top | |
symbol: ${arrow_down} | |
dropdown_list: | |
bg_color: color_blue | |
text_color: 0x800000 | |
- label: | |
text_font: helv20 | |
outline_width: 1 | |
outline_color: 0xFFFFFF | |
text: "XX \U000f0084 \U0000f0ed XX" #mdi-battery-charging | |
- label: | |
outline_width: 1 | |
outline_color: 0xFFFFFF | |
text_font: montserrat_20 | |
text: 'aAbBDcCxXyYzZáÁéÉíÍóÓőŐúÚűŰ0' | |
- id: page_1 | |
layout: flex | |
pad_all: 10 | |
widgets: | |
- obj: | |
width: 100% | |
height: 50px | |
bg_color: 0xFFFFFF | |
outline_width: 0 | |
border_width: 2 | |
border_color: 0x000000 | |
- label: | |
height: size_content | |
width: 150px | |
long_mode: scroll_circular | |
text: 'Page 1 label with very long text wrapping lines' | |
- btn: | |
on_click: | |
then: | |
- logger.log: Button clicked | |
- lvgl.widget.show: message_box | |
width: size_content | |
id: change_btnm | |
widgets: | |
- label: | |
width: 100px | |
long_mode: scroll | |
text: Disable button matrix | |
on_press: | |
then: | |
- lvgl.widget.update: | |
id: b_matrix | |
state: | |
disabled: true | |
- lambda: |- | |
static const char * new_matrix[] = {"A","bbb","\n","ccc",LV_SYMBOL_PREV,"\n","E",NULL}; | |
lv_btnmatrix_set_map(id(b_matrix)->obj, new_matrix); | |
text_color: 0x000000 | |
align: center | |
- btn: | |
bg_color: 0x80FF00 | |
width: size_content | |
id: lv_page1_button0 | |
on_click: | |
then: | |
- lvgl.pause: | |
show_snow: true | |
widgets: | |
- label: | |
bg_color: 0x80ffff | |
width: 100px | |
long_mode: scroll | |
text: Disable button matrix | |
- btn: | |
bg_color: 0xFF80FF | |
width: size_content | |
id: lv_page1_button1 | |
on_click: | |
then: | |
- lvgl.widget.show: | |
id: b_matrix | |
widgets: | |
- label: | |
text_font: helv20 | |
bg_color: 0xFF80FF | |
width: 100px | |
long_mode: scroll | |
text: Disable button matrix | |
- btn: | |
on_click: | |
then: | |
- logger.log: Button clicked | |
- lvgl.widget.show: message_box | |
width: size_content | |
id: lv_page1_button | |
widgets: | |
- label: | |
width: 100px | |
long_mode: scroll | |
text: "Show message box" | |
- roller: | |
id: lv_roller | |
options: | |
- Jan | |
- Feb | |
- Mar | |
- Apr | |
- May | |
- Jun | |
- Jul | |
- Aug | |
- Sep | |
- Oct | |
- Nov | |
- Dec | |
selected_index: 2 | |
- led: | |
id: lv_led | |
color: 0xFF0000 | |
brightness: 50% | |
on_long_press: | |
then: | |
- lvgl.page.show: main_page | |
- btnmatrix: | |
items: | |
checked: | |
bg_color: 0xFFFF00 | |
id: b_matrix | |
rows: | |
- buttons: | |
- id: button_a | |
text: ${home_icon} | |
width: 2 | |
control: | |
checkable: true | |
- id: button_b | |
text: B | |
width: 1 | |
on_click: | |
then: | |
- lvgl.page.previous: | |
control: | |
hidden: false | |
- buttons: | |
- id: button_c | |
text: C | |
control: | |
checkable: false | |
- id: button_d | |
text: ${menu_left} | |
on_long_press: | |
then: | |
logger.log: Long pressed | |
on_long_press_repeat: | |
then: | |
logger.log: Long pressed repeated | |
- buttons: | |
- id: button_e | |
text: E | |
width: 2 | |
control: | |
checked: true | |
- id: page_2 | |
layout: flex | |
widgets: | |
- line: | |
styles: style_line | |
align: center | |
points: | |
- 5, 5 | |
- 70, 70 | |
- 120, 10 | |
- 180, 60 | |
- 240, 10 | |
- obj: | |
width: size_content | |
height: size_content | |
widgets: | |
- btnmatrix: | |
align: BOTTOM_MID | |
items: | |
disabled: | |
bg_color: 0x00FFFF | |
align: center | |
id: keypad_matrix | |
disabled: | |
bg_color: 0x00FF00 | |
rows: | |
- buttons: | |
- text: 1 | |
key_code: "1" | |
- text: 2 | |
key_code: "2" | |
- text: 3 | |
- buttons: | |
- text: 4 | |
- text: 5 | |
- text: 6 | |
key_code: 0x36 | |
- buttons: | |
- text: 7 | |
- text: 8 | |
- text: 9 | |
- buttons: | |
- text: ${backspace} | |
key_code: "*" | |
- text: 0 | |
- text: ${check} | |
key_code: '#' | |
- label: | |
text_align: center | |
height: 100 | |
id: pin_code | |
align: TOP_MID | |
- img: | |
x: 10 | |
y: 200 | |
src: cat_image | |
id: img_id | |
radius: 11 | |
clip_corner: true | |
- label: | |
id: lbl_cathome | |
align_to: | |
id: img_id | |
x: 0 | |
y: 10 | |
align: OUT_BOTTOM_MID | |
text: 'Home' | |
text_color: 0x00FF00 | |
- btn: | |
x: 100 | |
y: 200 | |
widgets: | |
- label: | |
text: Disable keypad | |
on_press: | |
then: | |
- lvgl.btnmatrix.update: | |
id: keypad_matrix | |
state: | |
disabled: true | |
items: | |
bg_color: 0x0000ff | |
- lvgl.spinner.update: | |
id: spinner_id | |
indicator: | |
arc_color: 0x0000FF | |
- btn: | |
x: 100 | |
y: 240 | |
widgets: | |
- label: | |
text: Enable keypad | |
on_press: | |
then: | |
- lvgl.btnmatrix.update: | |
id: keypad_matrix | |
state: | |
disabled: false | |
items: | |
bg_color: 0xf0f0f0 | |
- spinner: | |
id: spinner_id | |
indicator: | |
arc_color: 0xF000FF | |
x: 200 | |
y: 400 | |
height: 100 | |
width: 100 | |
spin_time: 2s | |
arc_length: 60deg | |
- id: page_3 | |
layout: flex | |
widgets: | |
- obj: | |
scrollbar_mode: "off" | |
pad_all: 0 | |
width: 230 | |
max_width: 230 | |
height: 40 | |
bg_opa: 0 | |
border_width: 1 | |
widgets: | |
- checkbox: | |
id: chk_stat_6 | |
text: "Pretty long blah blah blah to go wider than obj width" | |
x: 5 | |
y: 5 | |
key_collector: | |
- id: pincode_reader | |
source_id: keypad_matrix | |
min_length: 4 | |
max_length: 4 | |
end_keys: "#" | |
end_key_required: true | |
back_keys: "*" | |
allowed_keys: "0123456789S" | |
timeout: 10s | |
on_progress: | |
- lvgl.label.update: | |
id: pin_code | |
text: !lambda 'return x.c_str();' | |
border_color: 0 | |
- logger.log: | |
format: "input progress: '%s', started by '%c'" | |
args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] | |
on_result: | |
- logger.log: | |
format: "input result: '%s', started by '%c', ended by '%c'" | |
args: [ 'x.c_str()', "(start == 0 ? '~' : start)", "(end == 0 ? '~' : end)" ] | |
- lambda: id(text_sensor).publish_state(x); | |
on_timeout: | |
- logger.log: | |
format: "input timeout: '%s', started by '%c'" | |
args: [ 'x.c_str()', "(start == 0 ? '~' : start)" ] | |
text: | |
- platform: template | |
id: text_sensor | |
name: "Template text" | |
optimistic: true | |
#min_length: 0 | |
#max_length: 100 | |
mode: text | |
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
And just wanted to thank you again! - this LVGL component is revolutionary for ESPhome..
Nice! Swipes and other gestures are likely to come, plenty of other stuff to do yet.
I build this with modified versions of the LVGL compoennt (and a modified display driver):
Check https://www.youtube.com/shorts/McAPOdtXWlw and https://youtu.be/RJwAdNKXpX8?si=0WGuvMw0ej2FJtB9&t=57
I am more then happy to help if you like. My work was mostly around optimizing Touch-interfacing icm LVGL, and framerate optimizations to make LVGL lightning fast.
Totally perfect for rich touchscreen interfaces with all it's bells and whisles, swiped, onscreen-keyboards etc.
PRs are welcome. Raise against my LVGL branch: https://github.com/clydebarrow/esphome/tree/lvgl
First, thanks for all the work you have done to port LVGL to ESPHome.
Is there a way to test the LVGL YAML code in a PC simulator?
It would be great to be able to develop the code and see the result easily without having to flash the ESP32.
https://docs.lvgl.io/8.2/get-started/pc-simulator.html
Thanks for your help
You can use the host
platform and SDL display driver. See https://esphome.io/components/display/sdl
You can use the
host
platform and SDL display driver. See https://esphome.io/components/display/sdl
Thank you very much, this works perfectly.
Could you help me how you set this up?
I'm trying to do it on MacOS but I'm failing.
Thanks
Hello @clydebarrow , I have a question. I'd like to update the screen while doing OTAs, but I wasn't able to do so. Is it possible at all?
ota:
- platform: esphome
password: "xxxxxxx"
on_begin:
then:
- logger.log: "OTA start a"
- lvgl.widget.hide: root
- lvgl.widget.show: popup_obj
- lvgl.resume:
- lvgl.widget.redraw:
- logger.log: "OTA start b"
on_progress:
then:
- lvgl.bar.update:
id: popup_pb_percentage
value:
50
- lvgl.label.update:
id: popup_lbl_percentage
text:
format: "%0.1f %%"
args: ["x"]
- logger.log:
format: "OTA progress %0.1f%%"
args: ["x"]
- lvgl.resume:
- lvgl.widget.redraw:
lvgl:
buffer_size: 25%
displays:
- main_tft
touchscreens:
- main_ts
on_idle:
- timeout: 10s
then:
- logger.log: idle timeout
- if:
condition:
lvgl.is_idle:
timeout: 5s
then:
- logger.log: LVGL is idle
- timeout: 15s
then:
- logger.log: idle 15s timeout
disp_bg_image: disp_bg
style_definitions:
- id: date_style
text_font: roboto10
align: center
text_color: 0x000000
bg_opa: cover
radius: 4
pad_all: 2
widgets:
- obj:
id: popup_obj
hidden: true
clickable: false
x: 0
y: 0
width: 100%
height: 100%
pad_all: 10
bg_opa: cover
widgets:
- label:
id: lbl_popup_title
x: 2
y: 2
text: "OTA in progress"
- label:
id: popup_lbl_percentage
x: 2
y: 30
width: 100%
text: "0 %"
- bar:
id: popup_pb_percentage
x: 2
y: 60
width: 100%
height: 10
max_value: 100
min_value: 0
value: 0
- obj: # Clock container
id: root
height: 170
width: 170
align: left_mid
pad_all: 4
bg_opa: 0.5
widgets:
[....]
I see the logger loggin the % of the OTA, but the screen never changes what's shown. I'm using your clock example as a basis.
The normal loop()
calls don't happen during OTA, so the display is not updated. Something like this should work:
ota:
platform: esphome
password: !secret ota_password
on_progress:
then:
- lvgl.bar.update:
id: lv_bar
value: !lambda "return (int)x;"
- lambda: "id(lv_id).loop();"
Where lv_id
is the ID of your lvgl component.
I build this with modified versions of the LVGL compoennt (and a modified display driver):
Check https://www.youtube.com/shorts/McAPOdtXWlw and https://youtu.be/RJwAdNKXpX8?si=0WGuvMw0ej2FJtB9&t=57
I am more then happy to help if you like. My work was mostly around optimizing Touch-interfacing icm LVGL, and framerate optimizations to make LVGL lightning fast.
Totally perfect for rich touchscreen interfaces with all it's bells and whisles, swiped, onscreen-keyboards etc.
Would you mind sharing your code for swiping with the touchscreen? I tried for several hours but I can't get it working..
Would you mind sharing your code for swiping with the touchscreen? I tried for several hours but I can't get it working..
Sure: https://github.com/expaso/ESPHome.Components.T-Display-S3
and https://github.com/expaso/ESPHome.Components.ESPHome-GUI
It could be that the displaybuffer implementations are no longer compatible with the latest versions of ESPHome, because they made a few breaking changes so PR's are welcome ;)
Nowadays I saw there were a lot of changes around the GUI component, but I mainly use the GUI component to bootstrap LVGL, and bind the display and touchscreen together. The GUI component will make sure that LVGL receives the touch events from the touchscreen.
Basically, with this setup you let LVGL do drawing directly in a double-buffer, and could still draw in the displaybuffer yourself (for any reason).
The performance of this solution relies on 2 parts:
1- I use a separate thread on a separate cpu-core to push the buffer to the display, so the main CPU can do other stuff
2- I only push the changed regions to the display, ant not full frames.
This is pseudo-code for how I wired these components up in YAML:
# For inclusion of all the LVGL C-files I exported from Squareline Studio
esphome:
includes:
- ../GUI_Export/
- ../GUI_Export/ui_main.h
on_boot:
- priority: 399 #Set boot prio as low as possible, so the UI will come up quick
then:
#Call some own LVGL C-functions to play startup animations and let the backlight easy-in
- lambda: |-
id(backlight)->turn_on().set_transition_length(700).perform();
ui_init(); //Initialize the UI
esphome::tactile_gloves::ui::ui_start();
- delay: 5000ms
- lambda: |-
esphome::tactile_gloves::ui::ui_finish_start();
#To import the forked ESPHomeGUI Repo
external_components:
- source:
type: local
path: ../ExternalRepos/ESPHome.Components.ESPHome-GUI/esphome/components
components: [display, gui]
- source:
type: local
path: ../ExternalRepos/ESPHome.Components.T-Display-S3/components/
components: [tdisplays3]
# LVGL Gui attached to the display and the touchscreen
gui:
id: ui
display_id: disp
touchscreen_id: touchscr
# items:
# - type: label
# id: mylabel
# position: 2, 2
# dimensions: 50x50
# I2C
i2c:
scl: 17
sda: 18
# Lights
light:
- platform: monochromatic
id: backlight
output: gpio38
name: "Backlight"
internal: true
restore_mode: ALWAYS_ON
# Display
display:
- platform: tdisplays3
id: disp
#update_interval: 2s
update_interval: never
auto_clear_enabled: false
rotation: 270
use_async_io: true
disable_buffer: true
# lambda: |-
# it.printf(20, 70, id(roboto), Color(255, 0, 0), id(ha_time).now().strftime("%y-%m-%d %h:%m:%s").c_str());
touchscreen:
- platform: tdisplays3
interrupt_pin: GPIO16
reset_pin: GPIO21
address: 0x15
# The T-Display S3 has a round button below the screen.
# With the current rotation (270°), touching this button produces a
# negative coordinate (-40), which is cannot be used in ESPHome for a
# touch point.
# Adding an offset moves *all* points by that offset, allowing to use
# the button in this rotation as well.
# Rotation 180° would need an y offset instead; this is also supported.
#x_offset: 40
id: touchscr
on_touch:
- lambda: |-
ESP_LOGI("touchscreen", "x:%d, y:%d",
id(touchscr).x,
id(touchscr).y
);
@clydebarrow
Your work on this is fantastic and hugely appreciated. My now much easier to work with configuration on an S3 Box 3 was actually fun to figure out and now much easier to maintain. Thank you!
Two quick questions:
-
I've got a complex "Settings" page using a tabview with the tabs on the left side. I also have a header included in the top_layer. It took a while to get things lined up so that the tabview started after the header, but I was successful. However there is a "bar" (currently black, though that's likely from my bg_color) that I can't seem to get rid of no matter how I style the different parts. The tab buttons go all the way to the bottom of the section, but the tab pages have that black bar and force scrolling. Any ideas what I might be missing between the page, obj, and tabview components that might cause that?
-
I noticed that many of the LVGL widgets support being a platform for other components, e.g. an LVGL switch can be automatically tied to an ESPHome switch using the LVGL platform. This looks like it would make keeping them in sync much easier and less YAML than having all the actions update back and forth manually. However I can't see a way to store and restore values for LVGL platform entities. Did a quick test and the values reset on reboot on a couple. Am I missing anything here, or does this currently not support stored/restored values? If not, I'd love to see that as a future enhancement since it would simplify things significantly!
In case helpful, the config I'm working on for both questions can be found here:
https://github.com/raetha/esphome-configs/blob/main/esp32s3box3/config.yaml
Thanks again for all your work on the LVGL stuff and providing some great examples. This stuff is awesome!
Ooooh this example is amazing!! I hope this is linked to from the final documentation for this component :) I've got my power meter display in a mostly functional state :) just added multiple pages after finding this example. I just set it to change to the next page upon any touchscreen touch. Is there a way to detect swipes and have the pages swipe left right? not actually necessary would just look cool..
