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.
The 12-button CYD touch panel and the CYD touch thermostat are controls. You tap them, and Home Assistant does something. This pack is the other direction. Home Assistant already knows a door is open, a washer finished, or rain is coming, and it tells a Cheap Yellow Display. The display changes a small figure’s expression, holds up a status card, and flashes the RGB LED on the back of the board. It does not toggle lights, and it does not change a setpoint.
The device name and the two message fields live in substitutions and script fields. Wi-Fi credentials stay in secrets.yaml. Do not publish which door, which plug, or which room the card is talking about.
What problem it solves
You want a desk or bedside screen that reacts to events you already automate, without a tablet dashboard and without another button grid on the same board.
How it works
The board is an ESP32-2432S028R, the resistive 2.8″ Cheap Yellow Display, 320×240. ESPHome draws with LVGL. The figure is shapes, not a bitmap, so it fits the ESP32 without PSRAM. The pack ships one figure and five expressions: normal, happy, alert, tired, and rain.
- A script is the only input — anything in Home Assistant that can call a script can drive the screen. A door alert, a laundry handoff reminder, or a morning weather briefing all call the same script with a short line and one expression name.
- Native API — the ESPHome node exposes an action,
show_status, withtextandmood. After adoption the service name follows the device name substitution. Withdevice_name: desk_companionthe script callsesphome.desk_companion_show_status. - The card and the figure — the line replaces the status card. The expression selects the face. The card stays up for the hold time in the YAML (pack default 8 seconds) and then the figure returns to
normalwith a blank card. - The RGB LED — the onboard LED follows the expression for that same hold, then turns off.
alertis red,happyis green,rainis blue,tiredis a dim amber,normaldoes not light the LED. It is a flash, not a night light. - MQTT, if you already have a broker — the pack includes a second script that publishes the same two fields as JSON,
{"action": "status", "text": "...", "expression": "alert"}, to a topic prefix you set in a substitution. Skip it when the native API is enough. Do not put the broker password in the script.
The touchscreen is initialized only so the stock pin map stays intact. This pack does not put buttons on it. Taps do not call Home Assistant.
Hardware notes
- Board. ESP32-2432S028R, the common 2.8″ resistive “CYD”. In ESPHome use
board: esp32dev. A capacitive “C” variant uses a different touch part, and this YAML does not cover it. One-USB and two-USB boards can still use different display controllers. A white screen means the display model in the pack comments does not match this rev. Try the commented alternate, the same way the PC hardware monitor does. - Pins that are already taken. Display SPI is GPIO14, GPIO13, and GPIO12, with CS GPIO15, DC GPIO2, and backlight GPIO21. The RGB LED is GPIO4 red, GPIO16 green, and GPIO17 blue, all inverted. Leave those in the substitutions. GPIO6–GPIO11 are flash.
- Power. The 5 V USB supply. The backlight and the LED are a poor match for a battery pack.
- Where it sits. A desk or a bedside table, close enough to read one line. The card text is one short sentence. A paragraph will not fit.
Snippet
The device name, the LED pins, and the hold time are substitutions. The figure drawing and the display bus are in the pack YAML.
substitutions:
device_name: desk_companion
led_r_pin: GPIO4
led_g_pin: GPIO16
led_b_pin: GPIO17
hold: 8s
esp32:
board: esp32dev
output:
- platform: ledc
id: led_r_out
pin:
number: ${led_r_pin}
inverted: true
- platform: ledc
id: led_g_out
pin:
number: ${led_g_pin}
inverted: true
- platform: ledc
id: led_b_out
pin:
number: ${led_b_pin}
inverted: true
light:
- platform: rgb
id: status_led
red: led_r_out
green: led_g_out
blue: led_b_out
api:
actions:
- action: show_status
variables:
text: string
mood: string
then:
- lvgl.label.update:
id: status_card
text: !lambda "return text;"
- script.execute:
id: apply_expression
- delay: ${hold}
- light.turn_off: status_led
apply_expression reads mood and sets the face and the LED color. Unknown names fall through to normal and leave the LED off. Wi-Fi and the API encryption key stay in secrets.yaml.
The script the pack imports:
fields:
message:
name: Status line
required: true
selector:
text:
expression:
name: Expression
default: alert
selector:
select:
options:
- normal
- happy
- alert
- tired
- rain
sequence:
- action: esphome.desk_companion_show_status
data:
text: "{{ message }}"
mood: "{{ expression }}"
Rename the action if you changed device_name. The MQTT script in the pack takes the same two fields and does not call the native API.
Setup outline
- Flash the YAML over USB. The figure should be on the screen in
normal, with an empty card, and the RGB LED off. - Adopt the node in Home Assistant. Allow the device to be called. Confirm
esphome.desk_companion_show_statusexists under Developer Tools → Actions. - Import the script. Run it with the line
Washer finishedand expressionhappy. The card shows that line, the face changes, the LED flashes green, and both clear after the hold. - Call the script from one real automation. A door contact that stays open, a laundry cycle-done event, or a forecast that includes rain are the three the notes walk through. Pass a short line you would actually want to read from across the room.
- If you use the MQTT script instead, point the topic prefix substitution at your broker and confirm one JSON payload changes the card. Leave the password in the broker configuration.
Troubleshooting
- White screen. The display model does not match this CYD rev (one USB port versus two does not tell you which controller). Use the alternate model commented in the pack. Backlight is GPIO21. A dark screen with a lit backlight is a model mismatch. A dark screen with no backlight is power or GPIO21.
- The action does not exist. The device name substitution and the script action have to match, and the node has to be adopted.
desk_companionbecomesesphome.desk_companion_show_status. - The card changes and the face does not.
expressionwas not one of the five names, so the pack keptnormal. The select on the script only offers those five. - The LED stays on. The hold delay did not run, or a second call arrived and the first turn-off lost the race. The pack uses
mode: restartonapply_expressionso a new message replaces the previous hold. - Red and blue are swapped. That is the panel’s color order, not the LED. The LED pins above are the onboard RGB. A swapped picture is the display
color_ordercomment in the pack. - You wanted buttons. This board can be a control instead. Use the 12-button panel or the touch thermostat. Do not merge those grids into this YAML. The pins are the same, the jobs are different.
Credits
Based on cheap-yellow-companion, an ESPHome and LVGL figure for the ESP32-2432S028R that takes MQTT commands from Home Assistant. This write-up is an original status face: five expressions, one card, an RGB flash, a native API action, and a script with the same fields over MQTT. It does not include that project’s games, seasons, or extra characters.