Skip to content

Instantly share code, notes, and snippets.

@Cadair
Last active July 4, 2022 15:13
Show Gist options
  • Save Cadair/7db53154a8d353eb304bcc515a9273bb to your computer and use it in GitHub Desktop.
Save Cadair/7db53154a8d353eb304bcc515a9273bb to your computer and use it in GitHub Desktop.
substitutions:
esp_name: ESP Display
esp_hostname: esp-display
ha_climate_component: climate.central_heating
esphome:
name: ${esp_hostname}
platformio_options:
upload_speed: 1500000
esp32:
board: esp32dev
framework:
type: arduino
spi:
clk_pin: 18
mosi_pin: 23
#external_components:
# - source: github://tiaanv/esphome-components
# components: ["t547"]
# Partial refresh but bleeds
external_components:
- source:
type: git
url: https://github.com/vbaksa/esphome
ref: dev
components: [lilygo_t5_47_display]
refresh: 5s
logger:
api:
ota:
wifi:
networks:
- ssid: "cadair"
password: !secret wifi_password
time:
- platform: sntp
id: ntp
sun:
latitude: !secret home_lat
longitude: !secret home_lon
binary_sensor:
- platform: gpio
pin:
number: GPIO39
inverted: true
name: "${esp_name} Button 5"
on_state:
then:
- delay: 0.2s
- script.execute: refresh_display
- platform: gpio
pin:
number: GPIO34
inverted: true
name: "${esp_name} Button 4"
on_state:
then:
- delay: 0.2s
- script.execute: refresh_display
- platform: gpio
pin:
number: GPIO35
inverted: true
name: "${esp_name} Button 3"
on_state:
then:
- delay: 0.2s
- script.execute: refresh_display
- platform: homeassistant
id: backdoor_locked
entity_id: binary_sensor.backdoor_locked
internal: true
- platform: homeassistant
id: backdoor
entity_id: binary_sensor.backdoor
internal: true
on_state:
then:
- component.update: t5_display
- platform: homeassistant
id: dryer
entity_id: binary_sensor.dryer
internal: true
- platform: homeassistant
id: washer
entity_id: binary_sensor.washer
internal: true
sensor:
- platform: adc
pin: GPIO36
name: "${esp_name} Battery Voltage"
id: batt_volt
attenuation: 11db
filters:
- multiply: 2
- platform: template
name: "${esp_name} Battery"
id: batt
unit_of_measurement: "%"
accuracy_decimals: 0
device_class: battery
lambda: |-
int y = (1-(4.1-id(batt_volt).state)/(4.1-3.3))*100;
if (y < 100) {return y;} else {return 100;};
- platform: homeassistant
id: climate_set_point
entity_id: "${ha_climate_component}"
attribute: temperature
internal: true
- platform: homeassistant
id: climate_current_temp
entity_id: "${ha_climate_component}"
attribute: current_temperature
internal: true
- platform: homeassistant
id: forecast_temp_high
entity_id: sensor.openweathermap_forecast_temperature
internal: true
- platform: homeassistant
id: forecast_temp_low
entity_id: sensor.openweathermap_forecast_temperature_low
internal: true
- platform: homeassistant
id: forecast_percip_prob
entity_id: sensor.holmfirth_probability_of_precipitation
internal: true
- platform: homeassistant
id: forecast_wind_speed
entity_id: sensor.holmfirth_wind_speed
internal: true
- platform: homeassistant
id: next_bin_days
entity_id: sensor.next_bin_timedelta
internal: true
- platform: homeassistant
id: landing_humidity
entity_id: sensor.lumi_lumi_weather_28025d04_humidity
internal: true
- platform: homeassistant
id: fish_tank_temperature
entity_id: sensor.fish_tank_temperature
internal: true
text_sensor:
- platform: sun
name: Sun Next Sunrise
type: sunrise
id: sunrise
- platform: sun
name: Sun Next Sunset
type: sunset
id: sunset
# Sensors read from homeassistant
- platform: homeassistant
entity_id: sensor.next_bin_collection
id: next_bin
internal: true
- platform: homeassistant
entity_id: "${ha_climate_component}"
attribute: hvac_action
id: climate_state
internal: true
- platform: homeassistant
entity_id: sensor.charging_status
id: car_charging_status
internal: true
- platform: homeassistant
entity_id: sensor.holmfirth_weather
id: fc_weather
internal: true
filters:
# Convert the text to the MDI icon
- map:
- clear-night -> 󰖔
- cloudy -> 󰖐
- partlycloudy -> 󰖕
- fog -> 󰖑
- hail -> 󰖒
- lightning -> 󰖓
- lightning-rainy -> 󰙾
- pouring -> 󰖖
- rainy -> 󰖗
- snowy -> 󰼶
- snowy-rainy -> 󰙿
- sunny -> 󰖙
- windy -> 󰖝
- windy-variant -> 󰖞
- exceptional -> 󰼸
script:
- id: refresh_display
then:
- component.update: t5_display
font:
- file: "SourceSansPro-Regular.ttf"
id: font_footer
size: 28
- file: "SourceSansPro-Regular.ttf"
id: font_value
size: 56
- file: "SourceSansPro-Bold.ttf"
id: font_name
size: 42
- file: 'materialdesignicons-webfont.ttf'
id: font_icons_footer
size: 28
glyphs:
- "\U000F058E" # Water percent
- "\U000F0E02" # Thermometer down
- "\U000F0E03" # Thermometer up
- "\U000F059D" # Windy
- file: 'materialdesignicons-webfont.ttf'
id: font_icons
size: 160
glyphs:
- "\U000F0594" # clear-night
- "\U000F0590" # cloudy
- "\U000F0595" # partlycloudy
- "\U000F0591" # fog
- "\U000F0592" # hail
- "\U000F0593" # lightning
- "\U000F067E" # lightning-rainy
- "\U000F0596" # pouring
- "\U000F0597" # rainy
- "\U000F0F36" # snowy
- "\U000F067F" # snowy-rainy
- "\U000F0599" # sunny
- "\U000F059D" # windy
- "\U000F059E" # windy-variant
- "\U000F0F38" # exceptional
- file: 'materialdesignicons-webfont.ttf'
id: font_icons_small
size: 56
glyphs:
- "\U000F10C2" # Temperature High
- "\U000F10C3" # Temperature Low
- "\U000F0E04" # Thermometer Minus
- "\U000F0E05" # Thermometer Plus
- "\U000F0510" # Thermometer Lines
- "\U000F051F" # Timer sand
- "\U000F0438" # Heater On
- "\U000F0AD7" # Heater Disabled
- "\U000F0AD8" # Heater Off
- "\U000F081B" # Door Closed
- "\U000F10AF" # Door Closed Locked
- "\U000F081C" # Door Open
- "\U000F0130" # Empty circle
- "\U000F11BB" # Dryer Off
- "\U000F0917" # Dryer On
- "\U000F11BD" # Washing Machine Off
- "\U000F072A" # Washing Machine On
- "\U000F05F1" # Ev Station
- "\U000F151E" # Type 2 Connector
- "\U000F059C" # Sun
- "\U000F059B" # Sun
- "\U000F1011" # Blind Open
- "\U000F00AC" # Blind Closed
graph:
# Show bare-minimum auto-ranged graph
- id: house_temperature_graph
duration: 6h
width: 250
height: 125
border: false
y_grid: 1.0
traces:
- sensor: climate_set_point
line_type: DASHED
line_thickness: 3
- sensor: climate_current_temp
line_type: SOLID
line_thickness: 3
display:
- platform: lilygo_t5_47_display
id: t5_display
rotation: 90
update_interval: 5s
lambda: |-
#define xres 540
#define yres 960
// Pixel locations of the buttons (from bottom [not USB-C end] to top)
#define button_1_y yres - 245
#define button_delta 67
#define button_2_y button_1_y - button_delta
#define button_3_y button_2_y - button_delta
#define button_4_y button_3_y - button_delta
#define button_5_y button_4_y - button_delta
#define x_pad 10 // border padding
#define y_pad 10 // border padding
#define cat_pad 85 // padding before category
#define val_pad 70 // padding before value
#define icon_pad 40 //padding after icons
#define x1n 20 //x position 1st column name
#define x1v 25 //x position 1st column value
#define x1i 50 //x position 1st column icon
#define x2n xres/2 //x position 2nd column name
#define x2v xres/2 //x position 2nd column value
#define x2i xres/2 //x position 1st column icon
#define icon_large 160 // height of large icon
#define icon_small 56 // height of large icon
#define icon_footer 28 // height of large icon
#define div_thickness 2
int y = 0;
// Date
it.strftime(xres/2, y+y_pad, id(font_name), TextAlign::TOP_CENTER, "%A %d %b %Y", id(ntp).now());
y+=val_pad+cat_pad+y_pad+10;
// Weather Icon
#define weather_icon_x xres/4 - icon_large/2
int weather_row = icon_footer + y_pad;
int weather_y = y + icon_large/2 - 20;
it.printf(weather_icon_x, weather_y, id(font_icons), TextAlign::BASELINE_LEFT, "%s", id(fc_weather).state.c_str());
weather_y += weather_row;
it.printf(weather_icon_x, weather_y, id(font_icons_footer), TextAlign::BASELINE_LEFT, "\U000F0E03");
it.printf(weather_icon_x + icon_footer + 5, weather_y, id(font_footer), TextAlign::BASELINE_LEFT, "%.0f °C", id(forecast_temp_high).state);
weather_row = icon_footer + y_pad/2;
weather_y += weather_row;
it.printf(weather_icon_x, weather_y, id(font_icons_footer), TextAlign::BASELINE_LEFT, "\U000F0E02");
it.printf(weather_icon_x + icon_footer + 5, weather_y, id(font_footer), TextAlign::BASELINE_LEFT, "%.0f °C", id(forecast_temp_low).state);
weather_y += weather_row;
// small shift in x for relative icon widths
it.printf(weather_icon_x-5, weather_y, id(font_icons_footer), TextAlign::BASELINE_LEFT, "\U000F058E");
it.printf(weather_icon_x + icon_footer + 5, weather_y, id(font_footer), TextAlign::BASELINE_LEFT, "%.0f %%", id(forecast_percip_prob).state);
weather_y += weather_row;
it.printf(weather_icon_x-2, weather_y, id(font_icons_footer), TextAlign::BASELINE_LEFT, "\U000F059D");
it.printf(weather_icon_x + icon_footer + 5, weather_y, id(font_footer), TextAlign::BASELINE_LEFT, "%.0f mph", id(forecast_wind_speed).state);
// Heating Status
#define climate_x xres / 2 + x_pad*2 + icon_small / 2
#define climate_y y - 40
if (id(climate_state).state == "heating") {
it.printf(climate_x, climate_y, id(font_icons_small), TextAlign::CENTER, "\U000F0438");
} else if (id(climate_state).state == "off") {
it.printf(climate_x, climate_y, id(font_icons_small), TextAlign::CENTER, "\U000F0AD8");
} else {
it.printf(climate_x, climate_y, id(font_icons_small), TextAlign::CENTER, "\U000F0AD7");
}
it.printf(climate_x + icon_pad, climate_y+25, id(font_value), TextAlign::BASELINE_LEFT, "%.1f °C", id(climate_set_point).state);
y+=val_pad;
it.printf(climate_x, climate_y, id(font_icons_small), TextAlign::CENTER, "\U000F10C3");
it.printf(climate_x + icon_pad, climate_y+18, id(font_value), TextAlign::BASELINE_LEFT, "%.1f °C", id(climate_current_temp).state);
y+=20;
it.graph(xres / 2 + 10, y, id(house_temperature_graph));
// Inline with top button
// Row one
#define icon_x_1 icon_small/2 + xres / 3
#define icon_x_2 icon_x_1 + (xres / 3) + icon_small/2
#define sensor_y_shift icon_small + icon_footer + y_pad*4
y = button_5_y + icon_small/4;
if (!id(backdoor_locked).state) {
it.printf(icon_x_1, y, id(font_icons_small), TextAlign::CENTER, "\U000F10AF");
} else if (!id(backdoor).state) {
it.printf(icon_x_1, y, id(font_icons_small), TextAlign::CENTER, "\U000F081B");
} else {
it.printf(icon_x_1, y, id(font_icons_small), TextAlign::CENTER, "\U000F081C");
}
it.printf(icon_x_1, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "Backdoor");
// column 2
if (id(car_charging_status).state == "connected") {
it.printf(icon_x_2, y, id(font_icons_small), TextAlign::CENTER, "\U000F151E");
} else if (id(car_charging_status).state == "charging") {
it.printf(icon_x_2, y, id(font_icons_small), TextAlign::CENTER, "\U000F05F1");
} else {
it.printf(icon_x_2, y, id(font_icons_small), TextAlign::CENTER, "\U000F0130");
}
it.printf(icon_x_2, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "Car");
// Second Row
y += sensor_y_shift;
// Washer
if (id(washer).state) {
it.printf(icon_x_1, y, id(font_icons_small), TextAlign::CENTER, "\U000F072A");
} else {
it.printf(icon_x_1, y, id(font_icons_small), TextAlign::CENTER, "\U000F11BD");
}
it.printf(icon_x_1, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "Washer");
// column 2
// Dryer
if (id(dryer).state) {
it.printf(icon_x_2, y, id(font_icons_small), TextAlign::CENTER, "\U000F0917");
} else {
it.printf(icon_x_2, y, id(font_icons_small), TextAlign::CENTER, "\U000F11BB");
}
it.printf(icon_x_2, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "Dryer");
// Third Row
y += sensor_y_shift;
it.printf(icon_x_1, y, id(font_value), TextAlign::CENTER, "%.0f", id(next_bin_days).state);
it.printf(icon_x_1, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "days til %s bin", id(next_bin).state.c_str());
// column 2
it.printf(icon_x_2, y, id(font_value), TextAlign::CENTER, "%.0f %%", id(landing_humidity).state);
it.printf(icon_x_2, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "Humidity");
// Forth Row
y += sensor_y_shift;
it.printf(icon_x_1, y, id(font_icons_small), TextAlign::CENTER, "\U000F059C");
it.printf(icon_x_1, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "%s", id(sunrise).state.c_str());
it.printf(icon_x_2, y, id(font_icons_small), TextAlign::CENTER, "\U000F059B");
it.printf(icon_x_2, y + icon_small/2 + y_pad, id(font_footer), TextAlign::CENTER, "%s", id(sunset).state.c_str());
// Buttons
it.printf(x1n, button_5_y + icon_small/2 - 5, id(font_icons_small), TextAlign::BASELINE_LEFT, "\U000F0510");
it.printf(x1n, button_4_y + icon_small/2 - 5, id(font_icons_small), TextAlign::BASELINE_LEFT, "\U000F1011");
it.printf(x1n, button_3_y + icon_small/2 - 5, id(font_icons_small), TextAlign::BASELINE_LEFT, "\U000F00AC");
// Vertical Divider
it.filled_rectangle(x1n + 70, button_5_y - icon_small / 2, div_thickness, icon_small * 3 + y_pad * 3);
// Footer
it.strftime(x_pad, yres-y_pad/2, id(font_footer), TextAlign::BASELINE_LEFT, "Updated: %H:%M", id(ntp).now());
it.printf(xres-x_pad, yres-y_pad/2, id(font_footer), TextAlign::BASELINE_RIGHT, "%.2fV/%.0f%%", id(batt_volt).state, id(batt).state);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment