Current version: v4.8.1
A smart touch panel to control Home Assistant using an ESP32-2432S028R (CYD - Cheap Yellow Display).
- Multi-page display: Dynamic screens with 8-second auto-cycling
- Weather Page: Current conditions with animated weather icon, outdoor temperature, rain, wind, snow, frost, and real-time Météo-France alerts (yellow/orange/red vigilance)
- 🌧️ Rain forecast: 9 colored rectangles showing minute-by-minute forecast (0–55 min) with intuitive color coding (empty=dry, light/medium/dark blue = light/moderate/heavy rain)
- Sensors Page: Temperature and humidity from up to 4 zones in a 2x2 grid layout
- Energy & Climate Page: Home power (W/kW), electricity cost today (€), air conditioning power (W/kW), and AC energy consumption (kWh)
- Media Page: Now Playing (Artist & Title) with automatic text wrapping and dynamic layout
- Printer Page: Real-time BambuLab status (file, progress, nozzle/bed temps, remaining time)
- Dynamic Pagination: Dots indicator adjusts automatically (3/4/5 dots) based on active pages (Media/Printer hidden when unused)
- Live Web Simulator & Screen Mirror:
- 🖥️ Interactive Simulator (
/screen): Realistic CYD device enclosure mockup with live auto-refresh (1s), touchscreen click simulation, quick navigation pills (Home, Sensors, Energy, Media, 3D), menu toggle, and latency telemetry. - 📷 Zero-RAM Framebuffer Stream (
/screenshot.bmp): Pixel-perfect 8-bit indexed BMP directly streamed over HTTP chunk by chunk from the display buffer. Ideal for Home Assistant picture entities or remote viewing without requiring PSRAM! - 🕹️ Control API (
/api/screen/page): Remote HTTP endpoints to switch pages (?page=N) or toggle the configuration menu (?action=toggle_menu).
- 🖥️ Interactive Simulator (
- Embedded Web Server: Modern ESPHome v3 responsive web dashboard accessible via browser (port 80)
- Control menu: Touch-activated, 8 configurable buttons to control Home Assistant entities (covers, lights, 3D printer)
- Clean interface without header to maximize button space
- Visual feedback with colored icons (blue = active, grey = inactive)
- Full internationalization (EN/FR/ES) via dedicated language files
- Easy Wi-Fi Setup & Zero-Friction Provisioning:
- 📷 On-Screen QR Code: When disconnected, the CYD automatically displays a QR code on screen. Scan with your smartphone camera to connect to the fallback hotspot (
CYD-HA-Fallback) and open the captive portal (http://192.168.4.1). - 🔌 Improv Serial USB Provisioning: Plug the CYD via USB and open web.esphome.io or the included Web Flasher in Chrome/Edge to send Wi-Fi credentials in 1 click without any phone.
- ℹ️ On-Screen IP Diagnostics: Assigned IP address is displayed on boot in the top header and at the bottom of the touch menu (
IP: 192.168.1.84 | v4.6.1).
- 📷 On-Screen QR Code: When disconnected, the CYD automatically displays a QR code on screen. Scan with your smartphone camera to connect to the fallback hotspot (
- Global header: Device name and date/time (DD/MM HH:MM) on data pages
- Responsive touch interface: Precise detection with XPT2046 calibration
- 👆 Dual-Mode Touch Navigation:
- Page display mode: Tap lower-right (dots area) for immediate Next Page, tap lower-left for Previous Page, or tap the upper 75% of the screen to open the 8-button control menu.
- Control menu mode: 8 configurable buttons with visual state feedback and 10s auto-return timeout.
- 👆 Dual-Mode Touch Navigation:
- High-Performance Architecture & Zero-RAM Overhead:
- Event-driven rain forecast byte cache (
cyd_ui.h) computed only on sensor updates, eliminating ~36 dynamic string allocations/sec from the 500ms rendering loop. - Dedicated modular UI engine (
cyd_ui.h) separating rendering logic from YAML orchestration.
- Event-driven rain forecast byte cache (
- Home Assistant Dynamic Controls & Customization:
- 🎛️ Live Customization from HA: Edit room block names (
text), select room icons (select), and tune temperature calibration offsets (number) directly from Home Assistant without recompiling or reflashing. - 🔄 Bidirectional Page Selector (
select): View the active screen page in real-time or force a specific page from Home Assistant automations (e.g. show 3D printer when printing starts). - ⏱️ Configurable Screen Timings: Adjust page auto-cycle speed (3-60s), toggle auto-cycle (
switch), and configure menu timeout directly from Home Assistant. - 💾 Flash NVS Persistence: All settings modified in Home Assistant persist across power cycles.
- 🧩 Optional Virtual Helpers Package: Map sensors through dynamic Home Assistant drop-down helpers (
input_select) to reassign rooms without touching firmware (seedocs/homeassistant_helpers.yaml).
- 🎛️ Live Customization from HA: Edit room block names (
- Secure connection: Encrypted API, password-protected OTA
- Modular architecture: Configuration split into clean, single-responsibility files for easy maintenance
- Auto-return: Automatic return to display cycle after menu inactivity
| ☀️ Weather & Alerts | 🌡️ Indoor Sensors | ⚡ Energy & Climate | 🔘 8-Button Touch Menu |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
A real-time digital twin accessible directly at http://<CYD_IP_ADDRESS>/screen or through the navigation banner on the ESPHome dashboard:
You can easily integrate your live CYD screen into Home Assistant dashboards:
Display the real-time CYD display buffer on any Lovelace dashboard:
- In Home Assistant, go to Settings → Devices & Services → Add Integration → Generic Camera.
- Configure:
- Still Image URL:
http://<CYD_IP_ADDRESS>/screenshot.bmp - Frame Rate:
1fps
- Still Image URL:
- Add a Picture Entity card to your dashboard:
type: picture-entity entity: camera.cyd_live_screen name: CYD Screen show_state: false tap_action: action: url url_path: http://<CYD_IP_ADDRESS>/screen
Embed the interactive touch simulator and remote page switcher directly in Home Assistant:
type: iframe
url: http://<CYD_IP_ADDRESS>/screen
aspect_ratio: 75%- ESP32-2432S028R (Cheap Yellow Display)
- ESP32 (240 MHz dual-core)
- ILI9342 320x240 TFT display (mipi_spi driver)
- XPT2046 touch controller
- Built-in RGB LED
- PWM backlight
cyd_HA/
├── cyd_ha.yaml # ✅ Main configuration file
├── cyd_ha_refactored.yaml # 🔄 Backward compatibility shim
├── cyd_ui.h # 🖥️ UI rendering engine, rain cache & navigation
├── cyd_screen_streamer.h # 📺 Live screen streamer & Web simulator
├── docs/ # 🖼️ Documentation & screenshots
│ └── images/
├── web_flasher/ # 🌐 ESP Web Tools browser installer
│ ├── index.html
│ └── manifest.json
├── cyd_ha/ # 📂 Module subfolder
│ ├── substitutions.yaml # ⚙️ All user configuration
│ ├── common.yaml # 🎨 UI resources (fonts, colors, icons)
│ ├── hardware.yaml # 🔧 Hardware config (SPI, touch, outputs)
│ ├── sensors.yaml # 📊 Home Assistant sensor integration
│ ├── buttons.yaml # 🔘 Touch zone definitions
│ ├── display_pages.yaml # 🖥️ Display setup & page orchestration
│ └── i18n/ # 🌍 Language packs
│ ├── en.yaml
│ ├── fr.yaml
│ └── es.yaml
├── secrets.yaml # 🔐 Credentials (shared across ESPHome projects)
├── secrets.yaml.example # 📄 Secrets template
├── esphome-build-upload.bat # 🪟 Windows build & flash script
├── esphome-build-upload.sh # 🐧 Linux/macOS build & flash script
├── materialdesignicons-webfont.ttf # 🎨 Weather icon font
├── CHANGELOG.md # 📝 Version history
└── README.md # 📖 This file
- ESPHome installed
- Working Home Assistant with API enabled
- USB connection to ESP32
Copy the template secrets.yaml.example to secrets.yaml (protected by .gitignore):
cp secrets.yaml.example secrets.yamlFill in your actual Wi-Fi and Home Assistant API credentials:
# Global WiFi (shared)
wifi_ssid: "YOUR_SSID"
wifi_password: "YOUR_WIFI_PASSWORD"
# Project-specific secrets (prefixed with "cyd_ha")
cyd_ha_api_encryption_key: "YOUR_API_KEY"
cyd_ha_ota_password: "YOUR_OTA_PASSWORD"Copy the template cyd_ha/substitutions.yaml to cyd_ha/substitutions.local.yaml (auto-created by the build scripts and protected by .gitignore):
cp cyd_ha/substitutions.yaml cyd_ha/substitutions.local.yamlTip
Why substitutions.local.yaml?
This file is ignored by Git. All your customized Home Assistant entity IDs, room names, and private settings are safely kept on your machine and will never be committed or exposed if you push changes or share your repo.
Customize your entities, language, and Wi-Fi fallback credentials in cyd_ha/substitutions.local.yaml:
# ─── Language (uncomment ONE line only) ───────────────────────
<<: !include i18n/fr.yaml
# <<: !include i18n/en.yaml
# <<: !include i18n/es.yaml
# ─── Device ──────────────────────────────────────────────────
device_name: cydhapanel
device_friendly_name: CYD HA Panel
# ─── Fallback Wi-Fi AP & Captive Portal ───────────────────────
wifi_ap_ssid: "CYD-HA-Fallback"
wifi_ap_password: "CHANGE_ME_PASSWORD" # Min 8 chars (for QR code & AP)
# ─── Location ────────────────────────────────────────────────
location_name: Paris
# ─── Weather ─────────────────────────────────────────────────
weather_entity: weather.paris
rain_chance_entity: sensor.paris_rain_chance
# ... more entities
# ─── Media Player ────────────────────────────────────────────
media_player_entity: media_player.example
# ─── Sensor Blocks (up to 4) ─────────────────────────────────
sensor_bloc1_temp_entity: sensor.living_room_temperature
sensor_bloc1_hum_entity: sensor.living_room_humidity
sensor_bloc1_icon: hometemperature
# ... repeat for bloc2, bloc3, bloc4 (use sensor.none to disable)
# ─── Energy & Climate (up to 4 blocks) ───────────────────────
energy_power_entity: sensor.home_power_w
energy_cost_entity: sensor.electricity_cost_today_eur
ac_power_entity: sensor.ac_power_w
ac_energy_entity: sensor.ac_energy_today_kwh
# ─── Menu Buttons ────────────────────────────────────────────
btn1_service: cover.open_cover
btn1_entity: cover.living_room_blinds
# ... configure all 7 buttonsDownload MaterialDesignIcons (auto-downloaded by the build scripts)
# Compile and upload
esphome run cyd_ha.yamlOr use the helper scripts:
Windows:
esphome-build-upload.batLinux / macOS:
./esphome-build-upload.sh # OTA upload
./esphome-build-upload.sh -u # USB uploadEdit cyd_ha/common.yaml:
color:
- id: blue
hex: 'F39621' # Change this value (BGR format)- Find icon on Material Design Icons
- Add to
cyd_ha/common.yaml:
image:
- file: mdi:YOUR_ICON
id: my_icon
resize: 40x40
type: BINARYThe UI uses dedicated language packs.
Available packs: en.yaml, fr.yaml, es.yaml
Activate by uncommenting ONE line at the top of cyd_ha/substitutions.yaml:
<<: !include i18n/en.yaml # ← English
# <<: !include i18n/fr.yaml
# <<: !include i18n/es.yamlTranslated keys:
- Page titles:
i18n_weather_title,i18n_sensors_title,i18n_printer_title - Menu buttons:
btn1_labeltobtn8_label - Sensor blocks:
sensor_bloc1_labeltosensor_bloc4_label - Rain messages:
i18n_next_rain_prefix,i18n_next_rain_none
- Check
secrets.yaml(correct SSID/password) - 5GHz WiFi is not supported (use 2.4GHz)
- Adjust calibration in
cyd_ha/hardware.yaml:
touchscreen:
calibration:
x_min: 280
x_max: 3860
y_min: 280
y_max: 3860- Verify
entity_idinsubstitutions.yamlmatches Home Assistant entities - Check API connection in Home Assistant
Home Assistant API
↓
cyd_ha/sensors.yaml (import entities)
↓
cyd_ha/display_pages.yaml (rendering with 8s auto-cycle)
↓
ESP32 Display (mipi_spi - ESP32-2432S028-9342, 270° rotation)
Dynamic Pages with auto-cycling (8s):
┌─────────────────────────────────────┐
│ Page 0: Weather │
│ - Large animated weather icon │
│ - Météo-France alerts (🔴🟠🟡) │
│ - Rain forecast: 9 colored bars │
│ - "Next rain: X min" text │
│ - Temp/Rain/Wind/Snow/Frost grid │
├─────────────────────────────────────┤
│ Page 1: Home Sensors │
│ - 4 blocks in 2x2 grid │
│ - Each: icon + label + temp + hum │
├─────────────────────────────────────┤
│ Page 2: Energy & Climate │
│ - 4 blocks in 2x2 grid │
│ - Home power (W/kW), cost (€) │
│ - AC power (W/kW), AC energy (kWh) │
├─────────────────────────────────────┤
│ Page 3: Media Player (conditional) │
│ - Artist & Title text wrap │
│ - Playing / Paused status │
├─────────────────────────────────────┤
│ Page 4: BambuLab Printer (cond.) │
│ - Scrolling filename │
│ - Progress bar with percentage │
│ - Status / Time remaining / End │
│ - Nozzle/Bed temperatures │
└─────────────────────────────────────┘
Touch anywhere → 8-button menu (10s timeout)
See CHANGELOG.md for version history.
To improve this project:
- Test on your hardware
- Report bugs via issues
- Suggest improvements
- Share your custom configurations
This project is licensed under the GNU General Public License v2.0. You are free to use, modify, and distribute this software under the terms of the GPL v2.
This project was inspired by the excellent tutorial from Aguacatec:
Made with ❤️ for the Home Assistant community




