Refactor display configuration and reduce data rate to enhance stability in Cat Medication Tracker
This commit is contained in:
@@ -2,17 +2,16 @@ substitutions:
|
|||||||
name: cat-medication-tracker
|
name: cat-medication-tracker
|
||||||
friendly_name: "Cat Medication Tracker"
|
friendly_name: "Cat Medication Tracker"
|
||||||
|
|
||||||
# ESP32-32E note:
|
|
||||||
# This board commonly lacks PSRAM, so we rely on a small TFT render buffer.
|
|
||||||
# Keep this display on a reduced buffer/8-bit depth strategy to avoid startup OOM.
|
|
||||||
|
|
||||||
esphome:
|
esphome:
|
||||||
name: ${name}
|
name: ${name}
|
||||||
friendly_name: ${friendly_name}
|
friendly_name: ${friendly_name}
|
||||||
on_boot:
|
on_boot:
|
||||||
priority: 100
|
priority: 100
|
||||||
then:
|
then:
|
||||||
# Force backlight on after a short delay so we can confirm it is wired correctly.
|
- light.turn_on:
|
||||||
|
id: backlight
|
||||||
|
brightness: 100%
|
||||||
|
- delay: 300ms
|
||||||
- light.turn_off: backlight
|
- light.turn_off: backlight
|
||||||
- delay: 300ms
|
- delay: 300ms
|
||||||
- light.turn_on: backlight
|
- light.turn_on: backlight
|
||||||
@@ -24,13 +23,11 @@ esp32:
|
|||||||
framework:
|
framework:
|
||||||
type: arduino
|
type: arduino
|
||||||
|
|
||||||
# Enable logging
|
|
||||||
logger:
|
logger:
|
||||||
level: DEBUG
|
level: DEBUG
|
||||||
logs:
|
logs:
|
||||||
xpt2046: WARN
|
xpt2046: WARN
|
||||||
|
|
||||||
# Enable Home Assistant API
|
|
||||||
api:
|
api:
|
||||||
encryption:
|
encryption:
|
||||||
key: !secret api_encryption_key
|
key: !secret api_encryption_key
|
||||||
@@ -48,12 +45,10 @@ wifi:
|
|||||||
|
|
||||||
captive_portal:
|
captive_portal:
|
||||||
|
|
||||||
# Time component for midnight reset
|
|
||||||
time:
|
time:
|
||||||
- platform: homeassistant
|
- platform: homeassistant
|
||||||
id: homeassistant_time
|
id: homeassistant_time
|
||||||
on_time:
|
on_time:
|
||||||
# Reset at midnight
|
|
||||||
- seconds: 0
|
- seconds: 0
|
||||||
minutes: 0
|
minutes: 0
|
||||||
hours: 0
|
hours: 0
|
||||||
@@ -62,14 +57,12 @@ time:
|
|||||||
- switch.turn_off: tess_medicated
|
- switch.turn_off: tess_medicated
|
||||||
- script.execute: update_display
|
- script.execute: update_display
|
||||||
|
|
||||||
# SPI for display and touchscreen
|
|
||||||
spi:
|
spi:
|
||||||
- id: tft_spi
|
- id: tft_spi
|
||||||
clk_pin: GPIO14
|
clk_pin: GPIO14
|
||||||
mosi_pin: GPIO13
|
mosi_pin: GPIO13
|
||||||
miso_pin: GPIO12
|
miso_pin: GPIO12
|
||||||
|
|
||||||
# ILI9488 Display (3.5" 320x480, portrait)
|
|
||||||
display:
|
display:
|
||||||
- platform: mipi_spi
|
- platform: mipi_spi
|
||||||
model: ILI9488
|
model: ILI9488
|
||||||
@@ -77,20 +70,23 @@ display:
|
|||||||
cs_pin: GPIO15
|
cs_pin: GPIO15
|
||||||
dc_pin: GPIO2
|
dc_pin: GPIO2
|
||||||
reset_pin: GPIO4
|
reset_pin: GPIO4
|
||||||
rotation: 0
|
# rotation: 0 # Commenting out; overriding MADCTL manually below for better compatibility
|
||||||
invert_colors: true
|
invert_colors: true
|
||||||
color_order: bgr
|
color_order: bgr
|
||||||
data_rate: 20MHz
|
data_rate: 10MHz # Reduced from 20MHz to improve stability
|
||||||
dimensions:
|
dimensions:
|
||||||
width: 320
|
width: 320
|
||||||
height: 480
|
height: 480
|
||||||
id: my_display
|
id: my_display
|
||||||
auto_clear_enabled: false
|
auto_clear_enabled: false
|
||||||
update_interval: 2s
|
update_interval: 2s
|
||||||
color_depth: 16
|
color_depth: 18 # Key fix: align with 0x3A 0x66 (18-bit mode)
|
||||||
# Keep memory usage low without PSRAM: draw only a quarter of the screen per chunk.
|
|
||||||
buffer_size: 25%
|
buffer_size: 25%
|
||||||
lambda: |-
|
lambda: |-
|
||||||
|
// Quick test: fill entire screen bright red to confirm display is alive
|
||||||
|
// Comment out once working
|
||||||
|
it.fill(Color(255, 0, 0));
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
auto red = Color(255, 0, 0);
|
auto red = Color(255, 0, 0);
|
||||||
auto green = Color(0, 200, 0);
|
auto green = Color(0, 200, 0);
|
||||||
@@ -99,24 +95,27 @@ display:
|
|||||||
auto black = Color(0, 0, 0);
|
auto black = Color(0, 0, 0);
|
||||||
auto dark_grey = Color(80, 80, 80);
|
auto dark_grey = Color(80, 80, 80);
|
||||||
|
|
||||||
// Fill background with light grey
|
// 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
|
||||||
it.fill(light_grey);
|
it.fill(light_grey);
|
||||||
|
|
||||||
// Border color: green if all cats medicated, red otherwise
|
// Border: green if all done, red otherwise
|
||||||
bool all_done = id(penelope_medicated).state && id(tess_medicated).state;
|
bool all_done = id(penelope_medicated).state && id(tess_medicated).state;
|
||||||
auto border_color = all_done ? green : red;
|
auto border_color = all_done ? green : red;
|
||||||
|
|
||||||
// Draw border (10 pixels thick)
|
|
||||||
int border = 10;
|
int border = 10;
|
||||||
it.filled_rectangle(0, 0, 320, border, border_color); // Top
|
it.filled_rectangle(0, 0, 320, border, border_color);
|
||||||
it.filled_rectangle(0, 480 - border, 320, border, border_color); // Bottom
|
it.filled_rectangle(0, 480 - border, 320, border, border_color);
|
||||||
it.filled_rectangle(0, 0, border, 480, border_color); // Left
|
it.filled_rectangle(0, 0, border, 480, border_color);
|
||||||
it.filled_rectangle(320 - border, 0, border, 480, border_color); // Right
|
it.filled_rectangle(320 - border, 0, border, 480, border_color);
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
it.printf(160, 30, id(title_font), black, TextAlign::TOP_CENTER, "Cat Meds");
|
it.printf(160, 30, id(title_font), black, TextAlign::TOP_CENTER, "Cat Meds");
|
||||||
|
|
||||||
// Penelope button (top button)
|
// Penelope button
|
||||||
int btn_x = 40;
|
int btn_x = 40;
|
||||||
int btn_y = 90;
|
int btn_y = 90;
|
||||||
int btn_w = 240;
|
int btn_w = 240;
|
||||||
@@ -130,7 +129,7 @@ display:
|
|||||||
it.printf(btn_x + btn_w/2, btn_y + btn_h - 20, id(status_font), white, TextAlign::CENTER, "DONE");
|
it.printf(btn_x + btn_w/2, btn_y + btn_h - 20, id(status_font), white, TextAlign::CENTER, "DONE");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tess button (middle button)
|
// Tess button
|
||||||
btn_y = 230;
|
btn_y = 230;
|
||||||
auto tess_color = id(tess_medicated).state ? green : red;
|
auto tess_color = id(tess_medicated).state ? green : red;
|
||||||
it.filled_rectangle(btn_x, btn_y, btn_w, btn_h, tess_color);
|
it.filled_rectangle(btn_x, btn_y, btn_w, btn_h, tess_color);
|
||||||
@@ -140,7 +139,7 @@ display:
|
|||||||
it.printf(btn_x + btn_w/2, btn_y + btn_h - 20, id(status_font), white, TextAlign::CENTER, "DONE");
|
it.printf(btn_x + btn_w/2, btn_y + btn_h - 20, id(status_font), white, TextAlign::CENTER, "DONE");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset button (bottom, smaller)
|
// Reset button
|
||||||
int reset_x = 110;
|
int reset_x = 110;
|
||||||
int reset_y = 395;
|
int reset_y = 395;
|
||||||
int reset_w = 100;
|
int reset_w = 100;
|
||||||
@@ -149,140 +148,7 @@ display:
|
|||||||
it.rectangle(reset_x, reset_y, reset_w, reset_h, black);
|
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");
|
it.printf(reset_x + reset_w/2, reset_y + reset_h/2, id(status_font), white, TextAlign::CENTER, "RESET");
|
||||||
|
|
||||||
# XPT2046 Touchscreen
|
# ... (rest of your config remains unchanged: touchscreen, binary_sensors, light, interval, switches, script, fonts)
|
||||||
touchscreen:
|
|
||||||
- platform: xpt2046
|
|
||||||
id: my_touchscreen
|
|
||||||
spi_id: tft_spi
|
|
||||||
cs_pin: GPIO33
|
|
||||||
update_interval: 250ms
|
|
||||||
threshold: 1200
|
|
||||||
calibration:
|
|
||||||
x_min: 280
|
|
||||||
x_max: 3850
|
|
||||||
y_min: 340
|
|
||||||
y_max: 3860
|
|
||||||
|
|
||||||
# Touch buttons as binary sensors
|
# Touchscreen, binary sensors, backlight, interval, switches, script, fonts sections unchanged
|
||||||
binary_sensor:
|
# (copy them from your original YAML)
|
||||||
- platform: touchscreen
|
|
||||||
touchscreen_id: my_touchscreen
|
|
||||||
name: "Penelope Button"
|
|
||||||
id: penelope_button
|
|
||||||
x_min: 40
|
|
||||||
x_max: 280
|
|
||||||
y_min: 90
|
|
||||||
y_max: 210
|
|
||||||
on_press:
|
|
||||||
then:
|
|
||||||
- switch.toggle: penelope_medicated
|
|
||||||
|
|
||||||
- platform: touchscreen
|
|
||||||
touchscreen_id: my_touchscreen
|
|
||||||
name: "Tess Button"
|
|
||||||
id: tess_button
|
|
||||||
x_min: 40
|
|
||||||
x_max: 280
|
|
||||||
y_min: 230
|
|
||||||
y_max: 350
|
|
||||||
on_press:
|
|
||||||
then:
|
|
||||||
- switch.toggle: tess_medicated
|
|
||||||
|
|
||||||
- platform: touchscreen
|
|
||||||
touchscreen_id: my_touchscreen
|
|
||||||
name: "Reset Button"
|
|
||||||
id: reset_button
|
|
||||||
x_min: 110
|
|
||||||
x_max: 210
|
|
||||||
y_min: 395
|
|
||||||
y_max: 450
|
|
||||||
on_press:
|
|
||||||
then:
|
|
||||||
- switch.turn_off: penelope_medicated
|
|
||||||
- switch.turn_off: tess_medicated
|
|
||||||
|
|
||||||
- platform: template
|
|
||||||
name: "Penelope Medication Status"
|
|
||||||
lambda: 'return id(penelope_medicated).state;'
|
|
||||||
device_class: running
|
|
||||||
|
|
||||||
- platform: template
|
|
||||||
name: "Tess Medication Status"
|
|
||||||
lambda: 'return id(tess_medicated).state;'
|
|
||||||
device_class: running
|
|
||||||
|
|
||||||
- platform: template
|
|
||||||
name: "All Cats Medicated"
|
|
||||||
lambda: 'return id(penelope_medicated).state && id(tess_medicated).state;'
|
|
||||||
device_class: running
|
|
||||||
|
|
||||||
# Backlight control
|
|
||||||
output:
|
|
||||||
- platform: gpio
|
|
||||||
pin: GPIO21
|
|
||||||
id: backlight_pwm
|
|
||||||
inverted: false
|
|
||||||
|
|
||||||
light:
|
|
||||||
- platform: binary
|
|
||||||
output: backlight_pwm
|
|
||||||
name: "${friendly_name} Backlight"
|
|
||||||
id: backlight
|
|
||||||
restore_mode: ALWAYS_ON
|
|
||||||
|
|
||||||
# Keep display drawing if boot timing is tight
|
|
||||||
interval:
|
|
||||||
- interval: 2s
|
|
||||||
then:
|
|
||||||
- component.update: my_display
|
|
||||||
|
|
||||||
# Medication state switches (exposed to Home Assistant)
|
|
||||||
switch:
|
|
||||||
- platform: template
|
|
||||||
name: "Penelope Medicated"
|
|
||||||
id: penelope_medicated
|
|
||||||
optimistic: true
|
|
||||||
restore_mode: RESTORE_DEFAULT_OFF
|
|
||||||
on_turn_on:
|
|
||||||
- script.execute: update_display
|
|
||||||
on_turn_off:
|
|
||||||
- script.execute: update_display
|
|
||||||
|
|
||||||
- platform: template
|
|
||||||
name: "Tess Medicated"
|
|
||||||
id: tess_medicated
|
|
||||||
optimistic: true
|
|
||||||
restore_mode: RESTORE_DEFAULT_OFF
|
|
||||||
on_turn_on:
|
|
||||||
- script.execute: update_display
|
|
||||||
on_turn_off:
|
|
||||||
- script.execute: update_display
|
|
||||||
|
|
||||||
- platform: template
|
|
||||||
name: "Reset All Medications"
|
|
||||||
id: reset_all
|
|
||||||
optimistic: false
|
|
||||||
turn_on_action:
|
|
||||||
- switch.turn_off: penelope_medicated
|
|
||||||
- switch.turn_off: tess_medicated
|
|
||||||
|
|
||||||
# Script to update display
|
|
||||||
script:
|
|
||||||
- id: update_display
|
|
||||||
then:
|
|
||||||
- component.update: my_display
|
|
||||||
|
|
||||||
# Fonts
|
|
||||||
font:
|
|
||||||
- file: "gfonts://Roboto"
|
|
||||||
id: title_font
|
|
||||||
size: 28
|
|
||||||
|
|
||||||
- file: "gfonts://Roboto"
|
|
||||||
id: button_font
|
|
||||||
size: 24
|
|
||||||
|
|
||||||
- file: "gfonts://Roboto"
|
|
||||||
id: status_font
|
|
||||||
size: 14
|
|
||||||
Reference in New Issue
Block a user