Waveshare ESP32-S3 LCD Touch 4"

Dear All!

I have a Waveshare ESP32-S3 LCD Touch 4" display with st7701s. There is an issue when I do a soft reset on the esp32. The display gets purple tint and won’t work. If I press the reset button (physical) on the panel the screen starts working again. Every time when I use OTA firmware update I have to press the reset button on the panel. What is the difference between soft and hard reset on esp32? How can I avoid this issue? I’ve tried to manual reset the display in the on_boot section without success. In the config file at the display section there is a reset pin declaration, which is the right pin.

Finally solved this issue. I pull the display reset pin LOW at the end of OTA update and pull it back to HIGH at boot priority 0.

Curiously, I have a Waveshare 4" LCD (an early model) that does the opposite - a power cycle results in a display with wrong colours, any kind of soft reset including OTA update fixes it.

I’ve got the rev 4.0 board and after 3 days messing, for me, there are two key things to get it reliably resetting and cold powering on with no issues:

  1. You have to enable the GT911 touch controller… without that in the chain I could never get cold boots working, only soft/warm resets… (seems the faux IO expander CH32V003F has some hidden logic)
  2. I delayed the display: setup until -50 which initialises that well after the IO expander.

Here’s the YAML for both…

touchscreen:
  - platform: gt911
    id: my_touchscreen
    display: my_display

    reset_pin:
      waveshare_io_ch32v003: waveshare_io_hub
      number: 1

display:
  - platform: mipi_rgb
    setup_priority: -50
    model: WAVESHARE-4-480x480
    id: my_display
    rotation: 180
    reset_pin:
      waveshare_io_ch32v003: waveshare_io_hub
      number: 3

I do a triple ‘beep’ on_boot but don’t think that matters… this just let me know the IO expander was ‘active’ so when I delayed the display boot priority to -50 which is after all that, I was perplexed why the display wasn’t resetting correctly and ultimately made me realise the CH32V0003F IO expander (MCU repurposed) was maybe doing more than just being a blind IO expander and despite AI saying it thought it was highly unlikely to work, I just tried enabling the touchscreen and to my amazement, the display booted on a soft reset, warm reset and from a cold boot 100% of the time!

I don’t think this is needed, but since I do this, and it interacts with the IO expander to prove it’s all booted correctly, here’s my extra Yaml on boot: (The backlight turns on by default to close to 100%, I just lower it to 50% as it runs cooler and I don’t need it that bright!)

    - priority: -150
      then:
        - delay: 200ms
        - light.turn_on:
            id: display_backlight
            brightness: 50%
        - delay: 100ms            
        - delay: 100ms
        - output.turn_on: board_speaker_out
        - delay: 100ms
        - output.turn_off: board_speaker_out
        - delay: 100ms
        - output.turn_on: board_speaker_out
        - delay: 100ms
        - output.turn_off: board_speaker_out
        - delay: 100ms
        - output.turn_on: board_speaker_out
        - delay: 100ms
        - output.turn_off: board_speaker_out
        - component.update: my_display

Hope that helps someone!

Very helpful, thanks!
I have a couple other issues (I can’t get my speaker to beep), you cool sharing your full YAML for the rev4 board?

I’m curious as well. I got my display to not be black with your code (it’s an ugly green now), but it doesn’t stop beeping, which is very annoying during troubleshooting.

[edit] in the mean time I got the display to work, so that’s no trouble anymore, I got the beeper off, so no trouble there, I just can’t manage to get the touchscreen working now, I’ve been on that for over a day.

Oh come on!!! I dont believe you and think your a fibber!! You dont have to lie here just to make friends!!

; ) jk

Still no touchscreen? Was it originally working at least and isn’t anymore or what?? Also, its typically very helpful if you also provide your code/config, pictures/videos if relevant and also any personal glamor shots worthy of framing and hanging on our walls… well at least everything else that’s not a glamor shot. ; ) lol.

Was there anything that may have accidentally gotten changed from your original code to what you changed to now? Did you accidentally configure a different touchscreen driver perhaps??

On a side note, you cant always just copy/paste others code from online just because you might both be using a “Waveshare Touch 4” because very often they make these things slightly different over time or slightly different so there may be different features/capabilities between different variations and so its very important that you always verify the code you’re copying has the correct gpio pins listed, the correct hardware driver and etc.

For example here is a common one that i see and people will often just refer to all of these as the “CYD Displays” or Cheap Yellow Display and as you can see there are several versions of the display and they spoken about as if theres only 1.

@snubbers
I’m “working” on the Waveshare ESP32-S3 Touch LCD 4.0 Rev 4 board, and I’m hitting the same “grey screen” issue you described.
From your post it looks like you used a custom / external ESPHome component (waveshare_io_ch32v003 + waveshare_rgb / mipi_rgb) to properly initialise the CH32 MCU and release the LCD reset.
I can’t seem to find these components in official ESPHome, and the GitHub repo links I’ve been pointed to, appear to be “dead ends”/404.
Would you mind sharing where you got those components from (or your repo/branch), and how you integrated them into ESPHome?
Even a pointer would help a lot — I only need basic display output (just showing temperature).
Thanks in advance :slightly_smiling_face:

@JimmyHotcakes0235 https://www.waveshare.com/esp32-s3-touch-lcd-4.htm?sku=28154 , the “challenge” here, is , that waveshares documentation, does not mention rev 4.0 specific. And their product page is showing rev 3.0 .

Please link to official website for products instead either trying to type the whole name out or worse case is people that use abbreviated names/words or use very vague names for things… When you and anyone else post here or any forum asking a question then please do the person trying to help you a solid favor by providing the specific links for any components mentioned in your OP. You seriously want to try avoiding at all costs where you’re asking about one thing and someone elae assumed you’re talking about a different device and then things start seeming worse than when the problem started…

If you leave room for people to make guesses and assumptions then they absolutely will do that.

It’s important for anyone trying to help you that you’re both talking about the exact same things and also its very common to need to pull up a devices documentation/spec sheets inorder to help and without providing them a link where it can be found, now they’ve got to go Google your device and then assume or hope that its the correct option and all of the internal components and drivers required, they all match yours because if not and you dont have the correct device model ID’s and are looking for a driver that goes with the Revision #3 display…

By providing an official product link in your posts then you are absolutely helping everyone else including yourself by not leaving opportunities for others to make guesses or assumptions and waste a whole bunch of everyone’s time because of it!

The touchscreen only worked with the original Arduino code, and to be sure, I put it back yesterday, and it still works. It’s a rev 4.0, and no, it’s not a CYD. I didn’t just copy/paste code from others (although looking at code from others, checking it an if it’s good paste it isn’t a bad thing to do).

Your comments aren’t really helpful. But as you wish, I’ll show the code here:


esphome:
  name: mini-screen
  platformio_options:
    board_build.flash_mode: dio
  min_version: 2024.11.0
  on_boot:
    priority: -100
    then:
      - lambda: |-
          id(waveshare_io_hub).digital_write(6, false);

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  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"
    components:
      - name: "espressif/esp_websocket_client"
        ref: 1.5.0
      - name: "espressif/esp-dsp"
        ref: 1.7.0
      - name: "bitbank2/jpegdec"
        source: https://github.com/strange-v/jpegdec-esphome


preferences:
  flash_write_interval: 1min   # Limit flash writes to once per minute

psram:
  mode: octal
  speed: 80MHz

external_components:
  - source: github://strange-v/RemoteWebViewClient@main
    refresh: 0s
    components: [remote_webview]
  - source: github://fuzzybear62/esphome-waveshare_io_ch32v003@main
    refresh: 0s
    components: [ waveshare_io_ch32v003 ]

logger:

api:
  encryption:
    key: !secret api_key     # Replace with your own API key
  reboot_timeout: 0s                        # Prevent reboot if HA connection lost

ota:
  - platform: esphome
    password: !secret ota_password      # Replace with your OTA password

