Waveshare ESP32-S3-Touch-LCD-7

I’ve uploaded my test example to my github for this device in case it helps anyone. Scroll down to the bottom of the readme page for the link.
Please report back if this helps anyone and any other code examples related to this device.
Regards
Derham

3 Likes

Hello,
I have a project with this ESP32-S3-Touch-LCD-7.
For the display it works.
The touchscreen seems to work because I can move from one page to another and when I press the lamp button the color change.
The problem is that, it does not send the command to HA and therefore switching the lamp on/off does not work.
What could be the problem?

HA button code:
- button:
x: 650
y: 260
width: 60
height: 58
checkable: true
widgets:
- label:
text_font: light32
id: ext_light_l1_btn
text: “\U000F0335”
align: center
on_click:
- homeassistant.service:
service: switch.toggle
data_template:
entity_id: switch.10014d7390_4


1 Like

I don’t know what your issue is as you haven’t provided all of the yaml but here is a working example of pressing a button to turn on/off a plug socket with a light attached, perhaps that will help you further…

################################################################################
# Substitution Variables
################################################################################
substitutions:
  device_internal_name: esphome_19
  device_wifi_name: esphome-19
  device_friendly_name: ESPHome 19
  device_ip_address: 192.168.1.19
  device_sampling_time: 30s

  # glyphs
  lightbulb_on:      "\U000F0335"
  lightbulb_off:     "\U000F0336"


################################################################################
# Globals
################################################################################
globals: ##to set default reboot behavior
  - id: wifi_connection
    type: bool
    restore_value: no
    initial_value: "false"


################################################################################
# Board Configuration
################################################################################
esphome:
  name: ${device_internal_name}
  friendly_name: ${device_friendly_name}
  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

psram:
  mode: octal
  speed: 120MHz

esp32:
  board: esp32s3box
  variant: ESP32S3
  flash_size: 8MB
  framework:
    type: esp-idf
    platform_version: 6.9.0
    version: 5.3.0
    sdkconfig_options:
      COMPILER_OPTIMIZATION_SIZE: y
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_ESPTOOLPY_FLASHSIZE_8MB: "y"
      CONFIG_FREERTOS_HZ: "1000"
      CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240: y
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: y
      CONFIG_COMPILER_OPTIMIZATION_PERF: y

################################################################################
# Enable logging
################################################################################
logger:
  logs:
    component: ERROR

################################################################################
# Enable Home Assistant API
################################################################################
api:
  reboot_timeout: 0s
  encryption:
    key: !secret api_encryption_key

################################################################################
# OTA
################################################################################
ota:
  platform: esphome
  password: !secret web_server_password

################################################################################
# WiFi
################################################################################
wifi:
  networks:
    - ssid: !secret wifi_ssid
      password: !secret wifi_password
  output_power: 13
  reboot_timeout: 30min
  manual_ip:
    static_ip: ${device_ip_address}
    gateway: !secret gateway_address
    subnet: !secret subnet_address

  ap:
    # ssid: ${device_wifi_name}
    password: !secret web_server_password

captive_portal:

################################################################################
# Web Server
################################################################################
web_server:
  port: 80
  version: 3
  include_internal: true
  auth:
    username: !secret web_server_user
    password: !secret web_server_password
  local: true

################################################################################
# IO Extender
################################################################################
ch422g:
  - id: ch422g_hub

################################################################################
# Switch
################################################################################
switch:
  - platform: restart
    name: "Restart"
    id: device_restart
  
  - platform: safe_mode
    name: Use Safe Mode
    id: device_safe_mode
    
  - platform: gpio
    id: lcdbacklight
    name: lcdbacklight
    pin:
      ch422g: ch422g_hub
      number: 2
      mode:
        output: true
      inverted: false
    restore_mode: ALWAYS_ON

################################################################################
# Sensors
################################################################################
sensor:
  # WiFi
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: ${device_internal_name}_wifi_signal_sensor
    update_interval: 10s

