# ==============================================================================
# CYD 2.8" HAMon - Home Assistant Monitor
# A customisable clock & sensor dashboard for the ESP32 Cheap Yellow Display
#
# Generated by CYD HAMon Config Generator
# https://github.com/element-software/CYD-ESPHome-HA-Monitor
#
# License: MIT
# ==============================================================================
#
# SUBSTITUTIONS - Customise your dashboard by editing the values below.
# Passwords and keys should be stored in your secrets.yaml file.
#
# ==============================================================================
substitutions:
# --- Device ---
device_name: "hamon"
friendly_name: "HAMon"
# --- Icon Glyphs ---
# List each unique icon ONCE here. If you use the same icon multiple times below,
# only include it once in this list to avoid "duplicate glyph" errors.
icon_glyphs: "\uea0b\ueffc\ue1ff\ue559\ue7fd\ue0f0"
# --- Row 1, Column 1 ---
r1c1_entity: "sensor.whole_home_energy_usage"
r1c1_type: "sensor"
r1c1_label: "Energy"
r1c1_icon: "\uea0b"
r1c1_icon_color: "0xFFA500"
r1c1_format: '%.0fW'
r1c1_color_thresh_high: "5000"
r1c1_color_thresh_mid: "3000"
r1c1_color_thresh_low: "1000"
r1c1_color_high: "0xFF0000"
r1c1_color_mid: "0xFFA500"
r1c1_color_low: "0x32CD32"
# --- Row 1, Column 2 ---
r1c2_entity: "binary_sensor.front_door_sensor_contact"
r1c2_type: "binary"
r1c2_label: "Front Door"
r1c2_icon: "\ueffc"
r1c2_icon_color: "0x32CD32"
r1c2_state_on: "Open"
r1c2_state_off: "Closed"
r1c2_icon_on: "\ueffc"
r1c2_icon_off: "\ueffc"
r1c2_color_on: "0xFF0000"
r1c2_color_off: "0x32CD32"
# --- Row 2, Column 1 ---
r2c1_entity: "sensor.office_presence_one_temperature"
r2c1_type: "sensor"
r2c1_label: "Office"
r2c1_icon: "\ue1ff"
r2c1_icon_color: "0x00BFFF"
r2c1_format: '%.1f°C'
r2c1_color_thresh_high: "30"
r2c1_color_thresh_mid: "25"
r2c1_color_thresh_low: "15"
r2c1_color_high: "0xFF0000"
r2c1_color_mid: "0xFFA500"
r2c1_color_low: "0x32CD32"
# --- Row 2, Column 2 ---
r2c2_entity: "binary_sensor.gate_door_contact"
r2c2_type: "binary"
r2c2_label: "Gate"
r2c2_icon: "\ue559"
r2c2_icon_color: "0x32CD32"
r2c2_state_on: "Open"
r2c2_state_off: "Closed"
r2c2_icon_on: "\ue559"
r2c2_icon_off: "\ue559"
r2c2_color_on: "0xFF0000"
r2c2_color_off: "0x32CD32"
# --- Row 3, Column 1 ---
r3c1_entity: "binary_sensor.garden_pano_person_occupancy"
r3c1_type: "binary"
r3c1_label: "Garden"
r3c1_icon: "\ue7fd"
r3c1_icon_color: "0x32CD32"
r3c1_state_on: "Detected"
r3c1_state_off: "Clear"
r3c1_icon_on: "\ue7fd"
r3c1_icon_off: "\ue7fd"
r3c1_color_on: "0xFF0000"
r3c1_color_off: "0x32CD32"
# --- Row 3, Column 2 ---
r3c2_entity: "light.kitchen_downlights"
r3c2_type: "light"
r3c2_label: "Kitchen"
r3c2_icon: "\ue0f0"
r3c2_icon_color: "0x000000"
r3c2_state_on: "On"
r3c2_state_off: "Off"
r3c2_icon_on: "\ue0f0"
r3c2_icon_off: "\ue0f0"
r3c2_color_on: "0xFFFFFF"
r3c2_color_off: "0x000000"
# ==============================================================================
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
esp32:
board: esp32dev
framework:
type: esp-idf
logger:
# Replace with the API encryption key provided by your ESPHome instance
api:
encryption:
key: !secret hamon_api_key
# Replace with the OTA password provided by your ESPHome instance
ota:
- platform: esphome
password: !secret hamon_ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "${friendly_name} Fallback"
password: !secret hamon_ap_password
captive_portal:
output:
- platform: ledc
pin: GPIO21
id: backlight_pwm
spi:
- id: tft
clk_pin: GPIO14
mosi_pin: GPIO13
miso_pin: GPIO12
- id: touch
clk_pin: GPIO25
mosi_pin: GPIO32
miso_pin: GPIO39
display:
- platform: ili9xxx
id: my_display
model: ILI9341
spi_id: tft
cs_pin: GPIO15
dc_pin: GPIO2
auto_clear_enabled: false
invert_colors: false
color_order: RGB
dimensions:
width: 240
height: 320
transform:
swap_xy: true
mirror_y: true
mirror_x: true
touchscreen:
platform: xpt2046
id: my_touchscreen
spi_id: touch
cs_pin: GPIO33
calibration:
x_min: 220
x_max: 3756
y_min: 394
y_max: 3749
transform:
swap_xy: false
mirror_x: true
mirror_y: false
on_touch:
- lambda: |-
ESP_LOGI("touch", "Touch at LVGL (%d, %d)", touch.x, touch.y);
# --- FONTS ---
font:
- file: "gfonts://Roboto"
id: clock_font
size: 48
glyphs: '0123456789: '
- file: "gfonts://Roboto"
id: date_font
size: 20
glyphs: "0123456789/- abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- file: "gfonts://Material Icons"
id: icon_font
size: 28
glyphs: "${icon_glyphs}"
- file: "gfonts://Roboto"
id: state_font
size: 18
glyphs: '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz .°%W-'
- file: "gfonts://Roboto"
id: label_font
size: 11
glyphs: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz .°%-"
# --- TIME ---
time:
- platform: homeassistant
id: esptime
on_time:
- seconds: 0
then:
- lvgl.label.update:
id: label_clock
text: !lambda 'return id(esptime).now().strftime("%H:%M");'
- lvgl.label.update:
id: label_date
text: !lambda |-
static const char *const dias[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
auto now = id(esptime).now();
return str_sprintf("%s %02d/%02d", dias[now.day_of_week - 1], now.day_of_month, now.month);
# --- DISPLAY PAGE CONFIG ---
lvgl:
displays:
- my_display
touchscreens:
- my_touchscreen
pages:
- id: main_page
bg_color: 0x000000
widgets:
- label:
id: label_clock
text: "--:--"
text_font: clock_font
text_color: 0xFFFFFF
align: TOP_MID
y: 15
- label:
id: label_date
text: "--- --/--"
text_font: date_font
text_color: 0xAAAAAA
align: TOP_MID
y: 65
# ====== ROW 1 ======
- button:
x: 2
y: 100
id: button_r1c1
width: 117
height: 68
bg_opa: TRANSP
border_width: 0
shadow_width: 0
radius: 0
scrollbar_mode: "OFF"
widgets:
- label:
id: icon_r1c1
text: "${r1c1_icon}"
text_font: icon_font
text_color: ${r1c1_icon_color}
align: LEFT_MID
x: 0
clickable: false
- label:
id: lbl_r1c1
text: "${r1c1_label}"
text_font: label_font
text_color: 0xAAAAAA
align: LEFT_MID
x: 32
y: -10
clickable: false
- label:
id: val_r1c1
text: "--"
text_font: state_font
text_color: 0xFFFFFF
align: LEFT_MID
x: 32
y: 10
clickable: false
- button:
x: 121
y: 100
id: button_r1c2
width: 117
height: 68
bg_opa: TRANSP
border_width: 0
shadow_width: 0
radius: 0
scrollbar_mode: "OFF"
widgets:
- label:
id: icon_r1c2
text: "${r1c2_icon}"
text_font: icon_font
text_color: ${r1c2_icon_color}
align: LEFT_MID
x: 0
clickable: false
- label:
id: lbl_r1c2
text: "${r1c2_label}"
text_font: label_font
text_color: 0xAAAAAA
align: LEFT_MID
x: 32
y: -10
clickable: false
- label:
id: val_r1c2
text: "--"
text_font: state_font
text_color: 0xFFFFFF
align: LEFT_MID
x: 32
y: 10
clickable: false
# ====== ROW 2 ======
- button:
x: 2
y: 170
id: button_r2c1
width: 117
height: 68
bg_opa: TRANSP
border_width: 0
shadow_width: 0
radius: 0
scrollbar_mode: "OFF"
widgets:
- label:
id: icon_r2c1
text: "${r2c1_icon}"
text_font: icon_font
text_color: ${r2c1_icon_color}
align: LEFT_MID
x: 0
clickable: false
- label:
id: lbl_r2c1
text: "${r2c1_label}"
text_font: label_font
text_color: 0xAAAAAA
align: LEFT_MID
x: 32
y: -10
clickable: false
- label:
id: val_r2c1
text: "--"
text_font: state_font
text_color: 0xFFFFFF
align: LEFT_MID
x: 32
y: 10
clickable: false
- button:
x: 121
y: 170
id: button_r2c2
width: 117
height: 68
bg_opa: TRANSP
border_width: 0
shadow_width: 0
radius: 0
scrollbar_mode: "OFF"
widgets:
- label:
id: icon_r2c2
text: "${r2c2_icon}"
text_font: icon_font
text_color: ${r2c2_icon_color}
align: LEFT_MID
x: 0
clickable: false
- label:
id: lbl_r2c2
text: "${r2c2_label}"
text_font: label_font
text_color: 0xAAAAAA
align: LEFT_MID
x: 32
y: -10
clickable: false
- label:
id: val_r2c2
text: "--"
text_font: state_font
text_color: 0xFFFFFF
align: LEFT_MID
x: 32
y: 10
clickable: false
# ====== ROW 3 ======
- button:
x: 2
y: 240
id: button_r3c1
width: 117
height: 68
bg_opa: TRANSP
border_width: 0
shadow_width: 0
radius: 0
scrollbar_mode: "OFF"
widgets:
- label:
id: icon_r3c1
text: "${r3c1_icon}"
text_font: icon_font
text_color: ${r3c1_icon_color}
align: LEFT_MID
x: 0
clickable: false
- label:
id: lbl_r3c1
text: "${r3c1_label}"
text_font: label_font
text_color: 0xAAAAAA
align: LEFT_MID
x: 32
y: -10
clickable: false
- label:
id: val_r3c1
text: "--"
text_font: state_font
text_color: 0xFFFFFF
align: LEFT_MID
x: 32
y: 10
clickable: false
- button:
x: 121
y: 240
id: button_r3c2
width: 117
height: 68
bg_opa: TRANSP
border_width: 0
shadow_width: 0
radius: 0
scrollbar_mode: "OFF"
on_click:
- homeassistant.action:
action: light.toggle
data:
entity_id: "light.kitchen_downlights"
checked:
bg_color: 0xFFA500
bg_opa: COVER
widgets:
- label:
id: icon_r3c2
text: "${r3c2_icon}"
text_font: icon_font
text_color: ${r3c2_icon_color}
align: LEFT_MID
x: 0
clickable: false
- label:
id: lbl_r3c2
text: "${r3c2_label}"
text_font: label_font
text_color: 0xAAAAAA
align: LEFT_MID
x: 32
y: -10
clickable: false
- label:
id: val_r3c2
text: "--"
text_font: state_font
text_color: 0xFFFFFF
align: LEFT_MID
x: 32
y: 10
clickable: false
# --- BINARY SENSOR & LIGHT ENTITY STATE ---
# Binary sensors and HA light entities (on/off state); icon color follows state (color_on / color_off).
binary_sensor:
- platform: homeassistant
id: ha_r1c2
entity_id: ${r1c2_entity}
trigger_on_initial_state: true
on_state:
then:
- lvgl.label.update:
id: icon_r1c2
text: !lambda |-
if (id(ha_r1c2).state) return "${r1c2_icon_on}";
return "${r1c2_icon_off}";
- lvgl.widget.update:
id: icon_r1c2
text_color: !lambda |-
if (id(ha_r1c2).state) return lv_color_hex((uint32_t)${r1c2_color_on});
return lv_color_hex((uint32_t)${r1c2_color_off});
- lvgl.label.update:
id: val_r1c2
text: !lambda |-
if (id(ha_r1c2).state) return "${r1c2_state_on}";
return "${r1c2_state_off}";
- lvgl.widget.update:
id: val_r1c2
text_color: !lambda |-
if (id(ha_r1c2).state) return lv_color_hex((uint32_t)${r1c2_color_on});
return lv_color_hex((uint32_t)${r1c2_color_off});
- platform: homeassistant
id: ha_r2c2
entity_id: ${r2c2_entity}
trigger_on_initial_state: true
on_state:
then:
- lvgl.label.update:
id: icon_r2c2
text: !lambda |-
if (id(ha_r2c2).state) return "${r2c2_icon_on}";
return "${r2c2_icon_off}";
- lvgl.widget.update:
id: icon_r2c2
text_color: !lambda |-
if (id(ha_r2c2).state) return lv_color_hex((uint32_t)${r2c2_color_on});
return lv_color_hex((uint32_t)${r2c2_color_off});
- lvgl.label.update:
id: val_r2c2
text: !lambda |-
if (id(ha_r2c2).state) return "${r2c2_state_on}";
return "${r2c2_state_off}";
- lvgl.widget.update:
id: val_r2c2
text_color: !lambda |-
if (id(ha_r2c2).state) return lv_color_hex((uint32_t)${r2c2_color_on});
return lv_color_hex((uint32_t)${r2c2_color_off});
- platform: homeassistant
id: ha_r3c1
entity_id: ${r3c1_entity}
trigger_on_initial_state: true
on_state:
then:
- lvgl.label.update:
id: icon_r3c1
text: !lambda |-
if (id(ha_r3c1).state) return "${r3c1_icon_on}";
return "${r3c1_icon_off}";
- lvgl.widget.update:
id: icon_r3c1
text_color: !lambda |-
if (id(ha_r3c1).state) return lv_color_hex((uint32_t)${r3c1_color_on});
return lv_color_hex((uint32_t)${r3c1_color_off});
- lvgl.label.update:
id: val_r3c1
text: !lambda |-
if (id(ha_r3c1).state) return "${r3c1_state_on}";
return "${r3c1_state_off}";
- lvgl.widget.update:
id: val_r3c1
text_color: !lambda |-
if (id(ha_r3c1).state) return lv_color_hex((uint32_t)${r3c1_color_on});
return lv_color_hex((uint32_t)${r3c1_color_off});
- platform: homeassistant
id: ha_r3c2
entity_id: ${r3c2_entity}
trigger_on_initial_state: true
on_state:
then:
- lvgl.label.update:
id: icon_r3c2
text: !lambda |-
if (id(ha_r3c2).state) return "${r3c2_icon_on}";
return "${r3c2_icon_off}";
- lvgl.widget.update:
id: icon_r3c2
text_color: !lambda |-
if (id(ha_r3c2).state) return lv_color_hex(0x000000);
return lv_color_hex(0xFFFFFF);
- lvgl.label.update:
id: val_r3c2
text: !lambda |-
if (id(ha_r3c2).state) return "${r3c2_state_on}";
return "${r3c2_state_off}";
- lvgl.widget.update:
id: val_r3c2
text_color: !lambda |-
if (id(ha_r3c2).state) return lv_color_hex(0x000000);
return lv_color_hex(0xFFFFFF);
- lvgl.widget.update:
id: lbl_r3c2
text_color: !lambda |-
if (id(ha_r3c2).state) return lv_color_hex(0x000000);
return lv_color_hex(0xFFFFFF);
- lvgl.widget.update:
id: button_r3c2
state:
checked: !lambda return id(ha_r3c2).state;
# --- LIGHT CONFIG (display backlight) ---
light:
- platform: monochromatic
output: backlight_pwm
name: Display Backlight
id: backlight
restore_mode: ALWAYS_ON
default_transition_length: 0.5s
# --- NUMERIC SENSOR CONFIG ---
sensor:
- platform: homeassistant
id: ha_r1c1
entity_id: ${r1c1_entity}
on_value:
then:
- lvgl.label.update:
id: val_r1c1
text: !lambda |-
return str_sprintf("${r1c1_format}", x);
- lvgl.label.update:
id: icon_r1c1
text_color: !lambda |-
if (x > ${r1c1_color_thresh_high}) return lv_color_hex(${r1c1_color_high});
if (x > ${r1c1_color_thresh_mid}) return lv_color_hex(${r1c1_color_mid});
if (x > ${r1c1_color_thresh_low}) return lv_color_hex(${r1c1_color_low});
return lv_color_hex(${r1c1_color_low});
- platform: homeassistant
id: ha_r2c1
entity_id: ${r2c1_entity}
on_value:
then:
- lvgl.label.update:
id: val_r2c1
text: !lambda |-
return str_sprintf("${r2c1_format}", x);
- lvgl.label.update:
id: icon_r2c1
text_color: !lambda |-
if (x > ${r2c1_color_thresh_high}) return lv_color_hex(${r2c1_color_high});
if (x > ${r2c1_color_thresh_mid}) return lv_color_hex(${r2c1_color_mid});
if (x > ${r2c1_color_thresh_low}) return lv_color_hex(${r2c1_color_low});
return lv_color_hex(${r2c1_color_low});