ESP32-S3 4.3inch Capacitive Touch Display from - waveshare

Check the device logs to see if the action is being sent; check the HA logs to see if there are any errors there. Does the button change state when you switch the light from elsewhere?

Holy crap! I left it unplugged for a couple hours, then I plugged it back in just now to see if it would change state when I turned the light on, and the dang thing is working. But apparently blue is off and red is on, which I guess makes sense. But I literally made no changes to my code.

Okay, and now I’m noticing something else. It’s really flaky. I’ll let the screen go to sleep for a minute or so, when it wakes the screen comes up blank before refreshing the button and I can click the button a few times (and it will change state on the screen) while nothing happens to the light. Then all of a sudden it will start working again. But if I let it go to sleep and then immediately wake it back up, the screen comes up with the button on it and it still remains functional. Any idea what that might be about?

Well, I refer you to my previous answer about checking logs. But it sounds like you have some flakey communications.

A couple of unrelated things - you don’t need the on_boot action to show the main page, that happens by default (and you only have one page anyway.) Instead of using the global variable and an interval to control the backlight, use the LVGL on_idle trigger - see the cookbook for examples.

Okay, yeah, I was just taking the code from above for the blanking. But following your suggestion, I dug into the LVGL tips and tricks and moved to that method. That seems to be working well. I AM having some sort of communications issues though, but I’m unsure of how to move forward with the troubleshooting…

my new yaml:

esphome:
  name: waveshare-esp32-s3-touch
  friendly_name: Waveshare-ESP32-S3-Touch
  platformio_options:
    build_flags: "-DBOARD_HAS_PSRAM"
    board_build.arduino.memory_type: qio_opi
    board_build.flash_mode: dio
    board_upload.maximum_ram_size: 524288

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
      CONFIG_ESP32S3_DATA_CACHE_64KB: y
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y

# Enable logging
logger:
  level: DEBUG
  
# Enable Home Assistant API
api:
  encryption:
    key: "<secret>"

ota:
  - platform: esphome
    password: "<secret>"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Waveshare-Esp32-S3-Touch"
    password: "<secret>"
    
ch422g:
  - id: ch422g_hub

psram:
  mode: octal
  speed: 80MHz

i2c:
  sda: 8
  scl: 9
  scan: true
  frequency: 400kHz


# Switch to turn backlight back on
switch:
  - platform: gpio
    name: backlight
    id: display_backlight
    pin:
      ch422g: ch422g_hub
      number: 2
      mode:
        output: true
      inverted: False
    restore_mode: ALWAYS_ON
# Antiburn Switch
  - platform: template
    name: Antiburn
    id: switch_antiburn
    icon: mdi:television-shimmer
    optimistic: true
    entity_category: "config"
    turn_on_action:
      - logger.log: "Starting Antiburn"
      - if:
          condition: lvgl.is_paused
          then:
            - lvgl.resume:
            - lvgl.widget.redraw:
      - lvgl.pause:
          show_snow: true
    turn_off_action:
      - logger.log: "Stopping Antiburn"
      - if:
          condition: lvgl.is_paused
          then:
            - lvgl.resume:
            - lvgl.widget.redraw:

# Timer for Antiburn 
time:
  - platform: homeassistant
    on_time:
      - hours: 2,3,4,5
        minutes: 5
        seconds: 0
        then:
          - switch.turn_on: switch_antiburn
      - hours: 2,3,4,5
        minutes: 35
        seconds: 0
        then:
          - switch.turn_off: switch_antiburn

# Number to track backlight timeout
number:
  - platform: template
    name: LVGL Screen timeout
    optimistic: true
    id: display_timeout
    unit_of_measurement: "s"
    initial_value: 45
    restore_value: true
    min_value: 10
    max_value: 180
    step: 5
    mode: box    

touchscreen:
  - platform: gt911
    id: my_touchscreen
    interrupt_pin: 4
    reset_pin:
      ch422g:
      number: 1
    on_release:
      - if:
          condition: lvgl.is_paused
          then:
            - logger.log: "LVGL resuming"
            - lvgl.resume:
            - lvgl.widget.redraw:
            - switch.turn_on: display_backlight

display:
  - platform: rpi_dpi_rgb
    id: rpi_disp
#    update_interval: never
    auto_clear_enabled: false
    color_order: RGB
    pclk_frequency: 16MHz
    dimensions:
      width: 800
      height: 480
    reset_pin:
      ch422g:
      number: 3
    enable_pin:
      id: enable_pin_display
      ch422g:
      number: 2
    de_pin:
      number: 5
    hsync_pin:
      number: 46
      ignore_strapping_warning: true
    vsync_pin:
      number: 3
      ignore_strapping_warning: true
    pclk_pin: 7
    hsync_back_porch: 30
    hsync_front_porch: 210
    hsync_pulse_width: 30
    vsync_back_porch: 4
    vsync_front_porch: 4
    vsync_pulse_width: 4
    data_pins:
      red: [1, 2, 42, 41, 40]
      blue: [14, 38, 18, 17, 10]
      green: [39, 0, 45, 48, 47, 21]
      