################################################################################
# Text Sensors
################################################################################
text_sensor:
  - platform: homeassistant
    id: remote_light
    entity_id: switch.smart_power_strip_socket_2
    on_value:
      then:
        - lvgl.widget.update: # matrix button
            id: btn_light
            state:
              checked: !lambda return (0 == x.compare(std::string{"on"}));
              disabled: !lambda return ((0 == x.compare(std::string{"unavailable"})) or (0 == x.compare(std::string{"unknown"})));
        - lvgl.label.update:
            id: btn_light_icon # the matrix icon
            text: !lambda |-
              static char buf[10];
              std::string icon;
              if (0 == x.compare(std::string{"on"})) {
                  icon = "$lightbulb_on";
              } else {
                  icon = "$lightbulb_off";
              }
              snprintf(buf, sizeof(buf), "%s", icon.c_str());
              return buf;


color:
  - id: my_red
    red: 100%
    green: 0%
    blue: 0%
  - id: my_pink
    red: 100%
    green: 10%
    blue: 40%
  - id: my_yellow
    red: 100%
    green: 100%
    blue: 0%
  - id: my_green
    red: 0%
    green: 100%
    blue: 0%
  - id: my_blue
    red: 0%
    green: 0%
    blue: 100%
  - id: my_gray
    red: 50%
    green: 50%
    blue: 50%
  - id: my_white
    red: 100%
    green: 100%
    blue: 100%
  - id: my_black
    red: 0%
    green: 0%
    blue: 0%

font:
  - file: "fonts/arial.ttf"
    id: arial_98
    size: 98
  - file: "fonts/arial.ttf"
    id: arial_96
    size: 96
  - file: "fonts/arial.ttf"
    id: arial_134
    size: 134
  - file: "fonts/arial.ttf"
    id: arial_128
    size: 128
  - file: "fonts/arial.ttf"
    id: arial_48
    size: 48
  - file: "fonts/arial.ttf"
    id: arial_36
    size: 36
  - file: "fonts/arial.ttf"
    id: arial_24
    size: 24
  - file: "fonts/arial.ttf"
    id: arial_18
    size: 18
  - file: "fonts/arial.ttf"
    id: arial_12
    size: 12
  - file: "gfonts://Roboto"
    id: roboto10
    size: 10
    bpp: 4
  - file: "fonts/materialdesignicons-webfont.ttf"
    id: mdi_42
    size: 42
    bpp: 4
    glyphs: [
      "$lightbulb_on", 
      "$lightbulb_off", 
      ]


############################################ START OF VLGL

