mirror of
https://github.com/randybb/esphome-configs.git
synced 2026-10-14 08:35:12 +02:00
TFT: switch to LVGL, add XPT2046 touch
This commit is contained in:
1 parent
6ca813fb64
commit
b523963944
1 file changed
+222
-125
+222
-125
@@ -10,9 +10,10 @@ esphome:
|
|||||||
friendly_name: ${name}
|
friendly_name: ${name}
|
||||||
area: ${area}
|
area: ${area}
|
||||||
comment: ${comment}
|
comment: ${comment}
|
||||||
platformio_options:
|
on_boot:
|
||||||
board_build.flash_mode: dio
|
- priority: -100
|
||||||
|
then:
|
||||||
|
- lvgl.page.show: status_page
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
variant: esp32c3
|
variant: esp32c3
|
||||||
@@ -23,39 +24,118 @@ packages:
|
|||||||
common: !include common/common.yaml
|
common: !include common/common.yaml
|
||||||
ipv6_only: !include common/ipv6_only.yaml
|
ipv6_only: !include common/ipv6_only.yaml
|
||||||
|
|
||||||
logger:
|
api:
|
||||||
logs:
|
# status page until Home Assistant connects (log viewers don't subscribe to states)
|
||||||
component: ERROR
|
on_client_connected:
|
||||||
|
- delay: 2s
|
||||||
# GPIO1 UART TX
|
- if:
|
||||||
# GPIO3 UART RX
|
condition:
|
||||||
# GPIO4 I2C SDA
|
api.connected:
|
||||||
# GPIO5 I2C SCL
|
state_subscription_only: true
|
||||||
# GPIO12 DISPLAY DIO
|
then:
|
||||||
# GPIO12 DISPLAY CLOCK
|
- lvgl.page.show: main_page
|
||||||
# GPIO14 BUZZER
|
on_client_disconnected:
|
||||||
# GPIO16 RGB
|
- if:
|
||||||
|
condition:
|
||||||
|
not:
|
||||||
|
api.connected:
|
||||||
|
state_subscription_only: true
|
||||||
|
then:
|
||||||
|
- lvgl.page.show: status_page
|
||||||
|
|
||||||
spi:
|
spi:
|
||||||
clk_pin: 4
|
clk_pin: 4
|
||||||
mosi_pin: 5
|
mosi_pin: 5
|
||||||
miso_pin: 6
|
miso_pin: 6
|
||||||
|
|
||||||
color:
|
display:
|
||||||
- id: my_green
|
- platform: mipi_spi
|
||||||
hex: 00ff00
|
id: main_display
|
||||||
- id: my_magenta
|
model: ILI9341
|
||||||
hex: ff00ff
|
cs_pin: 7
|
||||||
- id: my_red
|
dc_pin: 8
|
||||||
hex: ff0000
|
reset_pin: 10
|
||||||
- id: my_white
|
invert_colors: false
|
||||||
hex: ffffff
|
data_rate: 40MHz
|
||||||
- id: status_ok
|
update_interval: never
|
||||||
hex: 4dd966
|
auto_clear_enabled: false
|
||||||
- id: status_wait
|
|
||||||
hex: ffb300
|
touchscreen:
|
||||||
- id: status_dim
|
- platform: xpt2046
|
||||||
hex: 8c8c8c
|
display: main_display
|
||||||
|
cs_pin: 0
|
||||||
|
interrupt_pin: 1
|
||||||
|
transform:
|
||||||
|
mirror_x: true
|
||||||
|
calibration:
|
||||||
|
x_min: 330
|
||||||
|
x_max: 3620
|
||||||
|
y_min: 230
|
||||||
|
y_max: 3680
|
||||||
|
|
||||||
|
script:
|
||||||
|
- id: update_status
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
// same colors as the other status screens: ok green, waiting orange, details gray
|
||||||
|
static const uint32_t OK = 0x4DD966, WAIT = 0xFFB300;
|
||||||
|
auto set = [](lv_obj_t *label, const std::string &text, uint32_t color) {
|
||||||
|
lv_label_set_text(label, text.c_str());
|
||||||
|
lv_obj_set_style_text_color(label, lv_color_hex(color), LV_PART_MAIN);
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool wifi_ok = wifi::global_wifi_component->is_connected();
|
||||||
|
set(id(status_wifi),
|
||||||
|
wifi_ok ? str_sprintf("WiFi: connected (%d dBm)", wifi::global_wifi_component->wifi_rssi())
|
||||||
|
: std::string("WiFi: connecting..."),
|
||||||
|
wifi_ok ? OK : WAIT);
|
||||||
|
|
||||||
|
// IPv6 first (skip link-local), then IPv4
|
||||||
|
std::string ips;
|
||||||
|
if (wifi_ok) {
|
||||||
|
char buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||||
|
for (bool v6 : {true, false}) {
|
||||||
|
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
|
||||||
|
if (!ip.is_set() || ip.is_ip6() != v6)
|
||||||
|
continue;
|
||||||
|
ip.str_to(buf);
|
||||||
|
if (v6 && strncmp(buf, "fe80", 4) == 0)
|
||||||
|
continue;
|
||||||
|
if (!ips.empty())
|
||||||
|
ips += "\n";
|
||||||
|
ips += buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lv_label_set_text(id(status_ips), ips.c_str());
|
||||||
|
if (ips.empty())
|
||||||
|
lv_obj_add_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
|
||||||
|
else
|
||||||
|
lv_obj_remove_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
|
const bool api_ok = api::global_api_server->is_connected();
|
||||||
|
set(id(status_ha), api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...",
|
||||||
|
api_ok ? OK : WAIT);
|
||||||
|
|
||||||
|
const uint32_t up = millis() / 1000;
|
||||||
|
lv_label_set_text(id(status_footer),
|
||||||
|
str_sprintf("ESPHome %s\nup %ud %02u:%02u:%02u", ESPHOME_VERSION, up / 86400,
|
||||||
|
(up / 3600) % 24, (up / 60) % 60, up % 60).c_str());
|
||||||
|
interval:
|
||||||
|
- interval: 1s
|
||||||
|
then:
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: clock_label
|
||||||
|
text: !lambda |-
|
||||||
|
auto now = id(ha_time).now();
|
||||||
|
if (!now.is_valid())
|
||||||
|
return std::string("--:--");
|
||||||
|
return now.strftime("%H:%M");
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lvgl.page.is_showing: status_page
|
||||||
|
then:
|
||||||
|
- script.execute: update_status
|
||||||
|
|
||||||
image:
|
image:
|
||||||
- platform: file
|
- platform: file
|
||||||
@@ -66,103 +146,120 @@ image:
|
|||||||
transparency: alpha_channel
|
transparency: alpha_channel
|
||||||
|
|
||||||
font:
|
font:
|
||||||
|
- file: "gfonts://Roboto@500"
|
||||||
|
id: font_clock
|
||||||
|
size: 80
|
||||||
|
glyphs: "0123456789:-"
|
||||||
- file: "gfonts://Roboto"
|
- file: "gfonts://Roboto"
|
||||||
id: font_default
|
id: font_title
|
||||||
size: 20
|
|
||||||
- file: "gfonts://B612"
|
|
||||||
id: b612_24
|
|
||||||
size: 24
|
|
||||||
- file: "gfonts://B612"
|
|
||||||
id: b612_16
|
|
||||||
size: 16
|
|
||||||
- file: "gfonts://B612"
|
|
||||||
id: b612_12
|
|
||||||
size: 12
|
|
||||||
- file: "gfonts://B612 Mono"
|
|
||||||
id: b612_24_mono
|
|
||||||
size: 24
|
|
||||||
- file: "gfonts://B612 Mono"
|
|
||||||
id: b612_16_mono
|
|
||||||
size: 16
|
|
||||||
- file: "gfonts://B612 Mono"
|
|
||||||
id: b612_12_mono
|
|
||||||
size: 12
|
|
||||||
- file: "gfonts://Roboto"
|
|
||||||
id: roboto_32
|
|
||||||
size: 32
|
|
||||||
- file: "gfonts://Roboto"
|
|
||||||
id: roboto_24
|
|
||||||
size: 24
|
size: 24
|
||||||
- file: "gfonts://Roboto"
|
- file: "gfonts://Roboto"
|
||||||
id: roboto_16
|
id: font_status
|
||||||
size: 16
|
size: 14
|
||||||
- file: "gfonts://Roboto"
|
|
||||||
id: roboto_12
|
|
||||||
size: 12
|
|
||||||
- file: "gfonts://Roboto Mono"
|
|
||||||
id: roboto_32_mono
|
|
||||||
size: 32
|
|
||||||
- file: "gfonts://Roboto Mono"
|
|
||||||
id: roboto_24_mono
|
|
||||||
size: 24
|
|
||||||
- file: "gfonts://Roboto Mono"
|
|
||||||
id: roboto_16_mono
|
|
||||||
size: 16
|
|
||||||
- file: "gfonts://Roboto Mono"
|
|
||||||
id: roboto_12_mono
|
|
||||||
size: 12
|
|
||||||
|
|
||||||
|
lvgl:
|
||||||
|
log_level: WARN
|
||||||
|
color_depth: 16
|
||||||
|
bg_color: 0x000000
|
||||||
|
text_color: 0xFFFFFF
|
||||||
|
theme:
|
||||||
|
button:
|
||||||
|
bg_color: 0x2B2F36
|
||||||
|
radius: 12
|
||||||
|
checked:
|
||||||
|
bg_color: 0xE08A00
|
||||||
|
buttonmatrix:
|
||||||
|
bg_opa: TRANSP
|
||||||
|
border_width: 0
|
||||||
|
items:
|
||||||
|
bg_color: 0x2B2F36
|
||||||
|
text_color: 0xFFFFFF
|
||||||
|
radius: 12
|
||||||
|
checked:
|
||||||
|
bg_color: 0xE08A00
|
||||||
|
top_layer:
|
||||||
|
widgets:
|
||||||
|
# same navigation bar as on the other LVGL displays
|
||||||
|
- buttonmatrix:
|
||||||
|
id: nav_bar
|
||||||
|
align: bottom_mid
|
||||||
|
width: 100%
|
||||||
|
height: 48
|
||||||
|
pad_all: 4
|
||||||
|
pad_column: 6
|
||||||
|
items:
|
||||||
|
text_font: montserrat_20
|
||||||
|
rows:
|
||||||
|
- buttons:
|
||||||
|
- id: page_prev
|
||||||
|
text: ""
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
lvgl.page.previous:
|
||||||
|
- id: page_home
|
||||||
|
text: ""
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
lvgl.page.show: main_page
|
||||||
|
- id: page_next
|
||||||
|
text: ""
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
lvgl.page.next:
|
||||||
|
pages:
|
||||||
|
# 1: clock
|
||||||
|
- id: main_page
|
||||||
|
widgets:
|
||||||
|
- label:
|
||||||
|
id: clock_label
|
||||||
|
align: CENTER
|
||||||
|
y: -24
|
||||||
|
text_font: font_clock
|
||||||
|
text: "--:--"
|
||||||
|
|
||||||
display:
|
# 2: status (shown until Home Assistant connects)
|
||||||
- platform: mipi_spi
|
- id: status_page
|
||||||
model: ILI9341
|
on_load:
|
||||||
cs_pin: 7
|
- script.execute: update_status
|
||||||
dc_pin: 8
|
widgets:
|
||||||
reset_pin: 10
|
- image:
|
||||||
invert_colors: false
|
src: esphome_logo
|
||||||
lambda: |-
|
align: TOP_MID
|
||||||
it.fill(Color::BLACK);
|
y: 8
|
||||||
|
- label:
|
||||||
// status screen until Home Assistant connects (240x320)
|
align: TOP_MID
|
||||||
if (!api::global_api_server->is_connected_with_state_subscription()) {
|
y: 78
|
||||||
const int cx = it.get_width() / 2;
|
text_font: font_title
|
||||||
it.image(cx, 48, id(esphome_logo), ImageAlign::CENTER);
|
text: "${name}"
|
||||||
it.print(cx, 100, id(roboto_24), id(my_white), TextAlign::CENTER, "${name}");
|
- obj:
|
||||||
|
x: 8
|
||||||
int y = 130;
|
y: 116
|
||||||
if (wifi::global_wifi_component->is_connected()) {
|
width: 224
|
||||||
it.printf(8, y, id(roboto_16), id(status_ok), "WiFi: connected (%d dBm)",
|
height: SIZE_CONTENT
|
||||||
wifi::global_wifi_component->wifi_rssi());
|
bg_opa: TRANSP
|
||||||
y += 22;
|
border_width: 0
|
||||||
// IPv6 first (skip link-local), then IPv4
|
pad_all: 0
|
||||||
char buf[network::IP_ADDRESS_BUFFER_SIZE];
|
scrollbar_mode: "OFF"
|
||||||
for (bool v6 : {true, false}) {
|
layout:
|
||||||
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
|
type: flex
|
||||||
if (!ip.is_set() || ip.is_ip6() != v6 || y > 200)
|
flex_flow: column
|
||||||
continue;
|
pad_row: 6
|
||||||
ip.str_to(buf);
|
widgets:
|
||||||
if (v6 && strncmp(buf, "fe80", 4) == 0)
|
- label:
|
||||||
continue;
|
id: status_wifi
|
||||||
it.print(8, y, id(roboto_12), id(status_dim), buf);
|
text_font: font_status
|
||||||
y += 16;
|
text: ""
|
||||||
}
|
- label:
|
||||||
}
|
id: status_ips
|
||||||
} else {
|
text_font: font_status
|
||||||
it.print(8, y, id(roboto_16), id(status_wait), "WiFi: connecting...");
|
text_color: 0x8C8C8C
|
||||||
y += 22;
|
text: ""
|
||||||
}
|
- label:
|
||||||
y += 8;
|
id: status_ha
|
||||||
it.print(8, y, id(roboto_16), api::global_api_server->is_connected() ? id(status_ok) : id(status_wait),
|
text_font: font_status
|
||||||
api::global_api_server->is_connected() ? "Home Assistant: connected" : "Home Assistant: waiting...");
|
text: ""
|
||||||
|
- label:
|
||||||
it.printf(8, it.get_height() - 8, id(roboto_12), id(status_dim), TextAlign::BOTTOM_LEFT, "ESPHome %s",
|
id: status_footer
|
||||||
ESPHOME_VERSION);
|
text_font: font_status
|
||||||
it.printf(it.get_width() - 8, it.get_height() - 8, id(roboto_12), id(status_dim), TextAlign::BOTTOM_RIGHT,
|
text_color: 0x8C8C8C
|
||||||
"up %us", (unsigned) (millis() / 1000));
|
text: ""
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
it.print(0, 0, id(b612_12), id(my_white), TextAlign::TOP_LEFT, "HELLO WORLD!");
|
|
||||||
it.print(0, 14, id(b612_12), id(my_green), TextAlign::TOP_LEFT, "HELLO WORLD!");
|
|
||||||
it.print(0, 28, id(b612_12), id(my_magenta), TextAlign::TOP_LEFT, "HELLO WORLD!");
|
|
||||||
it.print(0, 42, id(b612_12), id(my_red), TextAlign::TOP_LEFT, "HELLO WORLD!");
|
|
||||||
Reference in new issue
Block a user