2026-03-04 17:04:06 -05:00
|
|
|
substitutions:
|
|
|
|
|
name: cat-medication-tracker
|
|
|
|
|
friendly_name: "Cat Medication Tracker"
|
|
|
|
|
|
|
|
|
|
esphome:
|
|
|
|
|
name: ${name}
|
|
|
|
|
friendly_name: ${friendly_name}
|
2026-03-04 19:44:45 -05:00
|
|
|
on_boot:
|
2026-03-04 20:30:51 -05:00
|
|
|
priority: 100
|
|
|
|
|
then:
|
2026-03-06 14:05:07 -05:00
|
|
|
- light.turn_on:
|
|
|
|
|
id: backlight
|
|
|
|
|
brightness: 100%
|
|
|
|
|
- delay: 300ms
|
2026-03-06 13:50:48 -05:00
|
|
|
- light.turn_off: backlight
|
|
|
|
|
- delay: 300ms
|
2026-03-04 20:30:51 -05:00
|
|
|
- light.turn_on: backlight
|
2026-03-06 13:50:48 -05:00
|
|
|
- delay: 300ms
|
2026-03-04 20:30:51 -05:00
|
|
|
- component.update: my_display
|
2026-03-04 17:04:06 -05:00
|
|
|
|
|
|
|
|
esp32:
|
|
|
|
|
board: esp32dev
|
|
|
|
|
framework:
|
2026-03-06 13:25:41 -05:00
|
|
|
type: arduino
|
2026-03-04 17:04:06 -05:00
|
|
|
|
|
|
|
|
logger:
|
2026-03-04 20:30:51 -05:00
|
|
|
level: DEBUG
|
2026-03-04 19:51:11 -05:00
|
|
|
logs:
|
|
|
|
|
xpt2046: WARN
|
2026-03-04 17:04:06 -05:00
|
|
|
|
|
|
|
|
api:
|
|
|
|
|
encryption:
|
|
|
|
|
key: !secret api_encryption_key
|
|
|
|
|
|
|
|
|
|
ota:
|
|
|
|
|
platform: esphome
|
|
|
|
|
password: !secret ota_password
|
|
|
|
|
|
|
|
|
|
wifi:
|
2026-03-04 18:05:23 -05:00
|
|
|
ssid: !secret wifi_iot_ssid
|
2026-03-04 17:04:06 -05:00
|
|
|
password: !secret wifi_password
|
|
|
|
|
ap:
|
|
|
|
|
ssid: "${name}-fallback"
|
2026-03-04 17:37:54 -05:00
|
|
|
password: !secret fallback_password
|
2026-03-04 17:04:06 -05:00
|
|
|
|
|
|
|
|
captive_portal:
|
|
|
|
|
|
|
|
|
|
time:
|
|
|
|
|
- platform: homeassistant
|
|
|
|
|
id: homeassistant_time
|
|
|
|
|
on_time:
|
|
|
|
|
- seconds: 0
|
|
|
|
|
minutes: 0
|
|
|
|
|
hours: 0
|
|
|
|
|
then:
|
|
|
|
|
- switch.turn_off: penelope_medicated
|
|
|
|
|
- switch.turn_off: tess_medicated
|
|
|
|
|
- script.execute: update_display
|
|
|
|
|
|
|
|
|
|
spi:
|
|
|
|
|
- id: tft_spi
|
|
|
|
|
clk_pin: GPIO14
|
|
|
|
|
mosi_pin: GPIO13
|
|
|
|
|
miso_pin: GPIO12
|
|
|
|
|
|
|
|
|
|
display:
|
2026-03-06 12:43:47 -05:00
|
|
|
- platform: mipi_spi
|
2026-03-06 08:49:02 -05:00
|
|
|
model: ILI9488
|
2026-03-04 17:04:06 -05:00
|
|
|
spi_id: tft_spi
|
|
|
|
|
cs_pin: GPIO15
|
|
|
|
|
dc_pin: GPIO2
|
|
|
|
|
reset_pin: GPIO4
|
2026-03-06 14:05:07 -05:00
|
|
|
# rotation: 0 # Commenting out; overriding MADCTL manually below for better compatibility
|
2026-03-06 13:50:48 -05:00
|
|
|
invert_colors: true
|
2026-03-04 18:05:23 -05:00
|
|
|
color_order: bgr
|
2026-03-06 14:05:07 -05:00
|
|
|
data_rate: 10MHz # Reduced from 20MHz to improve stability
|
2026-03-04 17:04:06 -05:00
|
|
|
dimensions:
|
2026-03-06 08:49:02 -05:00
|
|
|
width: 320
|
|
|
|
|
height: 480
|
2026-03-04 17:04:06 -05:00
|
|
|
id: my_display
|
2026-03-04 18:05:23 -05:00
|
|
|
auto_clear_enabled: false
|
2026-03-04 20:30:51 -05:00
|
|
|
update_interval: 2s
|
2026-03-06 14:05:07 -05:00
|
|
|
color_depth: 18 # Key fix: align with 0x3A 0x66 (18-bit mode)
|
2026-03-06 12:43:47 -05:00
|
|
|
buffer_size: 25%
|
2026-03-04 17:04:06 -05:00
|
|
|
lambda: |-
|
2026-03-06 14:05:07 -05:00
|
|
|
// Quick test: fill entire screen bright red to confirm display is alive
|
|
|
|
|
// Comment out once working
|
|
|
|
|
it.fill(Color(255, 0, 0));
|
|
|
|
|
|
2026-03-04 17:04:06 -05:00
|
|
|
// Colors
|
|
|
|
|
auto red = Color(255, 0, 0);
|
|
|
|
|
auto green = Color(0, 200, 0);
|
|
|
|
|
auto light_grey = Color(200, 200, 200);
|
|
|
|
|
auto white = Color(255, 255, 255);
|
|
|
|
|
auto black = Color(0, 0, 0);
|
|
|
|
|
auto dark_grey = Color(80, 80, 80);
|
2026-03-06 08:49:02 -05:00
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
// Force common MADCTL for portrait (try 0x28, 0x48, 0x68, 0x98 if still wrong orientation)
|
|
|
|
|
it.command(0x36);
|
|
|
|
|
it.data(0x28); // ← Try this first; change to 0x48 / 0x68 etc. if upside-down/mirrored
|
|
|
|
|
|
|
|
|
|
// Fill background
|
2026-03-04 17:04:06 -05:00
|
|
|
it.fill(light_grey);
|
2026-03-06 08:49:02 -05:00
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
// Border: green if all done, red otherwise
|
2026-03-04 17:04:06 -05:00
|
|
|
bool all_done = id(penelope_medicated).state && id(tess_medicated).state;
|
|
|
|
|
auto border_color = all_done ? green : red;
|
2026-03-06 08:49:02 -05:00
|
|
|
|
|
|
|
|
int border = 10;
|
2026-03-06 14:05:07 -05:00
|
|
|
it.filled_rectangle(0, 0, 320, border, border_color);
|
|
|
|
|
it.filled_rectangle(0, 480 - border, 320, border, border_color);
|
|
|
|
|
it.filled_rectangle(0, 0, border, 480, border_color);
|
|
|
|
|
it.filled_rectangle(320 - border, 0, border, 480, border_color);
|
2026-03-06 08:49:02 -05:00
|
|
|
|
2026-03-04 17:04:06 -05:00
|
|
|
// Title
|
2026-03-06 08:49:02 -05:00
|
|
|
it.printf(160, 30, id(title_font), black, TextAlign::TOP_CENTER, "Cat Meds");
|
|
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
// Penelope button
|
2026-03-06 08:49:02 -05:00
|
|
|
int btn_x = 40;
|
|
|
|
|
int btn_y = 90;
|
|
|
|
|
int btn_w = 240;
|
|
|
|
|
int btn_h = 120;
|
|
|
|
|
|
2026-03-04 17:04:06 -05:00
|
|
|
auto penelope_color = id(penelope_medicated).state ? green : red;
|
|
|
|
|
it.filled_rectangle(btn_x, btn_y, btn_w, btn_h, penelope_color);
|
|
|
|
|
it.rectangle(btn_x, btn_y, btn_w, btn_h, dark_grey);
|
|
|
|
|
it.printf(btn_x + btn_w/2, btn_y + btn_h/2, id(button_font), white, TextAlign::CENTER, "Penelope");
|
|
|
|
|
if (id(penelope_medicated).state) {
|
2026-03-06 08:49:02 -05:00
|
|
|
it.printf(btn_x + btn_w/2, btn_y + btn_h - 20, id(status_font), white, TextAlign::CENTER, "DONE");
|
2026-03-04 17:04:06 -05:00
|
|
|
}
|
2026-03-06 08:49:02 -05:00
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
// Tess button
|
2026-03-06 08:49:02 -05:00
|
|
|
btn_y = 230;
|
2026-03-04 17:04:06 -05:00
|
|
|
auto tess_color = id(tess_medicated).state ? green : red;
|
|
|
|
|
it.filled_rectangle(btn_x, btn_y, btn_w, btn_h, tess_color);
|
|
|
|
|
it.rectangle(btn_x, btn_y, btn_w, btn_h, dark_grey);
|
|
|
|
|
it.printf(btn_x + btn_w/2, btn_y + btn_h/2, id(button_font), white, TextAlign::CENTER, "Tess");
|
|
|
|
|
if (id(tess_medicated).state) {
|
2026-03-06 08:49:02 -05:00
|
|
|
it.printf(btn_x + btn_w/2, btn_y + btn_h - 20, id(status_font), white, TextAlign::CENTER, "DONE");
|
2026-03-04 17:04:06 -05:00
|
|
|
}
|
2026-03-06 08:49:02 -05:00
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
// Reset button
|
2026-03-06 08:49:02 -05:00
|
|
|
int reset_x = 110;
|
|
|
|
|
int reset_y = 395;
|
2026-03-04 17:04:06 -05:00
|
|
|
int reset_w = 100;
|
2026-03-06 08:49:02 -05:00
|
|
|
int reset_h = 55;
|
2026-03-04 17:04:06 -05:00
|
|
|
it.filled_rectangle(reset_x, reset_y, reset_w, reset_h, dark_grey);
|
|
|
|
|
it.rectangle(reset_x, reset_y, reset_w, reset_h, black);
|
|
|
|
|
it.printf(reset_x + reset_w/2, reset_y + reset_h/2, id(status_font), white, TextAlign::CENTER, "RESET");
|
|
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
# ... (rest of your config remains unchanged: touchscreen, binary_sensors, light, interval, switches, script, fonts)
|
2026-03-04 17:23:41 -05:00
|
|
|
|
2026-03-06 14:05:07 -05:00
|
|
|
# Touchscreen, binary sensors, backlight, interval, switches, script, fonts sections unchanged
|
|
|
|
|
# (copy them from your original YAML)
|