lvgl:
  theme:
    arc:
      scroll_on_focus: true
      #group: general
    slider:
      scroll_on_focus: true
      #group: general
    label:
      text_font: arial_18
    button:
      scroll_on_focus: true
      #group: general
      border_width: 2
      text_font: arial_24
      outline_pad: 6
      bg_color: my_blue
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      pressed:
        border_color: my_yellow
      checked:
        border_color: my_blue
        bg_color: my_yellow
      focused:
        border_color: my_white

  style_definitions:
    - id: header_footer
      bg_color: 0x2F8CD8
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      bg_opa: COVER
      border_opa: TRANSP
      radius: 0
      pad_all: 0
      pad_row: 0
      pad_column: 0
      border_color: 0x0077b3
      text_color: 0xFFFFFF
      width: 100%
      height: 30
    - id: matrix
      bg_color: my_green
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      bg_opa: COVER
      border_opa: TRANSP
      radius: 0
      pad_all: 0
      pad_row: 0
      pad_column: 0
      border_color: 0x0077b3
      text_color: 0xFFFFFF
      width: 100%
      height: 30

  top_layer:
      widgets:
        - line:   ######### blue border
            points:
              - 0, 0
              - 799, 0
              - 799, 479
              - 0, 479
              - 0, 0
            line_width: 4
            line_color: my_blue
            line_rounded: true

  log_level: INFO
  color_depth: 16
  buffer_size: 25%
  bg_color: my_black
  text_font: arial_24
  width: 800
  height: 480
  align: center

  pages:
    - id: main_page
      widgets:

        - obj:
            align: CENTER
            width: 450
            height: 420
            pad_all: 6
            bg_opa: TRANSP
            border_opa: TRANSP
            layout:
              type: GRID
              grid_columns: [FR(1), FR(1), FR(1)] 
              grid_rows: [FR(25), FR(25), FR(25), FR(25)]
            widgets:
              - button:
                  grid_cell_column_pos: 0
                  grid_cell_row_pos: 0
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 0
                  grid_cell_row_pos: 1
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  id: btn_light
                  grid_cell_column_pos: 0
                  grid_cell_row_pos: 2
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
                  text_font: mdi_42
                  widgets:
                    - label:
                        id: btn_light_icon
                        align: CENTER
                        y: -20
                        text_font: mdi_42
                        text: "$lightbulb_off" # mdi-lightbulb-outline

                    - label:
                        #id: cov_up_east
                        align: CENTER
                        y: 20
                        text: "Light"
                        text_color: my_white
                        text_font: arial_18
                  on_short_click:
                    - homeassistant.action:
                        action: switch.toggle
                        data:
                          entity_id: switch.smart_power_strip_socket_2
                    - logger.log:
                        format: "Light button clicked: %d"
                        args: [ x ]

              - button:
                  grid_cell_column_pos: 0
                  grid_cell_row_pos: 3
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 1
                  grid_cell_row_pos: 0
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 1
                  grid_cell_row_pos: 1
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 1
                  grid_cell_row_pos: 2
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 1
                  grid_cell_row_pos: 3
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 2
                  grid_cell_row_pos: 0
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 2
                  grid_cell_row_pos: 1
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 2
                  grid_cell_row_pos: 2
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH
              - button:
                  grid_cell_column_pos: 2
                  grid_cell_row_pos: 3
                  grid_cell_x_align: STRETCH
                  grid_cell_y_align: STRETCH


########################################################### END OF VLGL


i2c:
  sda: GPIO08
  scl: GPIO09
  scan: True
  id: bus_a

# Define display
display:
  - platform: rpi_dpi_rgb
    id: my_display
    update_interval: never
    auto_clear_enabled: false
    color_order: RGB
    pclk_frequency: 16MHZ
    dimensions:
      width: 800
      height: 480
    de_pin:
      number: 5
    hsync_pin:
      number: 46
      ignore_strapping_warning: true
    vsync_pin:
      number: 3
      ignore_strapping_warning: true
    pclk_pin: 7
    pclk_inverted: true
    reset_pin:
      ch422g: ch422g_hub
      number: 3
    hsync_back_porch: 8
    hsync_front_porch: 8
    hsync_pulse_width: 4
    vsync_back_porch: 16
    vsync_front_porch: 16
    vsync_pulse_width: 4
    data_pins:
      red:
        - 1         #r3
        - 2         #r4
        - 42        #r5
        - 41        #r6
        - 40        #r7
      blue:
        - 14        #b3
        - 38        #b4
        - 18        #b5
        - 17        #b6
        - 10        #b7
      green:
        - 39        #g2
        - 0         #g3
        - 45        #g4
        - 48        #g5
        - 47        #g6
        - 21        #g7

touchscreen:
  platform: gt911
  id: my_touch
  interrupt_pin: GPIO4
  reset_pin:
    ch422g: ch422g_hub
    number: 1
    mode: OUTPUT
  on_touch:
    - lambda: |-
        ESP_LOGI("Touch", "Touch detected at x=%d, y=%d", touch.x, touch.y);
  on_update:
    - lambda: |-
          for (auto touch: touches)  {
              if (touch.state <= 2) {
                ESP_LOGI("Touch points:", "id=%d x=%d, y=%d x.raw=%d, y.raw=%d", touch.id, touch.x, touch.y, touch.x_raw, touch.y_raw);
              }
          }  




1 Like

