While doing that I discovered a small bug. This display has a LDR sensor on the front to measure incoming light and thus be able to adjust backlighting. I added that as a sensor in the hardware receipt
I used this receipt and created a sketch presenting a text sensor as well as the wifi sensor. If I do that the generated code will include include two sensor: sections. See this example:
# ============================================================================
# ESPHome YAML - Generated by ESPHome Designer
# ============================================================================
# TARGET DEVICE: Guition ESP32-2.8-inch resistor touch
# - https://randomnerdtutorials.com/esp32-cheap-yellow-display-cyd-pinout-esp32-2432s028r/
# - ESP32: Sparkleiot XH-32S
# - Display Platform: 2.8-inch color TFT display screen with ILI9341 driver chip
# - PSRAM: None
# - Touchscreen: XPT2046
# - Framework: ESP-IDF
# Name: Guition ESP32-2.8-inch resistor touch 240x320
# Resolution: 240x320
# Shape: rectangle
# ============================================================================
#
# SETUP INSTRUCTIONS:
#
# STEP 1: Copy the Material Design Icons font file
# - From this repo: resources/fonts/materialdesignicons-webfont.ttf
# - To ESPHome: /config/esphome/fonts/materialdesignicons-webfont.ttf
# (Create the fonts folder if it doesn't exist)
#
# STEP 2: Create a new device in ESPHome
# - Click "New Device"
# - Name: your-device-name
# - Select: ESP32
# - Framework: ESP-IDF (Required for this device)
#
# STEP 3: REPLACE your entire YAML with this generated output
# (This profile includes full esphome: and esp32: sections)
#
# ============================================================================
# substitutions: # (Auto-commented)
# name: "guiton_esp32_2432s028r"
# friendly_name: 'Guition ESP32-2.8-inch" 2432S028 R'
# device_description: "Guition ESP32-2.8-inch resistor touch 240x320"
# project_name: "ESPHomeDesigner_Waveshare_Touch_Round_LCD_1.28"
# project_version: "1.0.0"
# #GPIO pins for the LCD screen
# misopin: GPIO12
# mosipin: GPIO13
# sclkpin: GPIO14
# cspin: GPIO15
# dcpin: GPIO2
# blpin: GPIO21
# # GPIO pins for Touchpanel
# tp_irqpin: GPIO36
# tp_mosipin: GPIO32
# tp_misopin: GPIO39
# tp_clkpin: GPIO25
# tp_cspin: GPIO33
# # GPIO pins for RGB LED
# led_rpin: GPIO4
# led_gpin: GPIO16
# led_bpin: GPIO17
# # GPIO LDR
# ldr_pin: GPIO34
# # GPIO pins for i2c
# sdapin: GPIO27
# sclpin: GPIO22
# # SD Card
# sd_cs_pin: GPIO4
# esphome: # (Auto-commented)
# friendly_name: $friendly_name
# name: $name
# project:
# name: "${project_name}"
# version: "${project_version}"
# esp32: # (Auto-commented)
# board: esp32dev
# framework:
# type: esp-idf
spi:
- id: tft
clk_pin: $sclkpin
mosi_pin: $mosipin
miso_pin:
number: $misopin
ignore_strapping_warning: true
- id: touch
clk_pin: $tp_clkpin
mosi_pin: $tp_mosipin
miso_pin: $tp_misopin
i2c:
sda: $sdapin
scl: $sclpin
output:
- platform: ledc
pin: $blpin
frequency: 1000hz
id: gpio_backlight_pwm
- id: output_red
platform: ledc
pin: $led_rpin
inverted: true
- id: output_green
platform: ledc
pin: $led_gpin
inverted: true
- id: output_blue
platform: ledc
pin: $led_bpin
inverted: true
light:
- platform: monochromatic # Define a monochromatic, dimmable light for the backlight
output: gpio_backlight_pwm
name: Display Backlight
icon: mdi:lightbulb-on
id: display_backlight
restore_mode: ALWAYS_ON
- platform: rgb # RGB Led on backside
id: rgb_led
name: RGB LED
red: output_red
green: output_green
blue: output_blue
restore_mode: ALWAYS_OFF
sensor:
# Board LDR
- platform: adc
pin: $ldr_pin
name: "board_ldr"
update_interval: 1500ms
touchscreen:
- id: my_touchscreen
platform: xpt2046
spi_id: touch
cs_pin: $tp_cspin
interrupt_pin: $tp_irqpin
threshold: 400
calibration:
x_min: 280
x_max: 3860
y_min: 340
y_max: 3860
transform:
mirror_x: true
on_touch:
- lambda: |-
ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
touch.x,
touch.y,
touch.x_raw,
touch.y_raw
);
display:
- id: my_display
platform: ili9xxx
model: ILI9342
spi_id: tft
cs_pin:
number: $cspin
ignore_strapping_warning: true
dc_pin:
number: $dcpin
ignore_strapping_warning: true
invert_colors: false
update_interval: never
auto_clear_enabled: false
color_order: RGB
dimensions:
width: 240
height: 320
lambda: |-
const auto COLOR_WHITE = Color(255, 255, 255);
const auto COLOR_BLACK = Color(0, 0, 0);
const auto COLOR_RED = Color(255, 0, 0);
const auto COLOR_GREEN = Color(0, 255, 0);
const auto COLOR_BLUE = Color(0, 0, 255);
const auto COLOR_YELLOW = Color(255, 255, 0);
const auto COLOR_ORANGE = Color(255, 165, 0);
auto color_off = COLOR_WHITE;
auto color_on = COLOR_BLACK;
// Helper to apply a simple grey dither mask for e-paper (checkerboard)
auto apply_grey_dither_mask = [&](int x_start, int y_start, int w, int h, int r = 0) {
for (int y = y_start; y < y_start + h; y++) {
for (int x = x_start; x < x_start + w; x++) {
if (r > 0) {
int dx = 0, dy = 0;
if (x < x_start + r && y < y_start + r) { dx = x_start + r - x; dy = y_start + r - y; }
else if (x >= x_start + w - r && y < y_start + r) { dx = x - (x_start + w - r - 1); dy = y_start + r - y; }
else if (x < x_start + r && y >= y_start + h - r) { dx = x_start + r - x; dy = y - (y_start + h - r - 1); }
else if (x >= x_start + w - r && y >= y_start + h - r) { dx = x - (x_start + w - r - 1); dy = y - (y_start + h - r - 1); }
if (dx*dx + dy*dy > r*r) continue;
}
if ((x + y) % 2 == 0) it.draw_pixel_at(x, y, COLOR_WHITE);
else it.draw_pixel_at(x, y, COLOR_BLACK);
}
}
};
// Helper to apply grey dither to text (subtractive - erases every other black pixel)
auto apply_grey_dither_to_text = [&](int x_start, int y_start, int w, int h) {
for (int y = y_start; y < y_start + h; y++) {
for (int x = x_start; x < x_start + w; x++) {
if ((x + y) % 2 == 0) it.draw_pixel_at(x, y, COLOR_WHITE);
}
}
};
int currentPage = id(display_page);
if (currentPage == 0) {
// page:name "Page 1"
// page:dark_mode "inherit"
// page:refresh_type "interval"
// page:refresh_time ""
// Clear screen for this page
it.fill(COLOR_WHITE);
color_off = COLOR_WHITE;
color_on = COLOR_BLACK;
// widget:text id:w_mkzz2oupe6tj1 type:text x:60 y:74 w:120 h:40 text:"Welcome!"
it.printf(120, 94, id(font_roboto_400_20), COLOR_BLACK, TextAlign::CENTER, "Welcome!");
// widget:icon id:w_mkzz2sr1a20u2 type:icon x:71 y:114 w:98 h:93 code:F07D0 size:85 color:#00BCF7
it.printf(71, 114, id(font_material_design_icons_400_85), Color(0, 188, 247), "%s", "\U000F07D0");
// widget:wifi_signal id:w_mkzz3ql00s8t3 type:wifi_signal x:60 y:11 w:120 h:40 entity:wifi_signal_dbm size:24 font_size:12 color:#00B700 show_dbm:true local:true
{
const char* wifi_icon = "\U000F092B"; // Default: wifi-strength-alert-outline
if (id(wifi_signal_dbm).has_state()) {
float signal = id(wifi_signal_dbm).state;
if (std::isnan(signal)) signal = -100;
if (signal >= -50) wifi_icon = "\U000F0928"; // wifi-strength-4 (Excellent)
else if (signal >= -60) wifi_icon = "\U000F0925"; // wifi-strength-3 (Good)
else if (signal >= -75) wifi_icon = "\U000F0922"; // wifi-strength-2 (Fair)
else if (signal >= -100) wifi_icon = "\U000F091F"; // wifi-strength-1 (Weak)
else wifi_icon = "\U000F092B"; // wifi-strength-alert-outline
}
it.printf(60 + 120 / 2, 11 + (40 - 38) / 2, id(font_material_design_icons_400_24), Color(0, 183, 0), TextAlign::TOP_CENTER, "%s", wifi_icon);
if (id(wifi_signal_dbm).has_state()) {
it.printf(60 + 120 / 2, 11 + (40 - 38) / 2 + 24 + 2, id(font_roboto_400_12), Color(0, 183, 0), TextAlign::TOP_CENTER, "%.0fdB", id(wifi_signal_dbm).state);
}
}
// widget:sensor_text id:w_mkzz3yp9i02sx type:sensor_text x:60 y:237 w:120 h:40 entity:"sensor.medeltemperatur_pa_oppna_delar_av_entreplan" format:"label_newline_value"
it.printf(120, 237, id(font_roboto_400_14), COLOR_BLACK, TextAlign::TOP_CENTER, "Temperatur");
it.printf(120, 237 + 18, id(font_roboto_400_20), COLOR_BLACK, TextAlign::TOP_CENTER, "%.1f °C", id(sensor_medeltemperatur_pa_oppna_delar_av_entreplan).state);
}
globals:
- id: display_page
type: int
restore_value: true
initial_value: '0'
- id: page_refresh_default_s
type: int
restore_value: true
initial_value: '600'
- id: page_refresh_current_s
type: int
restore_value: false
initial_value: '60'
- id: last_page_switch_time
type: uint32_t
restore_value: false
initial_value: '0'
psram:
time:
- platform: homeassistant
id: ha_time
sensor:
- platform: homeassistant
id: sensor_medeltemperatur_pa_oppna_delar_av_entreplan
entity_id: sensor.medeltemperatur_pa_oppna_delar_av_entreplan
internal: true
- platform: wifi_signal
name: "WiFi Signal"
id: wifi_signal_dbm
update_interval: 60s
font:
- file:
type: gfonts
family: "Roboto"
weight: 400
italic: false
id: font_roboto_400_12
size: 12
glyphs: ["\U00000020", "\U00000021", "\U00000022", "\U00000023", "\U00000024", "\U00000025", "\U00000026", "\U00000027", "\U00000028", "\U00000029", "\U0000002A", "\U0000002B", "\U0000002C", "\U0000002D", "\U0000002E", "\U0000002F", "\U00000030", "\U00000031", "\U00000032", "\U00000033", "\U00000034", "\U00000035", "\U00000036", "\U00000037", "\U00000038", "\U00000039", "\U0000003A", "\U0000003B", "\U0000003C", "\U0000003D", "\U0000003E", "\U0000003F", "\U00000040", "\U00000041", "\U00000042", "\U00000043", "\U00000044", "\U00000045", "\U00000046", "\U00000047", "\U00000048", "\U00000049", "\U0000004A", "\U0000004B", "\U0000004C", "\U0000004D", "\U0000004E", "\U0000004F", "\U00000050", "\U00000051", "\U00000052", "\U00000053", "\U00000054", "\U00000055", "\U00000056", "\U00000057", "\U00000058", "\U00000059", "\U0000005A", "\U0000005B", "\U0000005C", "\U0000005D", "\U0000005E", "\U0000005F", "\U00000060", "\U00000061", "\U00000062", "\U00000063", "\U00000064", "\U00000065", "\U00000066", "\U00000067", "\U00000068", "\U00000069", "\U0000006A", "\U0000006B", "\U0000006C", "\U0000006D", "\U0000006E", "\U0000006F", "\U00000070", "\U00000071", "\U00000072", "\U00000073", "\U00000074", "\U00000075", "\U00000076", "\U00000077", "\U00000078", "\U00000079", "\U0000007A", "\U0000007B", "\U0000007C", "\U0000007D", "\U0000007E", "\U000000A0", "\U000000A1", "\U000000A2", "\U000000A3", "\U000000A4", "\U000000A5", "\U000000A6", "\U000000A7", "\U000000A8", "\U000000A9", "\U000000AA", "\U000000AB", "\U000000AC", "\U000000AD", "\U000000AE", "\U000000AF", "\U000000B0", "\U000000B1", "\U000000B2", "\U000000B3", "\U000000B4", "\U000000B5", "\U000000B6", "\U000000B7", "\U000000B8", "\U000000B9", "\U000000BA", "\U000000BB", "\U000000BC", "\U000000BD", "\U000000BE", "\U000000BF", "\U000000C0", "\U000000C1", "\U000000C2", "\U000000C3", "\U000000C4", "\U000000C5", "\U000000C6", "\U000000C7", "\U000000C8", "\U000000C9", "\U000000CA", "\U000000CB", "\U000000CC", "\U000000CD", "\U000000CE", "\U000000CF", "\U000000D0", "\U000000D1", "\U000000D2", "\U000000D3", "\U000000D4", "\U000000D5", "\U000000D6", "\U000000D7", "\U000000D8", "\U000000D9", "\U000000DA", "\U000000DB", "\U000000DC", "\U000000DD", "\U000000DE", "\U000000DF", "\U000000E0", "\U000000E1", "\U000000E2", "\U000000E3", "\U000000E4", "\U000000E5", "\U000000E6", "\U000000E7", "\U000000E8", "\U000000E9", "\U000000EA", "\U000000EB", "\U000000EC", "\U000000ED", "\U000000EE", "\U000000EF", "\U000000F0", "\U000000F1", "\U000000F2", "\U000000F3", "\U000000F4", "\U000000F5", "\U000000F6", "\U000000F7", "\U000000F8", "\U000000F9", "\U000000FA", "\U000000FB", "\U000000FC", "\U000000FD", "\U000000FE", "\U000000FF", "\U000003BC", "\U000003A9", "\U000020AC", "\U00002122"]
- file:
type: gfonts
family: "Roboto"
weight: 400
italic: false
id: font_roboto_400_14
size: 14
glyphs: ["\U00000020", "\U00000021", "\U00000022", "\U00000023", "\U00000024", "\U00000025", "\U00000026", "\U00000027", "\U00000028", "\U00000029", "\U0000002A", "\U0000002B", "\U0000002C", "\U0000002D", "\U0000002E", "\U0000002F", "\U00000030", "\U00000031", "\U00000032", "\U00000033", "\U00000034", "\U00000035", "\U00000036", "\U00000037", "\U00000038", "\U00000039", "\U0000003A", "\U0000003B", "\U0000003C", "\U0000003D", "\U0000003E", "\U0000003F", "\U00000040", "\U00000041", "\U00000042", "\U00000043", "\U00000044", "\U00000045", "\U00000046", "\U00000047", "\U00000048", "\U00000049", "\U0000004A", "\U0000004B", "\U0000004C", "\U0000004D", "\U0000004E", "\U0000004F", "\U00000050", "\U00000051", "\U00000052", "\U00000053", "\U00000054", "\U00000055", "\U00000056", "\U00000057", "\U00000058", "\U00000059", "\U0000005A", "\U0000005B", "\U0000005C", "\U0000005D", "\U0000005E", "\U0000005F", "\U00000060", "\U00000061", "\U00000062", "\U00000063", "\U00000064", "\U00000065", "\U00000066", "\U00000067", "\U00000068", "\U00000069", "\U0000006A", "\U0000006B", "\U0000006C", "\U0000006D", "\U0000006E", "\U0000006F", "\U00000070", "\U00000071", "\U00000072", "\U00000073", "\U00000074", "\U00000075", "\U00000076", "\U00000077", "\U00000078", "\U00000079", "\U0000007A", "\U0000007B", "\U0000007C", "\U0000007D", "\U0000007E", "\U000000A0", "\U000000A1", "\U000000A2", "\U000000A3", "\U000000A4", "\U000000A5", "\U000000A6", "\U000000A7", "\U000000A8", "\U000000A9", "\U000000AA", "\U000000AB", "\U000000AC", "\U000000AD", "\U000000AE", "\U000000AF", "\U000000B0", "\U000000B1", "\U000000B2", "\U000000B3", "\U000000B4", "\U000000B5", "\U000000B6", "\U000000B7", "\U000000B8", "\U000000B9", "\U000000BA", "\U000000BB", "\U000000BC", "\U000000BD", "\U000000BE", "\U000000BF", "\U000000C0", "\U000000C1", "\U000000C2", "\U000000C3", "\U000000C4", "\U000000C5", "\U000000C6", "\U000000C7", "\U000000C8", "\U000000C9", "\U000000CA", "\U000000CB", "\U000000CC", "\U000000CD", "\U000000CE", "\U000000CF", "\U000000D0", "\U000000D1", "\U000000D2", "\U000000D3", "\U000000D4", "\U000000D5", "\U000000D6", "\U000000D7", "\U000000D8", "\U000000D9", "\U000000DA", "\U000000DB", "\U000000DC", "\U000000DD", "\U000000DE", "\U000000DF", "\U000000E0", "\U000000E1", "\U000000E2", "\U000000E3", "\U000000E4", "\U000000E5", "\U000000E6", "\U000000E7", "\U000000E8", "\U000000E9", "\U000000EA", "\U000000EB", "\U000000EC", "\U000000ED", "\U000000EE", "\U000000EF", "\U000000F0", "\U000000F1", "\U000000F2", "\U000000F3", "\U000000F4", "\U000000F5", "\U000000F6", "\U000000F7", "\U000000F8", "\U000000F9", "\U000000FA", "\U000000FB", "\U000000FC", "\U000000FD", "\U000000FE", "\U000000FF", "\U000003BC", "\U000003A9", "\U000020AC", "\U00002122"]
- file:
type: gfonts
family: "Roboto"
weight: 400
italic: false
id: font_roboto_400_20
size: 20
glyphs: ["\U00000020", "\U00000021", "\U00000022", "\U00000023", "\U00000024", "\U00000025", "\U00000026", "\U00000027", "\U00000028", "\U00000029", "\U0000002A", "\U0000002B", "\U0000002C", "\U0000002D", "\U0000002E", "\U0000002F", "\U00000030", "\U00000031", "\U00000032", "\U00000033", "\U00000034", "\U00000035", "\U00000036", "\U00000037", "\U00000038", "\U00000039", "\U0000003A", "\U0000003B", "\U0000003C", "\U0000003D", "\U0000003E", "\U0000003F", "\U00000040", "\U00000041", "\U00000042", "\U00000043", "\U00000044", "\U00000045", "\U00000046", "\U00000047", "\U00000048", "\U00000049", "\U0000004A", "\U0000004B", "\U0000004C", "\U0000004D", "\U0000004E", "\U0000004F", "\U00000050", "\U00000051", "\U00000052", "\U00000053", "\U00000054", "\U00000055", "\U00000056", "\U00000057", "\U00000058", "\U00000059", "\U0000005A", "\U0000005B", "\U0000005C", "\U0000005D", "\U0000005E", "\U0000005F", "\U00000060", "\U00000061", "\U00000062", "\U00000063", "\U00000064", "\U00000065", "\U00000066", "\U00000067", "\U00000068", "\U00000069", "\U0000006A", "\U0000006B", "\U0000006C", "\U0000006D", "\U0000006E", "\U0000006F", "\U00000070", "\U00000071", "\U00000072", "\U00000073", "\U00000074", "\U00000075", "\U00000076", "\U00000077", "\U00000078", "\U00000079", "\U0000007A", "\U0000007B", "\U0000007C", "\U0000007D", "\U0000007E", "\U000000A0", "\U000000A1", "\U000000A2", "\U000000A3", "\U000000A4", "\U000000A5", "\U000000A6", "\U000000A7", "\U000000A8", "\U000000A9", "\U000000AA", "\U000000AB", "\U000000AC", "\U000000AD", "\U000000AE", "\U000000AF", "\U000000B0", "\U000000B1", "\U000000B2", "\U000000B3", "\U000000B4", "\U000000B5", "\U000000B6", "\U000000B7", "\U000000B8", "\U000000B9", "\U000000BA", "\U000000BB", "\U000000BC", "\U000000BD", "\U000000BE", "\U000000BF", "\U000000C0", "\U000000C1", "\U000000C2", "\U000000C3", "\U000000C4", "\U000000C5", "\U000000C6", "\U000000C7", "\U000000C8", "\U000000C9", "\U000000CA", "\U000000CB", "\U000000CC", "\U000000CD", "\U000000CE", "\U000000CF", "\U000000D0", "\U000000D1", "\U000000D2", "\U000000D3", "\U000000D4", "\U000000D5", "\U000000D6", "\U000000D7", "\U000000D8", "\U000000D9", "\U000000DA", "\U000000DB", "\U000000DC", "\U000000DD", "\U000000DE", "\U000000DF", "\U000000E0", "\U000000E1", "\U000000E2", "\U000000E3", "\U000000E4", "\U000000E5", "\U000000E6", "\U000000E7", "\U000000E8", "\U000000E9", "\U000000EA", "\U000000EB", "\U000000EC", "\U000000ED", "\U000000EE", "\U000000EF", "\U000000F0", "\U000000F1", "\U000000F2", "\U000000F3", "\U000000F4", "\U000000F5", "\U000000F6", "\U000000F7", "\U000000F8", "\U000000F9", "\U000000FA", "\U000000FB", "\U000000FC", "\U000000FD", "\U000000FE", "\U000000FF", "\U000003BC", "\U000003A9", "\U000020AC", "\U00002122"]
- file: "fonts/materialdesignicons-webfont.ttf"
id: font_material_design_icons_400_85
size: 85
glyphs: ["\U000F07D0"]
- file: "fonts/materialdesignicons-webfont.ttf"
id: font_material_design_icons_400_24
size: 24
glyphs: ["\U000F091F", "\U000F0922", "\U000F0925", "\U000F0928", "\U000F092B"]
script:
- id: change_page_to
parameters:
target_page: int
then:
- lambda: |-
int pages_count = 1;
int target = target_page;
while (target < 0) target += pages_count;
target %= pages_count;
// Debounce: Ignore page changes within 500ms of last change
// (adjusted for LCD display update time)
uint32_t now = millis();
if (now - id(last_page_switch_time) < 500) {
ESP_LOGD("display", "Page change ignored (debounce), last switch was %d ms ago", now - id(last_page_switch_time));
return;
}
if (id(display_page) != target) {
// Set debounce time BEFORE display update (update takes ~1.6s)
id(last_page_switch_time) = now;
id(display_page) = target;
id(my_display).update();
ESP_LOGI("display", "Switched to page %d", target);
// Restart refresh logic
if (id(manage_run_and_sleep).is_running()) id(manage_run_and_sleep).stop();
id(manage_run_and_sleep).execute();
}
- id: manage_run_and_sleep
mode: restart
then:
- logger.log: "Waiting for sync..."
- wait_until:
condition:
lambda: 'return id(ha_time).now().is_valid() && api_is_connected();'
timeout: 60s
- delay: 5s
- lambda: 'id(page_refresh_current_s) = id(page_refresh_default_s);'
- component.update: my_display
- delay: !lambda 'return id(page_refresh_current_s) * 1000;'
- script.execute: manage_run_and_sleep
I have just finished another hardware receipt, this time for the Cheap Yellow Display
While doing that I discovered a small bug. This display has a LDR sensor on the front to measure incoming light and thus be able to adjust backlighting. I added that as a sensor in the hardware receipt
I used this receipt and created a sketch presenting a text sensor as well as the wifi sensor. If I do that the generated code will include include two
sensor:sections. See this example: