Waveshare ESP32-P4-WIFI6-Touch-LCD-7B working config

There are no significant new features in the initial move to 9.4 to simplify the switchover. Things like other colour depths will be added after that.

2 Likes

Thank you!

Thanks for the work - and confirming - I really was barking up the wrong tree on this one.

I think I am done with the final iteration of my library. You can now truly build a button on an ESP32 screen that controls a light in Home Assistant with one line of code.

This is what it looks like

packages:
  button_1: !include
    file: esphome-modular-lvgl-buttons/buttons/switch_button.yaml
    vars:
      uid: button_1
      row: 0
      column: 0
      text: Light
      icon: $mdi_lightbulb
      entity_id: "switch.athom_smart_plug_v3_50ebc0_switch"

All you need after that is a simple LVGL grid to put the button on that looks like this.

lvgl:
  pages:
    - id: main_page
      layout: 4x4
      styles: page_style
      <<: !include esphome-modular-lvgl-buttons/widgets/swipe_navigation.yaml
      widgets:

The beauty of all this is the simplicity and flexibility. A novice can create their first screen and control a light in 20 seconds and an advanced programmer can mix a few simple prebuilt buttons on a screen with complicated ones that they design from scratch.

4 Likes

I guess i have to update my configuration :grimacing: :joy: :joy:

This code doesn’t work - looks like the code was double pasted.

I couldn’t get the screen to display basic text even after fixing the typos, after several hours of debugging, I have a working version in ESPHome 2026.1.5. The key was adding reset_pin 33 to the display block.

I was able to get the Modular buttons Git repository working with some effort.

esphome:
  name: waveshare-esp32-p4-touch-lcd-7b
  friendly_name: "Waveshare P4 7B"

esp32:
  variant: esp32p4
  flash_size: 32MB
  cpu_frequency: 360MHz
  framework:
    type: esp-idf
    advanced:
      enable_idf_experimental_features: true
    sdkconfig_options:
      CONFIG_SPIRAM_SPEED_200M: y
      CONFIG_ESP_TASK_WDT_TIMEOUT_S: "60"

external_components:
  - source: github://pr#11886
    components: [mipi_dsi]
    refresh: 1h

esp32_hosted:
  variant: ESP32C6
  reset_pin: GPIO54
  cmd_pin: GPIO19
  clk_pin: GPIO18
  d0_pin: GPIO14
  d1_pin: GPIO15
  d2_pin: GPIO16
  d3_pin: GPIO17
  active_high: true

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

api:
ota:
  - platform: esphome

logger:
  hardware_uart: USB_SERIAL_JTAG

web_server:
  port: 80
  version: 3

psram:
  mode: hex
  speed: 200MHz

preferences:
  flash_write_interval: 5min

esp_ldo:
  - voltage: 2.5V
    channel: 3

i2c:
  - id: bus_a
    sda: GPIO07
    scl: GPIO08
    frequency: 400kHz

touchscreen:
  - platform: gt911
    id: my_touchscreen
    i2c_id: bus_a
    reset_pin: GPIO23
    update_interval: 50ms
    transform:
      swap_xy: false
      mirror_x: false
      mirror_y: false
    # Enabled Touch Logger here
    on_touch:
      - logger.log:
          format: "Touch at (%d, %d)"
          args: [touch.x, touch.y]
      - lambda: |-
          ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%d",
          touch.x,
          touch.y,
          touch.x_raw,
          touch.y_raw
          );

output:
  - platform: ledc
    id: gpio_backlight_pwm
    pin: GPIO32
    inverted: true
    frequency: 1000Hz

light:
  - platform: monochromatic
    output: gpio_backlight_pwm
    name: "Display Backlight"
    id: display_backlight
    restore_mode: ALWAYS_ON
    default_transition_length: 250ms

display:
  - platform: mipi_dsi
    id: my_display
    model: WAVESHARE-ESP32-P4-WIFI6-TOUCH-LCD-7B
    reset_pin:
      number: 33
    rotation: 180
    update_interval: never
    auto_clear_enabled: false
    dimensions:
      width: 1024
      height: 600