Hi
Thanks for your reply.
My problem was the Ewelink integration not the button configuration, now it’s ok.
Do you know how I can light off the screen for the night?

This looks like a nice layout.

Would you mind sharing your yaml source for this?

Thanks

Would you mind reaching out to me please via Email. Thank u.
Jeremy

Hi! As psyko_chewbacca says, you have made a nice layout. Mind sharing the yaml code for the page?

Hi
I just finished (or are we really ever finished) my project for the weekend.
The examples with this board are to few, so here is mine. Copy as you like but be aware. I am an infrequent user of the forum so don’t expect me to be able to answer much questions regarding this.

2 Likes

Thanks to both of you for the codes; very helpful. Have you guys had any issues with OTA updates? I just got this display, and OTA is nearly impossible—it has to be updated manually while connected to the PC.

I removed everything regarding the web-server, don’t need that. Before removing that OTA was not possible (timed out and was super slow). Now everything works fine and quick :).

Interesting, I’ve been having slow OTA speeds but found that if I touch the antenna on the ESP32 it goes very fast and times out if I don’t. I tried your suggestion of removing the web stuff but it didn’t help. I am interested if there are any other solutions to the problem as it is quite annoying. I will continue investigating though.

Hmmm maybe I am totally off then. I have mine mounted now on the wall with a cable running from the USB-C connector behind the board and out on the opposite end from where the USB-C connector is. So it is possible that the USB-C cable that is powering the device might actually be touching the ESP32 antenna since it is running behind the board. I can´t see that since it’s inside the 3D printed case. That seems like a really strange phenomenon though… :slight_smile:

btw this is v2 for me, slightly updated.

1 Like

Awesome, this is finally helped me update my code, which was cobbled together from what others had done a few months back.

I agree about the wifi reception, mine just looses connection sometimes, and OTA updates are very unreliable. I might try playing with it to see if I can attach a better antenna.

I did some tests on the wifi performance, it looks like the signal is being blocked by the backlight shield, if you unscrew the board and move it further away, the wifi performance improves a lot.

2 Likes

If it helps anyone, this screen works really well with openHASP(nightly build). I just flashed it today, did some basic configurations, and it works flawlessly—no Wi-Fi dropouts either! :slightly_smiling_face:

WiFi Improvement…
I unscrewed the board and unfolded it and the wifi worked fine. I tried to fix it back about 15mm further from the base plate but the performance dropped off again. then I tried extending the antenna as shown below…

not very pretty I know and it’s only stuck to the existing ESP32 antenna with some double sided nano tape - no direct electrical connection. Now works reliably.

Full details of this mod can be found here… ESP32 wifi mod

1 Like

Edit: Just read the last post. I’ll try that.

I’ve been having the same problem. Poor WIFI connectivity to Home Assistant, and slow or impossible OTA updates. Touching the ESP32’s antenna helps enormously, but that’s not terribly practical for a unit in an enclosure. Oddly, it seems to have very little to do with the reported signal strength. The one in the enclosure is only 12 feet from the router, reports -27dBm, and still can’t complete an OTA update!

I did mod one to use a real antenna, and it made no difference to the OTA situation.

Has anybody found a solution? Otherwise, I LOVE these things.

This worked for me. I used these little PCB antennas, from an old device and soldered them on. OTA updates are still slower than when I’m touching the built-in antenna, but at least they get there.


2 Likes

Hi i’m trying to get one of these going with a simple button for now. I plugged in via the uart 1 and uploaded the firmware from esphome but i get nothing. Any ideas? I have included the code below

Blockquote

substitutions:
  device_internal_name: waveshare-7inch
  device_friendly_name: Waveshare 7inch

esphome:
  name: ${device_internal_name}
  friendly_name: ${device_friendly_name}
  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
  on_boot:
    priority: 600  # Run early during boot
    then:
      - logger.log: "Device booted successfully"

psram:
  mode: octal
  speed: 120MHz

