ESPHomeHome Assistant

Now-playing screen on a Cheap Yellow Display

A Cheap Yellow Display shows album art, title, and artist while a Home Assistant media player is playing, with touch play/pause and next, then falls back to a clock.

Difficulty · IntermediateSetup · 45–75 minutesHA · 2024.10 or newerESPHome · 2026.10
Get the pack · from $19Have us set it up

Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.

A speaker that is playing should not make you open a phone to see the track. This firmware puts that on the 320×240 panel of an ESP32-2432S028R, the usual one-USB Cheap Yellow Display. While the media player you name is playing, the screen shows album art, title, artist, a progress bar, and two touch targets. After it has been idle, the same panel is a clock with the room temperature and a weather line.

The same board, used as a wall of buttons or as a thermostat, is CYD touch control panel, CYD touch thermostat, and CYD desk companion. This one only watches a media player.

ha_base_url in the file is https://home.example.com. Replace it with the URL Home Assistant uses for /api/media_player_proxy/... pictures. Do not publish that URL, and do not publish the long-lived token.

What problem it solves

You want the track that is playing, on the desk, from whatever media player Home Assistant already has, and a clock when nothing is playing.

How it works

ESPHome draws two LVGL pages. Home Assistant is the source of the player, the temperature, and the weather. The display does not talk to a speaker’s own web page.

  1. Player — a substitution names one media_player. When its state becomes playing, the backlight goes to full and the playing page is shown. Any other state starts an idle timer (pack default 45 seconds). When that timer finishes, the backlight drops to 40% and the clock page is shown.
  2. Art — entity_picture is loaded as a 120×120 JPEG. A path that already starts with http is used as-is. A relative path is prefixed with ha_base_url. The request sends the token from secrets.yaml as Authorization. TLS verification is off so a local certificate still loads. A missing picture stays on the placeholder URL and does not block the title.
  3. Text and progress — title and artist update when those attributes change. Every 5 seconds the progress bar is media_position / media_duration. A player with no duration leaves the bar at zero.
  4. Touch — Play calls media_player.media_play_pause. Next calls media_player.media_next_track. Both go through the ESPHome device connection, so the device has to be allowed to perform Home Assistant actions. There is no previous button.
  5. Clock page — SNTP time as HH:MM, the temperature substitution, and the weather entity’s state plus its temperature attribute. The clock page is the one shown at boot.

Wi-Fi, the API key, OTA, and the token stay in secrets.yaml.

Hardware notes

  • Board. Stock one-USB resistive CYD. Display is MIPI SPI, model ILI9341, color order BGR. SPI clock GPIO14, MOSI GPIO13, MISO GPIO12, CS GPIO15, DC GPIO2. Backlight is LEDC on GPIO21. Touch is XPT2046 on a second SPI bus: clock GPIO25, MOSI GPIO32, MISO GPIO39, CS GPIO33, interrupt GPIO36. Rotation is 90, which matches the USB socket on the right for the usual case.
  • Other CYDs. A two-USB board or an ST7789 panel needs a different display model and pin map. This file does not cover those. If touch is mirrored, flip touch_mirror_x or touch_mirror_y and reflash.
  • Power. USB is enough. The panel is not a battery device. Later updates can be OTA.
  • Player. Any media_player that exposes entity_picture, media_title, and media_artist. A player that omits art still shows the text. Play and Next only work if that player implements those actions.
  • Token. Create a long-lived access token under your profile in Home Assistant. The secrets example expects the value to start with Bearer , including the space. Store it only in secrets.yaml.

Snippet

Names and the base URL are substitutions. The pages and the touch actions are in the pack.

substitutions:
  device_name: now-playing
  media_player: media_player.change_me
  temperature_entity: sensor.change_me_temperature
  weather_entity: weather.change_me
  ha_base_url: "https://home.example.com"
  idle_seconds: "45"

Setup outline

  1. Copy the secrets example into your ESPHome secrets. Fill Wi-Fi, a new API key, OTA, the fallback password, and ha_access_token.
  2. Paste the device YAML. Set the media player, the temperature sensor, the weather entity, and ha_base_url.
  3. Validate, then flash over USB. Accept the device in Home Assistant. Open the ESPHome device and enable Allow the device to perform Home Assistant actions.
  4. Start playback. The playing page should show title and artist within a few seconds, and art if entity_picture is a JPEG the panel can fetch.
  5. Pause and wait out the idle time. The clock, room line, and weather line should replace the track. Play again and the track page should return immediately.
  6. Tap Play and Next. The player should pause or skip. If the taps do nothing, the allow-actions checkbox is still off.

Troubleshooting

  • The clock never leaves --:--. SNTP has not synced. Check Wi-Fi. The timezone in the file is UTC. Change both time blocks if you want a local clock.
  • Title updates, art does not. The picture URL is wrong, or it is not a JPEG. Relative pictures need ha_base_url with no trailing path, for example https://home.example.com. The token must be Bearer plus the token. A 401 in the ESPHome log is that header.
  • Art works on the LAN and fails on a picture host. verify_ssl: false is for a local Home Assistant certificate. A public host that is not JPEG, or a host that blocks the token header, still fails. The title does not depend on art.
  • Touch is offset. Recalibrate touch_x_min, touch_x_max, touch_y_min, and touch_y_max. Start from the pack values. Mirroring is the other pair of substitutions.
  • Play does nothing. The device is not allowed to call Home Assistant services, or this player has no play/pause action. The log line is on the ESPHome device, not on the media player.
  • The screen stays on the track after pause. The idle delay restarts whenever the player state changes. Wait the full idle_seconds after the state settles on paused or idle.
  • A two-USB CYD stays white. This YAML is the ILI9341 one-USB map. Do not keep flashing it on a different panel.

Credits

Based on esp32-wiim-now-playing-display. That project draws now-playing on a Guition ESP32-S3 480×480 and talks to a WiiM player directly. This pack is the Cheap Yellow Display, and the player is any Home Assistant media_player, with art taken from entity_picture. It does not speak a speaker’s private API.

Changelog

v1.0 · Oct 30, 2026: First publish.