lvgl:
  buffer_size: 100%
  byte_order: little_endian
  pages:
    - id: main_page
      bg_color: 0x000000
      widgets:
        - label:
            text: "Hello World!"
            text_color: 0xFFFFFF
            align: CENTER
            text_font: montserrat_40

Are you using this test code here?

It works and give you a few test buttons. I tested this code recently with 2026.1.5 and it works well.

That demo file also has the Home Assistant Voice Assistant enabled and working.

The code in post #4 in this thread doesn’t work:

The modular buttons code works ok; my Git pull missed a couple of files for some reason - took a while to troubleshoot.

I want to make some improvements to the modular buttons package - I’ll post on Git; number one is modular cover control for the blinds in my house.

I just updated esphome-modular-lvgl-buttons recently. So refresh you git pull to get the latest.

I am making Voice Assistant modular as well so you can include it or not with one line of code.

That would be amazing! Send me a pull request and I’ll add it to esphome-modular-lvgl-buttons

Will do!

Messing around with the voice assistant now. The file fails to validate when including the voice assistant - ā€œmy_microphone not definedā€. esp32_microphone is defined in the hardware file, but I can’t find my_microphone defined anywhere.

It validates fine with this, but not far along enough to determine if it works:

Thanks, I just updated that. I fixed it for all six esp32-p4 screens that I support…

guition-esp32-p4-jc1060p470.yaml
guition-esp32-p4-jc4880p443.yaml
guition-esp32-p4-jc8012p4a1.yaml
waveshare-esp32-p4-86-panel.yaml
waveshare-esp32-p4-wifi6-touch-lcd-10.1.yaml
waveshare-esp32-p4-wifi6-touch-lcd-7b.yaml

2 Likes

2026.2.0 adds full support for this screen. I just updates my demo code for it to use the released driver for the screen.

1 Like

Has anyone had success configuring portrait mode for this device? In portrait mode, it fits perfectly inside the cut-out for the Nutone intercom system I’m removing; but has to be raised above the wall in landscape mode.

After rotating the config 90 degrees, it still thinks the x is 1024 and the y is 600. The touch is stretched / displaced, and the screen display is also stretched / displaced.

hardware file:

---

substitutions:
  # --- Defaults ---
  orientation: landscape
  flipped: "false"

  # --- Dimension Logic ---
  width_landscape: "1024"
  height_landscape: "600"
  width_portrait: "600"
  height_portrait: "1024"
  
  screen_width: "${width_${orientation}}"
  screen_height: "${height_${orientation}}"
  
  # --- Rotation & Touch Logic ---
  rotation_landscape_false: "180"
  rotation_landscape_true: "0"
  rotation_portrait_false: "270"
  rotation_portrait_true: "90"
  
  # Touch Swap: Only true for portrait modes
  s_landscape_false: "false" #ok
  s_landscape_true: "false" #ok
  s_portrait_false: "true"
  s_portrait_true: "true"

  # --- TOUCH MAPPING OVERRIDES ---
  # Change if touch is "backwards" or "inverted"
  # Landscape TUNING:
  mx_landscape_false: "false"
  my_landscape_false: "false"
  mx_landscape_true: "true"
  my_landscape_true: "true"

  # PORTRAIT TUNING:
  mx_portrait_false: "false"
  my_portrait_false: "true"
  mx_portrait_true: "true"
  my_portrait_true: "false"

  # Apply the keys
  screen_rotation: "${rotation_${orientation}_${flipped}}"
  touch_swap: "${s_${orientation}_${flipped}}"
  touch_mirror_x: "${mx_${orientation}_${flipped}}"
  touch_mirror_y: "${my_${orientation}_${flipped}}"

esphome:
  min_version: 2026.2.0
  project:
    name: "Waveshare.ESP32-P4-WIFI6-Touch-LCD-7B"
    version: "1.0"

esp32:
  variant: esp32p4
  flash_size: 32MB
  cpu_frequency: 360MHz
  framework:
    type: esp-idf
    advanced:
      enable_idf_experimental_features: true

esp32_hosted:
  variant: ESP32C6
  reset_pin: GPIO54
  cmd_pin: GPIO19
  clk_pin: GPIO18
  d0_pin: GPIO14
  d1_pin: GPIO15
  d2_pin: GPIO16
  d3_pin: GPIO17
  active_high: true