wifi:
  ssid: !secret wifi_ssid                   # Defined in secrets.yaml
  password: !secret wifi_password           # Defined in secrets.yaml
  ap:
    ssid: "ESP32-LCD4 Fallback Hotspot"
    password: !secret ap_password      # Used if Wi-Fi fails

captive_portal:

i2c:
  - id: tp_i2c
    sda: GPIO15
    scl: GPIO7
    scan: true
    frequency: 400kHz

waveshare_io_ch32v003:
  id: waveshare_io_hub
  i2c_id: tp_i2c
  address: 0x24

# Touchscreen setup with mirrored X/Y to match display orientation

touchscreen:
  platform: gt911
  i2c_id: tp_i2c
  id: my_touchscreen
  display: my_display
  setup_priority: -200
  reset_pin:
    waveshare_io_ch32v003: waveshare_io_hub
    number: 1

#  on_touch:
#    - logger.log:
#        format: "TOUCH at x=%d y=%d"
#        args: [touch.x, touch.y]
#    - script.execute: reset_display_timeout   # Reset screen timeout on touch
#    - if:
#        condition:
#          light.is_off: display_backlight
#        then:
#          - light.turn_on: display_backlight   # Turn backlight on if off

light:
  - platform: monochromatic
    output: backlight_output
    id: display_backlight
    restore_mode: ALWAYS_ON
    default_transition_length: 4s
    gamma_correct: 1.0

switch:
  - platform: gpio
    id: buzzer
    pin:
      waveshare_io_ch32v003: waveshare_io_hub
      number: 4
      mode:
        output: true
      inverted: True
    restore_mode: ALWAYS_OFF

output:
  - platform: ledc
    id: backlight_output
    pin: 44
    frequency: 1220Hz
    inverted: true
    min_power: 15%

spi:
  - id: lcd_spi
    mosi_pin: GPIO1
    clk_pin: GPIO2
    miso_pin: GPIO4

display:
  platform: mipi_rgb
  setup_priority: -100
  model: WAVESHARE-4-480x480
  id: my_display
  rotation: 180
  reset_pin:
    waveshare_io_ch32v003: waveshare_io_hub
    number: 3

# Script to turn off display backlight after inactivity
script:
  - id: reset_display_timeout
    mode: restart
    then:
      - delay: 30s
      - light.turn_off: display_backlight

# RemoteWebView — renders HA dashboard remotely and streams to display
remote_webview:
  id: rwv
  display_id: my_display
  touchscreen_id: my_touchscreen
  device_id: mini-screen
  server: "192.168.42.10:8181"   # Replace with your server hostname or IP
  url: "http://hass:8123/cc-screen"   # Replace with your HA dashboard URL
  tile_size: 64
  full_frame_tile_count: 2
  full_frame_area_threshold: 0.30
  full_frame_every: 30
  every_nth_frame: 2
  min_frame_interval: 600
  jpeg_quality: 80
  max_bytes_per_msg: 61440