# Draw the dashboard
lvgl:
  displays:
    - rpi_disp
  touchscreens:
    - my_touchscreen
  on_idle:
    timeout: !lambda "return (id(display_timeout).state * 1000);"
    then:
      - logger.log: "LVGL is idle"
      - switch.turn_off: display_backlight
      - lvgl.pause:            
  pages:
    - id: main_page
      width: 100%
      bg_color: 0x000000
      bg_opa: cover
      widgets:
        - button:
            id: office_corner_light_btn
            align: CENTER
            width: 150
            height: 70
            checkable: true
            widgets:
              - label:
                  align: CENTER
                  text: 'Office Corner Lights'
            on_click:
              - logger.log: "Toggle Button Pressed"   
              - homeassistant.action:
                  action: light.toggle
                  data:
                    entity_id: light.lifx_bulb

I was preparing to paste a ton of logs in here when I stumbled upon this in the homeassistant logs:

Can't connect to ESPHome API for waveshare-esp32-s3-touch @ 192.168.0.132: waveshare-esp32-s3-touch @ 192.168.0.132: The connection dropped immediately after encrypted hello; Try enabling encryption on the device or turning off encryption on the client (Home Assistant 2025.3.2). (HandshakeAPIError)

So… any idea where I fix that? I can only assume that the waveshare is connecting to homeassistant through my apache reverse proxy, which is totally fine with me, but since it’s not leaving the house, I can just as easily connect directly to it if I know where to configure that :confused:

No idea, and it’s not a display issue, personally I would start by deleting the device in HA and adding it again.

So that’s exactly what I did. Deleted it all, went and re-initialized it through web.esphome.io and then re-added to home assistant and re-installed my yaml. Seems to work until it doesn’t. But as you said, doesn’t seem to be a display issue. I’ll have to make a new post outlining what’s going on, because there’s something fishy going on, and it seems like the whole device is going to sleep instead of just the screen, and then when it wakes up it struggles to connect or something. Thanks for all the help though, at least I’ve gotten it to a point where it seems like my yaml is working. That was a huge step forward!

With this code

esphome:
  name: esp-display
  friendly_name: ESP Display
  platformio_options:
    build_flags: "-DBOARD_HAS_PSRAM"
    board_build.arduino.memory_type: qio_opi
    board_build.flash_mode: dio
    board_upload.maximum_ram_size: 524288

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
      CONFIG_ESP32S3_DATA_CACHE_64KB: y
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y

# Enable logging
logger:
  level: DEBUG
  
# Enable Home Assistant API
api:
  encryption:
    key: "KEY"

ota:
  - platform: esphome
    password: "PASSWORD"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp-Display Fallback Hotspot"
    password: "PASSWORD"
    
ch422g:
  - id: ch422g_hub

psram:
  mode: octal
  speed: 80MHz

i2c:
  sda: 8
  scl: 9
  scan: true
  frequency: 400kHz


# Switch to turn backlight back on
switch:
  - platform: gpio
    name: backlight
    id: display_backlight
    pin:
      ch422g: ch422g_hub
      number: 2
      mode:
        output: true
      inverted: False
    restore_mode: ALWAYS_ON
# Antiburn Switch
  - platform: template
    name: Antiburn
    id: switch_antiburn
    icon: mdi:television-shimmer
    optimistic: true
    entity_category: "config"
    turn_on_action:
      - logger.log: "Starting Antiburn"
      - if:
          condition: lvgl.is_paused
          then:
            - lvgl.resume:
            - lvgl.widget.redraw:
      - lvgl.pause:
          show_snow: true
    turn_off_action:
      - logger.log: "Stopping Antiburn"
      - if:
          condition: lvgl.is_paused
          then:
            - lvgl.resume:
            - lvgl.widget.redraw:

# Timer for Antiburn 
time:
  - platform: homeassistant
    on_time:
      - hours: 2,3,4,5
        minutes: 5
        seconds: 0
        then:
          - switch.turn_on: switch_antiburn
      - hours: 2,3,4,5
        minutes: 35
        seconds: 0
        then:
          - switch.turn_off: switch_antiburn

# Number to track backlight timeout
number:
  - platform: template
    name: LVGL Screen timeout
    optimistic: true
    id: display_timeout
    unit_of_measurement: "s"
    initial_value: 45
    restore_value: true
    min_value: 10
    max_value: 180
    step: 5
    mode: box    

touchscreen:
  - platform: gt911
    id: my_touchscreen
    interrupt_pin: GPIO4
    reset_pin:
      ch422g:
      number: 1
    on_touch:
      - lambda: |-
        ESP_LOGI("Touch", "Touch detected at x=%d, y=%d", touch.x, touch.y);
    on_release:
      - if:
          condition: lvgl.is_paused
          then:
            - logger.log: "LVGL resuming"
            - lvgl.resume:
            - lvgl.widget.redraw:
            - switch.turn_on: display_backlight