esp32:
  board: esp32s3box
  variant: ESP32S3
  flash_size: 8MB
  framework:
    type: esp-idf
    sdkconfig_options:
      COMPILER_OPTIMIZATION_SIZE: y
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_ESPTOOLPY_FLASHSIZE_8MB: "y"
      CONFIG_FREERTOS_HZ: "1000"
      CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240: y
      CONFIG_ESPTOOLPY_FLASHMODE_QIO: y
      CONFIG_ESPTOOLPY_FLASHFREQ_120M: y
      CONFIG_SPIRAM_MODE_OCT: y
      CONFIG_IDF_EXPERIMENTAL_FEATURES: y
      CONFIG_SPIRAM_SPEED_120M: y
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
      CONFIG_SPIRAM_RODATA: y
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: y
      CONFIG_COMPILER_OPTIMIZATION_PERF: y

# WiFi (with static IP)
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.100  # Choose an unused IP on your network
    gateway: 192.168.1.1      # Your router's IP
    subnet: 255.255.255.0     # Typically 255.255.255.0

# OTA
ota:
  - platform: esphome
    password: !secret ota_password

# Home Assistant API with encryption and renamed ID
api:
  id: ha_api
  encryption:
    key: ###############################################

# IO Extender
ch422g:
  - id: ch422g_hub

# I2C for touchscreen
i2c:
  sda: GPIO08
  scl: GPIO09
  scan: true
  id: bus_a

# Logger (set to VERY_VERBOSE for detailed debugging)
logger:
  baud_rate: 115200
  level: VERY_VERBOSE  # Keep high verbosity to debug crash

# Colors (from working config)
color:
  - id: my_red
    red: 100%
    green: 0%
    blue: 0%
  - id: my_yellow
    red: 100%
    green: 100%
    blue: 0%
  - id: my_green
    red: 0%
    green: 100%
    blue: 0%
  - id: my_gray
    red: 50%
    green: 50%
    blue: 50%
  - id: my_white
    red: 100%
    green: 100%
    blue: 100%
  - id: my_black
    red: 0%
    green: 0%
    blue: 0%

# Display setup
display:
  - platform: rpi_dpi_rgb
    id: my_display
    update_interval: never
    auto_clear_enabled: false
    color_order: RGB
    pclk_frequency: 16MHZ
    dimensions:
      width: 800
      height: 480
    de_pin:
      number: 5
    hsync_pin:
      number: 46
      ignore_strapping_warning: true
    vsync_pin:
      number: 3
      ignore_strapping_warning: true
    pclk_pin: 7
    pclk_inverted: true
    reset_pin:
      ch422g: ch422g_hub
      number: 3
    hsync_back_porch: 8
    hsync_front_porch: 8
    hsync_pulse_width: 4
    vsync_back_porch: 16
    vsync_front_porch: 16
    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

# Touchscreen (updated to match new config)
touchscreen:
  platform: gt911
  id: my_touch
  interrupt_pin: GPIO4
  reset_pin:
    ch422g: ch422g_hub
    number: 1
    mode: OUTPUT
  on_touch:
    - lambda: |-
        ESP_LOGI("Touch", "Touch detected at x=%d, y=%d", touch.x, touch.y);
  on_update:
    - lambda: |-
        for (auto touch: touches)  {
            if (touch.state <= 2) {
              ESP_LOGI("Touch points:", "id=%d x=%d, y=%d x.raw=%d, y.raw=%d", touch.id, touch.x, touch.y, touch.x_raw, touch.y_raw);
            }
        }

# LVGL setup with a single button
lvgl:
  displays: my_display
  touchscreens: my_touch
  buffer_size: 10%
  color_depth: 16
  pages:
    - id: main_page
      widgets:
        # Single Button: Table Light
        - button:
            id: table_button
            x: 20
            y: 20
            width: 200
            height: 100
            radius: 10
            bg_color: my_gray
            text_color: my_white
            on_click:
              then:
                - homeassistant.action:
                    action: light.toggle
                    data:
                      entity_id: light.table_light
            widgets:
              - label:
                  text: "Table Light"
                  align: center