# Expose the dashboard URL as a Home Assistant text entity
text:
  - platform: template
    id: rwv_url
    name: "Dashboard URL"
    optimistic: true
    mode: TEXT
    set_action:
      - lambda: |-
          if (!id(rwv).open_url(std::string(x.c_str()))) {
            id(rwv).set_url(std::string(x.c_str()));
            ESP_LOGI("remote_webview", "URL queued (not connected): %s", x.c_str());

As I wrote: everything works, except for touch…

[edit: reversed framework to the working version, I hoped Arduino would work better, but didn’t work at all; edit2: display: shortened, works as well with this driver]

We both responded to snubbers, who wrote in reply to the others, that he had a rev 4.0 board. A Waveshare ESP32-S3 LCD Touch 4" rev 4 => DuckDuckGo (I don’t use Google) first site: https://www.waveshare.com/esp32-s3-touch-lcd-4.htm. As buenso wrote, this is all rev3, there’s only a product schematic diagram on their wiki page (https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-4, I’m not allowed to put the link for the pdf here, as I am a new user) for rev 4.0. I’m currently mailing with Waveshare support, since I didn’t expect any comments here anymore.

But you’re right, the complete yaml was missing, so I had to search for the waveshare_io_ch32v003, and probably other external components are missing, and I have no clue whether he used esp-idf or Arduino. It would have helped a lot if that were clear.

From Waveshare support I was literally pointed to this thread for working code, or their demo code. I guess if snubbers doesn’t respond anymore, we’ll never find out. The biggest problem is that touch works with interrupts, but Waveshare decided to have their touch interrupt behind a io-expander. That isn’t usable in ESPHome as interrupt, so it never registers touch. Polling didn’t work either. I tried both Arduino and esp-idf to read touch on the device, but it never registers.

Are you sure using the right I/O-Expander?
It’s a TCA9554PWR according to docs

Yes and no. In the text it is the TCA9554PWR, but then if you look at the schematics, it is another one for rev 4.0. Either Waveshare doesn’t update their website, or they think it’s too much trouble for this cheap device.

[edit] I just tried with that EXIO, but it fails to boot, so that’s a very clear no, unfortunately.

ok, Waveshare provides a lot of documentation, but the quality is … I have the Touch LCD 4B, but I had to go through the demo code to find the pin numbers, the schematics is pretty much useless ( or I lack the skills to read it…). Still trying to figure out the GPIO for the buttons…

In the Demo Code for “ESP32-S3-Touch-LCD-4-V4 Demo” they seem to use the TCA9554PWR, but it might also link to the wrong source code package. Did you try to get any of the Demos running ?

The widget demo in the “ESP32-S3-Touch-LCD-4-V4 Demo” worked, but I cannot find any reference to the TCA9554PWR? I couldn’t find any reference to any irq either, it looks like they’re only polling. Installing that demo was the only reason I continued testing, since I came to the point that it looked like the thing was broken and I’d better stop trying.

You can see from the top there is code:

    then:
      - lambda: |-
          id(waveshare_io_hub).digital_write(6, false);

This is to turn off the speaker, and this works. Otherwise the speaker is beeping continuously :wink:

in the 06-Example for esp-idf
ESP-IDF-v5.3.1\06_LVGL_Proting\main
example_rgb_avoid_tearing.c

also in the Arduino-Examples
libraries\ESP32_IO_Expander\src
in both they seem to reference TCA9554 or PCA9554

for the 4B I also had to initialize the expander during boot:

Sample from my package for the 4B:

esphome:
  on_boot:
    then:
    - logger.log: "Onboot seq"
    - lambda: !lambda |-
       id(p_c_a)->pin_mode(1, esphome::gpio::FLAG_OUTPUT);
       id(p_c_a)->digital_write(1, false);
       id(p_c_a)->pin_mode(2, esphome::gpio::FLAG_OUTPUT);
       id(p_c_a)->digital_write(2, false);

# I2C bus configuration
i2c:
  - id: i2c_bus
    sda: GPIO47
    scl: GPIO48
    scan: true
    frequency: 100kHz
# PCA9554 GPIO extender for display reset
pca9554:
  - id: p_c_a
    address: 0x20
    i2c_id: i2c_bus
    pin_count: 8

The B has only one revision, the standard 4 has 4. In the schema of the 4B is the TCA9554PWR, so that’s probably based on rev 3.0. I guess that would have been better for me too :slight_smile:

I didn’t get any response from Waveshare anymore, so I suppose that the rev 4.0 is not compatible with ESPHome for now. I ordered another board, with more proven history and no revision updates yet :wink:

I’ve found some help on github: GitHub - PedanticAvenger/Waveshare_ESP32-S3-TOUCH-LCD-4: ESPHome config and board docs for the Waveshare_ESP32-S3-TOUCH-LCD-4 (rev. 4.0 currently) and ComfoSense-Touch/REV4_TECHNICAL_GUIDE.md at unified_fw_rev4_upgrade · vincentmakes/ComfoSense-Touch · GitHub that seem to work for me.