Waveshare 3.5″ Touch IPS Display

This project aims to create a low-cost, wall-mounted smart home dashboard using an ESP32‑S3 with a touchscreen, fully integrated into Home Assistant via ESPHome. The goal is to have a responsive, multi-page interface in the kitchen that can display energy consumption, sensor statuses, door/window contacts, or any other data relevant to your home.

I’ve invested a lot of time getting this setup running, studying countless blog articles, reading forum discussions, and researching various approaches. I want to share my findings here with the community to give back and help others who are working on similar projects.

Technical Requirements

  • ESP32‑S3 based board with Wi-Fi and touchscreen support
  • Compatible with ESPHome
  • Communication via ESPHome native API
  • UI rendered directly on the device using the touchscreen
  • Must work offline once paired with Home Assistant
  • OTA updates supported
  • Hardware cost below typical tablet solutions
  • Enough RAM for multiple pages and graphics
  • Powered via USB or 5V

Why I Chose the Waveshare 3.5″ Touch IPS Display

For this multi-page smart home dashboard, I wanted a display that combined clarity, versatility, and expandability. The Waveshare 3.5″ Capacitive IPS Touch Display stood out for several reasons:

  • 3.5″ Capacitive IPS Touchscreen – 320×480 resolution with ~262K colors provides a clear, vibrant interface ideal for dashboards with multiple pages.
  • ESP32‑S3R8 Dual-Core MCU – 240 MHz processing power ensures smooth UI updates, sensor polling, and optional audio or camera tasks.
  • Onboard Camera Interface – Supports OV2640/OV5640 modules for potential future expansions, such as visual monitoring or computer vision.
  • Expanded Connectivity – TF card slot, RTC, IMU, audio codec, and USB‑C enable multimedia, sensor data logging, and additional peripherals.
  • Flexible Development – Compatible with both ESP‑IDF and Arduino IDE, allowing easy integration with ESPHome and custom firmware.

Target Device: Waveshare Touch IPS 3.5″ 320×480

  • Size: 3.5″
  • Resolution: 320×480
  • Colors: 262K
  • Panel: IPS
  • Display Interface: SPI
  • Touch Interface: I2C
  • Shape: Rectangular

This combination of performance, display quality, and peripheral support made the Waveshare board the clear choice for a reliable, expandable smart home dashboard in the kitchen.

Choosing an ESPHome GUI Designer

For designing the user interface on my ESP32‑S3 projects, I evaluated two web-based ESPHome GUI tools:

  • ESPHome LVGL Designer – A modern tool tailored for LVGL integration, offering a polished workflow for creating complex UI layouts.
  • ESPHome Designer by Koosoli – A simpler, lightweight web-based interface designer compatible with ESPHome YAML configurations.

After testing both, I opted for Koosoli’s ESPHome Designer. The decision was driven by ease of use, faster prototyping, and direct YAML export, which fits my workflow better. While the LVGL Designer is powerful for more advanced graphics, I preferred the minimal overhead and straightforward approach of the Koosoli tool for my current ESP32‑S3 projects.

Default Settings and Hardware Configuration

For a stable and responsive multi-page dashboard on the ESP32‑S3, it’s important to configure the board and firmware correctly from the start. ESPHome allows setting defaults for boot behavior, memory usage, and additional hardware like audio.

  • Device identity – Set name and friendly_name for Home Assistant integration.
  • On boot actions – Use on_boot to start scripts (e.g., auto page cycling) and turn on the backlight at a defined brightness.
  • Board selection – Choose esp32-s3-devkitc-1 for proper pin mapping and PSRAM support.
  • Framework and PSRAM – ESP-IDF with execute_from_psram: true improves stability on high-resolution displays; PSRAM in octal mode at 80 MHz is recommended for multi-page dashboards.
  • Flash size – 16 MB flash ensures room for firmware, multiple pages, and assets.
  • Audio support – I2S audio can be configured for sound output using GPIO pins for LRCLK and BCLK.

Example ESPHome configuration:

# ============================================================================
# TARGET DEVICE: Waveshare Touch IPS 3.5 3.5" 320x480
# Name: Waveshare Touch IPS 3.5 3.5" 320x480
# Link: https://www.waveshare.com/3.5inch-capacitive-touch-lcd.htm
# Size: 3.5"
# Resolution: 320x480
# Display Color: 262K
# Display Panel: IPS
# Display Interface: SPI
# Touch Interface: I2C
# Shape: rect
#
# - Display Platform: ST7796S
# - Touchscreen: FT6336U
# - PSRAM: Yes
# ============================================================================


esphome:
name: "${name}"
friendly_name: "${friendly_name}"
on_boot:
priority: -100
then:
- script.execute: auto_cycle_timer
- light.turn_on:
id: display_backlight
brightness: 0.7 # 70%

esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
# For stability on S3 devices with high-res displays/LVGL:
advanced:
execute_from_psram: true
flash_size: 16MB

# PSRAM is strongly recommended for larger screens
psram:
mode: octal
speed: 80MHz

# Audio Output über I2S
i2s_audio:
id: i2s_speaker
i2s_lrclk_pin: GPIO17
i2s_bclk_pin: GPIO18

These defaults ensure that the ESP32‑S3 boots reliably, the dashboard pages and backlight are initialized automatically, and additional hardware like PSRAM and audio work without manual intervention.

Backlight Control with PWM

The Waveshare 3.5″ ESP32‑S3 display includes a backlight that can be dimmed using PWM from the ESP32. Controlling brightness with ESPHome keeps the display readable while saving power and reducing glare in the kitchen or other rooms.

  • LEDC platform – ESPHome uses the ledc output to generate a PWM signal.
  • Brightness control – Assign the PWM output to a monochromatic light component for easy integration.
  • Restore mode – Setting restore_mode: ALWAYS_ON ensures the backlight turns on automatically after a reboot.
  • Pin caution – Avoid strapping pins (GPIO45 and GPIO46) to prevent boot issues.

Example configuration:

# Backlight PWM output and light component
# Do not use Strapping-Pins GPIO45 and GPIO46 
output:
  - platform: ledc
    pin: GPIO06
    id: GPIO06
    frequency: 2000
    channel: 0light:
  - platform: monochromatic
    output: GPIO06
    name: Display Backlight
    id: display_backlight
    restore_mode: ALWAYS_ON    # I2C bus for touch controller and GPIO expander

This setup provides smooth, reliable backlight control for your multi-page dashboard, ensuring the display is always visible and responsive to ambient conditions.

Using the PCA9554 GPIO Expander

The Waveshare 3.5″ ESP32‑S3 display uses a PCA9554 I2C GPIO expander to handle some control lines like display reset and chip select. This frees up ESP32 pins and matches the display’s hardware wiring.

  • I2C connected – The PCA9554 communicates over the same I2C bus as the touch controller.
  • ESPHome support – You can assign display reset and CS pins to the PCA9554 in the YAML configuration.
  • Reliable initialization – Without configuring the PCA9554, the display may not initialize correctly or could behave unpredictably.

Example configuration in ESPHome:

# PCA9554 GPIO expander for display reset/chip select
pca9554:
  - id: p_c_a
    address: 0x20
    i2c_id: i2c_bus# SPI bus for display

This setup ensures the SPI display works reliably while keeping the ESP32’s GPIOs available for other sensors or outputs.

Touchscreen Orientation and Transformation

The Waveshare 3.5″ ESP32‑S3 touchscreen (FT6336) may report X and Y coordinates differently depending on how the display is mounted. ESPHome allows transforming the touch input to match your layout using swap_xy, mirror_x, and mirror_y.

  • swap_xy: true/false – Swap X and Y axes if the touch seems rotated relative to the display.
  • mirror_x / mirror_y: true/false – Flip coordinates along the respective axis if touch feels mirrored.

Example ESPHome configuration:

# I2C bus for touch controller
i2c:
- id: i2c_bus
sda: 8
scl: 7
scan: true# FT6336 touchscreen

# FT6336 touch controller
touchscreen:
platform: ft63x6
id: my_touch
transform:
swap_xy: true
mirror_x: false
mirror_y: true

on_touch:
- lambda: |-
// Page navigation by touch zones
if (touch.x >= 0 && touch.x <= 80 && touch.y >= 240 && touch.y <= 320) {
if (id(display_page) > 0)
id(change_page_to).execute(id(display_page) - 1);
} else if (touch.x >= 400 && touch.x <= 480 && touch.y >= 240 && touch.y <= 320) {
if (id(display_page) < 1)
id(change_page_to).execute(id(display_page) + 1);

This ensures that taps, swipes, and page navigation behave intuitively, regardless of how the display is installed. It’s especially useful for multi-page dashboards or kitchen-mounted screens where the orientation may differ from default.

Display Color Order and Configuration

For the Waveshare 3.5″ ESP32‑S3 display with ST7796 controller, the color order and pixel format matter for proper rendering. The display supports RGB or BGR ordering, and the ESPHome configuration must match the hardware.

  • BGR vs RGB – The Waveshare display defaults to BGR. If the colors look swapped (reds/greens incorrect), set color_order: bgr in ESPHome.
  • Pixel mode – Use pixel_mode: 16bit for efficient color depth without overwhelming the ESP32‑S3’s RAM.
  • Invert colors – Sometimes the panel is inverted by default; use invert_colors: true if needed.
# SPI bus for display
spi:
  id: display_spi
  clk_pin: GPIO05
  mosi_pin: GPIO01
  miso_pin: GPIO02# ST7796 display

# ST7796 display
display:
  - platform: mipi_spi
    model: st7796
    id: my_display
    spi_id: display_spi
    cs_pin:
      pca9554: p_c_a
      number: 2
    dc_pin: 3
    reset_pin:
      pca9554: p_c_a
      number: 1
    rotation: 90
    spi_mode: 1
    color_order: bgr
    pixel_mode: 16bit
    invert_colors: true
    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);
        ...

This ensures accurate colors, good performance, and consistent rendering across all UI pages.

Case and Assembly

I chose a 3D-printable case for the Waveshare 3.5″ ESP32‑S3 display with battery and MagSafe. The display, connectors, and battery fit neatly without trimming, leaving the assembly compact and tidy.

I printed it in black PLA with 0.2 mm layer height, 6 walls, and 25 % infill. The result is sturdy and professional-looking. A big thanks to PixelWave, the creator of this case.

View the case on MakerWorld