display:
  - platform: rpi_dpi_rgb
    id: rpi_disp
#    update_interval: never
    auto_clear_enabled: false
    color_order: RGB
    pclk_frequency: 16MHz
    dimensions:
      width: 800
      height: 480
    reset_pin:
      ch422g:
      number: 3
    enable_pin:
      id: enable_pin_display
      ch422g:
      number: 2
    de_pin:
      number: 5
    hsync_pin:
      number: 46
      ignore_strapping_warning: true
    vsync_pin:
      number: 3
      ignore_strapping_warning: true
    pclk_pin: 7
    hsync_back_porch: 30
    hsync_front_porch: 210
    hsync_pulse_width: 30
    vsync_back_porch: 4
    vsync_front_porch: 4
    vsync_pulse_width: 4
    data_pins:
      red: [1, 2, 42, 41, 40]
      blue: [14, 38, 18, 17, 10]
      green: [39, 0, 45, 48, 47, 21]
      

# Draw the dashboard
lvgl:
  displays:
    - rpi_disp
  touchscreens:
    - my_touchscreen
  on_idle:
    timeout: !lambda "return (id(display_timeout).state * 1000);"
    then:
      - logger.log: "LVGL is idle"
      - switch.turn_off: display_backlight
      - lvgl.pause:            
  pages:
    - id: main_page
      width: 100%
      bg_color: 0x000000
      bg_opa: cover
      widgets:
        - button:
            id: office_light_btn
            align: CENTER
            width: 200
            height: 100
            checkable: true
            widgets:
              - label:
                  align: CENTER
                  text: 'Office Light'
            on_click:
              - logger.log: "Toggle Button Pressed"   
              - homeassistant.action:
                  action: light.toggle
                  data:
                    entity_id: light.office_light

text_sensor:
  - platform: wifi_info
    ip_address:
      name: IP Address
    ssid:
      name: Connected SSID
    bssid:
      name: Connected BSSID
    mac_address:
      name: Mac Wifi Address
    scan_results:
      name: Latest Scan Results

sensor:
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    update_interval: 60s

  - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
    name: "WiFi Signal dB"
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"

Everything is working but after the screen wakes up it take 5-10 seconds before the button will do anything. Any ideas how to speed that up?

Does anyone happen to have a basic working ESPHome example for the Waveshare 4.3" Touch Display? I’ve tried multiple selections from above but after flashing I’m getting nothing and HA is not recognizing my diplay.

This works for the 7" version. Is that what you have?

I have the 4.3" version.

try this one

substitutions:
  name: waveshare-s3-touch
  friendly_name: Waveshare S3 4.3

esphome:
  name: "${name}"
  platformio_options:
    board_build.flash_mode: dio


esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y

logger:

ch422g:

psram:
  mode: octal
  speed: 80MHz

i2c:
  sda: 8
  scl: 9
  scan: true
  frequency: 400kHz

touchscreen:
  - platform: gt911
    id: my_touchscreen
    interrupt_pin: 4
    reset_pin:
      ch422g:
      number: 1

display:
  - platform: rpi_dpi_rgb
    id: rpi_disp
    update_interval: never
    auto_clear_enabled: false
    color_order: RGB
    pclk_frequency: 16MHz
    dimensions:
      width: 800
      height: 480
    reset_pin:
      ch422g:
      number: 3
    enable_pin:
      ch422g:
      number: 2
    de_pin:
      number: 5
    hsync_pin:
      number: 46
      ignore_strapping_warning: true
    vsync_pin:
      number: 3
      ignore_strapping_warning: true
    pclk_pin: 7
    hsync_back_porch: 30
    hsync_front_porch: 210
    hsync_pulse_width: 30
    vsync_back_porch: 4
    vsync_front_porch: 4
    vsync_pulse_width: 4
    data_pins:
      red: [1, 2, 42, 41, 40]
      blue: [14, 38, 18, 17, 10]
      green: [39, 0, 45, 48, 47, 21]

lvgl:

I’ve flashed it and I see nothing.

Just want to make sure I’m flashing correctly. I’m holding down the boot button while powering up and then flashing with ESPHome Flasher 1.4 (I’m old fashioned and like using it). Afterwards, I’m moving the USB C cable to the USB port to power it on.

When doing so, I hear the PC I’m plugged into continually beep over and over again like the diplay is restarting.

I see nothing on the display but I can see the two red LEDs on the back and the backlight appears to be on.

Maybe I’m not following the correct flash/power on procedure?

You don’t have enough power to power it.

Get a USB brick

Yeah, I’m using a 20W USB block. Still nothing…

Turns out you can’t use ESPHome Flasher to flash these devices…it needs to be flashed via ESPHome Web.

Thank you so much.Good.

1 Like