psram:
  mode: hex
  speed: 200MHz

preferences:
  flash_write_interval: 5min

esp_ldo:
  - voltage: 2.5V
    channel: 3

# -------------------------------------------
# Touchscreen gt911 i2c
# -------------------------------------------
i2c:
  - id: bus_a
    sda: GPIO07
    scl: GPIO08
    frequency: 400kHz
    scan: true

touchscreen:
  - platform: gt911
    id: my_touchscreen
    i2c_id: bus_a
    reset_pin: GPIO23
    update_interval: 32ms
    display: main_display
    transform:
      swap_xy: ${touch_swap}
      mirror_x: ${touch_mirror_x}
      mirror_y: ${touch_mirror_y}
    on_touch:
      - logger.log:
          format: "Touch at (%d, %d)"
          args: [touch.x, touch.y]
      - lambda: |-
          ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%d",
            touch.x,
            touch.y,
            touch.x_raw,
            touch.y_raw
          );

# -------------------------------------------
# Backlight
# -------------------------------------------
output:
  - platform: ledc
    id: gpio_backlight_pwm
    pin: GPIO32
    inverted: true
    frequency: 1000Hz

light:
  - platform: monochromatic
    output: gpio_backlight_pwm
    name: Display Backlight
    icon: mdi:lightbulb-on
    id: display_backlight
    restore_mode: ALWAYS_ON
    default_transition_length: 250ms

# -------------------------------------------
# Display
# -------------------------------------------
display:
  - platform: mipi_dsi
    id: main_display
    model: WAVESHARE-ESP32-P4-WIFI6-TOUCH-LCD-7B
    reset_pin:
      number: 33
    rotation: ${screen_rotation}
    update_interval: never
    auto_clear_enabled: false
    dimensions:
      width: ${screen_width}
      height: ${screen_height}

# Special LVGL settings required for this display  
lvgl:
  byte_order: little_endian

# -------------------------------------------
# Audio devices
# -------------------------------------------

# ===== Amplifier Control =====
switch:
  - platform: gpio
    pin: GPIO53  # BSP_POWER_AMP_IO
    name: "Audio Amplifier"
    id: audio_amplifier
    restore_mode: ALWAYS_OFF

# ===== ES8311 Audio Codec Configuration =====
i2s_audio:
  - id: audio_bus
    i2s_mclk_pin: GPIO13
    i2s_lrclk_pin: GPIO10
    i2s_bclk_pin: GPIO12

audio_dac:
  - platform: es8311
    id: es8311_dac
    i2c_id: bus_a
    address: 0x18

audio_adc:
  - platform: es7210
    id: es7210_adc
    i2c_id: bus_a
    address: 0x40

# ===== Microphone =====
microphone:
  - platform: i2s_audio
    id: esp32_microphone
    i2s_audio_id: audio_bus
    i2s_din_pin: GPIO11
    sample_rate: 16000
    bits_per_sample: 16bit
    adc_type: external
    # on_data:
    #   - logger.log:
    #       format: "Microphone data received: %d bytes"
    #       args: [x.size()]

# ===== Speaker & Audio Pipeline =====
speaker:
  - platform: i2s_audio
    id: esp32_speaker
    i2s_audio_id: audio_bus
    i2s_dout_pin: GPIO9
    audio_dac: es8311_dac
    dac_type: external
    channel: mono
    buffer_duration: 100ms
    bits_per_sample: 16bit
    sample_rate: 48000

  - platform: mixer
    id: mixing_speaker
    output_speaker: esp32_speaker
    source_speakers:
      - id: announcement_mixing_input
        timeout: never
      - id: media_mixing_input
        timeout: never

  - platform: resampler
    id: announcement_resampling_speaker
    output_speaker: announcement_mixing_input
    sample_rate: 48000
    bits_per_sample: 16

  - platform: resampler
    id: media_resampling_speaker
    output_speaker: media_mixing_input
    sample_rate: 48000
    bits_per_sample: 16

Test code:

# Substitution variables used through the codebase
substitutions:
  orientation: portrait
  #flipped: "true"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: yes
  min_auth_mode: wpa2
  ap:
    ssid: chicken-coop
    password: !secret wifi_fallback_password

captive_portal:

web_server:
  port: 80
  version: 3

api:
  encryption:
    key: !secret api_key_display-den # Get this from the ESPHome dashboard

ota: # Merge with the OTA file. This will cause a validation warning - safe to ignore
  - platform: esphome
    password: !secret ota_password_display-den

esphome:
  name: "display-den"
  friendly_name: "Den Display"
  comment: "Waveshare ESP32-P4 WiFi6 Touch LCD 7B 1024px X 600px Smart Screen"

logger:
  level: debug
  logs:
    lvgl: info
  hardware_uart: UART0
  
# Some screens need little_endian byte order and some need big_endian
# this sets the byte order for all the images loaded in this file and the packages as well
image:
  defaults:
    byte_order: little_endian  
          
packages:

  # Harware description file
  hardware: !include esphome-modular-lvgl-buttons/hardware/waveshare-esp32-p4-wifi6-touch-lcd-7b.yaml

# This is the main LVGL section. We start with a simple grid.
lvgl:
  buffer_size: 100%
  width: 600
  height: 1024
  displays:
    - main_display

  pages:
    - id: main_page
      widgets:
        - button:
            id: simple_test_button
            width: 200
            height: 100
            x: 500
            y: 300
            widgets:
              - label:
                  text: "HELLO"
                  align: center

The most success after a couple of days trying is this calibration block in the hardware file, it makes the touchscreen x work, but not the y or the display:

touchscreen:
  - platform: gt911
    id: my_touchscreen
    i2c_id: bus_a
    reset_pin: GPIO23
    update_interval: 32ms
    display: main_display
    # Fix for stretching bug?
    calibration:
      x_min: 0
      x_max: 1024
      y_min: 0
      y_max: 600

I have it working this is my code

touchscreen:
  - platform: gt911
    id: my_touchscreen
    i2c_id: bus_a
    reset_pin: GPIO23
    update_interval: 50ms
    transform:
      swap_xy: true
      mirror_x: true
      mirror_y: false


display:
  - platform: mipi_dsi
    id: main_display
    model: WAVESHARE-ESP32-P4-WIFI6-TOUCH-LCD-7B
    rotation: 90
    reset_pin:
      number: 33
    update_interval: never
    auto_clear_enabled: false

But the performance is terrible! mipi_sdi displays do not have hardware rotation so this is implemented in software. Screen is very laggy and unresponsive in this mode.

Unfortunately the best way to do screen rotation would be to use the 2D hardware graphics capabilities of the P4 but there is no ESPHome drive for this yet.

That’s really funny. That is exactly what I am using the screen for as well! I’m going to see if I can power it using the old wires from the intercom. They go to the basement so I can attach 12v to them.

That’s really funny. That is exactly what I am using the screen for as well! I’m going to see if I can power it using the old wires from the intercom. They go to the basement so I can attach 12v to them.

It’s very simple / easy to do - here are some pics. Happy to share the 3D printed parts.

The main Nutone panel has 120v power and a transformer. I connected a 120v to 12v DC power supply, then 12v to 5v USB at the remote station. I’ll do a standalone post once all running.

I’m planning a 10" display on the main station, and 7" display on the remote stations. Using landscape mode isn’t terrible - gives space to mount a speaker and sensors. I’m planning a mmWave sensor and temperature / humidity sensor to start.




Looks great! If you put the screen the way you have it now you have room for a speaker.

What case is that?

Self designed / printed; still a work in progress. I’m planning to use the standard speaker included in the waveshare box.

Nice, I am working on a lot of projects like this. Check out my button library if you have not already. I have a lot of prebuilt widgets for a screen like this. I will have a media player soon.

That board and other P4 based boards should include all sorts of cool stuff in the future including video playback.

A hardware mod you might consider is a brightness sensor. I have a part of my library that trys to get the screen brightness so it’s not annoying but I really need to have it respond to room light level.

lux sensors are cheap. Thanks.

I looked through the button library - really appreciate your work. I’m starting with the mechanicals and basic room controls to start.

I would like to do an audio intercom eventually also. I don’t use cameras inside my house, but audio only would be nice.