Skip to content

Instantly share code, notes, and snippets.

@dariusk
Last active August 6, 2025 18:55
Show Gist options
  • Select an option

  • Save dariusk/25b4d73319d793981c9100a0e32831bf to your computer and use it in GitHub Desktop.

Select an option

Save dariusk/25b4d73319d793981c9100a0e32831bf to your computer and use it in GitHub Desktop.
ESPHome e-ink dashboard with weather, tri-met transit, and cute art
# This isn't my whole configuration.yaml, just the parts that I dropped into my existing
# configuration.yaml to get the dashboard working -Darius
# For Portland-area transit stuff, I use the Trimet developer API. You can get the API key ("appId") here: https://developer.trimet.org/appid/registration/
sensor:
- platform: rest
name: Trimet 20 E 0
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=813&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ iif(now() > (((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime),'Now',time_until(((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime, 1)) }}
- platform: rest
name: Trimet 20 E 1
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=813&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ time_until(((value_json.resultSet.arrival[1].estimated | int) / 1000) | timestamp_local | as_datetime, 1) }}
- platform: rest
name: Trimet 20 W 0
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=814&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ iif(now() > (((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime),'Now',time_until(((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime, 1)) }}
- platform: rest
name: Trimet 20 W 1
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=814&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ time_until(((value_json.resultSet.arrival[1].estimated | int) / 1000) | timestamp_local | as_datetime, 1) }}
- platform: rest
name: Trimet 72 N 0
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=7936&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ iif(now() > (((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime),'Now',time_until(((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime, 1)) }}
- platform: rest
name: Trimet 72 N 1
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=7936&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ time_until(((value_json.resultSet.arrival[1].estimated | int) / 1000) | timestamp_local | as_datetime, 1) }}
- platform: rest
name: Trimet 72 S 0
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=7937&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ iif(now() > (((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime),'Now',time_until(((value_json.resultSet.arrival[0].estimated | int) / 1000) | timestamp_local | as_datetime, 1)) }}
- platform: rest
name: Trimet 72 S 1
resource: "https://developer.trimet.org/ws/V2/arrivals?locIDs=7937&appID=APP_DEV_KEY_GOES_HERE"
scan_interval: 240
method: GET
json_attributes_path: '$.resultSet'
json_attributes: 'arrival'
value_template: >
{{ time_until(((value_json.resultSet.arrival[1].estimated | int) / 1000) | timestamp_local | as_datetime, 1) }}
template:
# I just set this sensor to "on" all the time, see notes in dashboard.yaml
- binary_sensor:
- name: Weatherman Motion Detected
unique_id: "dfa78de7-d761-425f-9731-86f1af332eac"
device_class: "occupancy"
delay_off: 2min
state: >-
on
# Bundle up all the data to send over to Weatherman (ESPHome device).
# I set this to every two minutes -Darius
- trigger:
platform: time_pattern
minutes: "/2"
sensor:
- name: Weatherman Data
state: "OK"
attributes:
bus_status_burnside_e_0: >
{{ states('sensor.trimet_20_e_0') | upper }}
bus_status_burnside_e_1: >
{{ states('sensor.trimet_20_e_1') | upper }}
bus_status_burnside_w_0: >
{{ states('sensor.trimet_20_w_0') | upper }}
bus_status_burnside_w_1: >
{{ states('sensor.trimet_20_w_1') | upper }}
bus_status_trimet_72_n_0: >
{{ states('sensor.trimet_72_n_0') | upper }}
bus_status_trimet_72_n_1: >
{{ states('sensor.trimet_72_n_1') | upper }}
bus_status_trimet_72_s_0: >
{{ states('sensor.trimet_72_s_0') | upper }}
bus_status_trimet_72_s_1: >
{{ states('sensor.trimet_72_s_1') | upper }}
weather_condition_now: >
{{ states('sensor.pirateweather_icon_0h') }}
weather_condition_0: >
{{ states('sensor.pirateweather_icon_0h') }}
weather_temperature_0: >
{{ states('sensor.pirateweather_temperature_0h') }}
weather_timestamp_0: >
{{ as_timestamp(now() + timedelta( hours = 0 )) | timestamp_custom('%-I %p') }}
weather_condition_1: >
{{ states('sensor.pirateweather_icon_3h') }}
weather_temperature_1: >
{{ states('sensor.pirateweather_temperature_3h') }}
weather_timestamp_1: >
{{ as_timestamp(now() + timedelta( hours = 3 )) | timestamp_custom('%-I %p') }}
weather_condition_2: >
{{ states('sensor.pirateweather_icon_6h') }}
weather_temperature_2: >
{{ states('sensor.pirateweather_temperature_6h') }}
weather_timestamp_2: >
{{ as_timestamp(now() + timedelta( hours = 6 )) | timestamp_custom('%-I %p') }}
weather_condition_3: >
{{ states('sensor.pirateweather_icon_9h') }}
weather_temperature_3: >
{{ states('sensor.pirateweather_temperature_9h') }}
weather_timestamp_3: >
{{ as_timestamp(now() + timedelta( hours = 9 )) | timestamp_custom('%-I %p') }}
# WEATHERMAN DASHBOARD
# For Home Assistant and ESPHome
# Designed by Madelena Mak 2022 - https://mmak.es
# Modified by Darius Kazemi 2025
# Cue "Blame it on the Weatherman" by B*Witched!
esphome:
name: "weatherman"
on_boot:
priority: 200.0
then:
- component.update: eink_display
- wait_until:
condition:
lambda: 'return id(data_updated) == true;'
# Wait a bit longer so all the items are received
- delay: 5s
- logger.log: "Initial sensor data received: Refreshing display..."
- lambda: 'id(initial_data_received) = true;'
- script.execute: update_screen
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
# The following `platform` listing is a fix required after HA updates in July 2025
# https://esphome.io/changelog/2025.7.0#web-server-ota-platform
ota:
- platform: esphome
- platform: web_server
button:
- platform: shutdown
name: "Weatherman - Shutdown"
- platform: restart
name: "Weatherman - Restart"
- platform: template
name: "Weatherman - Refresh Screen"
entity_category: config
on_press:
- script.execute: update_screen
# Global variables for detecting if the display needs to be refreshed. (Thanks @paviro!)
globals:
- id: data_updated
type: bool
restore_value: no
initial_value: 'false'
- id: initial_data_received
type: bool
restore_value: no
initial_value: 'false'
- id: recorded_display_refresh
type: int
restore_value: yes
initial_value: '0'
# Script for updating screen - Refresh display and publish refresh count and time. (Thanks @paviro!)
script:
- id: update_screen
then:
- lambda: 'id(data_updated) = false;'
- component.update: eink_display
- lambda: 'id(recorded_display_refresh) += 1;'
- lambda: 'id(display_last_update).publish_state(id(homeassistant_time).now().timestamp);'
# Check whether the display needs to be refreshed every two minutes,
# based on whether new data is received or motion is detected. (Thanks @paviro!)
time:
- platform: homeassistant
id: homeassistant_time
on_time:
- seconds: 0
minutes: /2
then:
- if:
condition:
lambda: 'return id(data_updated) == true;'
then:
- if:
condition:
binary_sensor.is_on: motion_detected
then:
- logger.log: "Sensor data updated and activity in home detected: Refreshing display..."
- script.execute: update_screen
else:
- logger.log: "Sensor data updated but no activity in home - skipping display refresh."
else:
- logger.log: "No sensors updated - skipping display refresh."
# Wifi information
wifi:
ssid: SSID_GOES_HERE
password: PASSWORD_GOES_HERE
# Enable fallback hotspot (captive portal) in case wifi connection fails. These values can be anything you want, they are
# for a temporary access point this will set up (I think?? -Darius)
ap:
ssid: MAKE_UP_AN_SSID
password: MAKE_UP_A_PASSWORD
# I did not bother optimizing the glyphs here, there are probably some that can be removed from the title fonts
# but my device isn't complaining so I'm not bothering. -Darius
# Include custom fonts
font:
- file: 'fonts/GothamRnd-Book.ttf'
id: font_small_book
size: 18
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_large_bold
size: 108
glyphs: [' ', '-', '°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'F']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_title
size: 54
glyphs: ['P', 'O', 'T', 'H', 'R', 'L', 'I', 'N', ' ', 'M', 'E']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_medium_bold
size: 30
# glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'M', 'I', 'N']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_small_bold
size: 24
# glyphs: [' ', '-', '°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'M', 'I', 'N']
# Include Material Design Icons font
# Thanks to https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/16
# Note: my weather app only supports a small number of the weather states covered by these glyphs. I could optimize them
# to only be the subset I need and save a little memory on device, but also it doesn't matter for this device. -Darius
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_large
size: 96
glyphs: &mdi-weather-glyphs
- "\U000F0590" # mdi-weather-cloudy
- "\U000F0F2F" # mdi-weather-cloudy-alert
- "\U000F0E6E" # mdi-weather-cloudy-arrow-right
- "\U000F0591" # mdi-weather-fog
- "\U000F0592" # mdi-weather-hail
- "\U000F0F30" # mdi-weather-hazy
- "\U000F0898" # mdi-weather-hurricane
- "\U000F0593" # mdi-weather-lightning
- "\U000F067E" # mdi-weather-lightning-rainy
- "\U000F0594" # mdi-weather-night
- "\U000F0F31" # mdi-weather-night-partly-cloudy
- "\U000F0595" # mdi-weather-partly-cloudy
- "\U000F0F32" # mdi-weather-partly-lightning
- "\U000F0F33" # mdi-weather-partly-rainy
- "\U000F0F34" # mdi-weather-partly-snowy
- "\U000F0F35" # mdi-weather-partly-snowy-rainy
- "\U000F0596" # mdi-weather-pouring
- "\U000F0597" # mdi-weather-rainy
- "\U000F0598" # mdi-weather-snowy
- "\U000F0F36" # mdi-weather-snowy-heavy
- "\U000F067F" # mdi-weather-snowy-rainy
- "\U000F0599" # mdi-weather-sunny
- "\U000F0F37" # mdi-weather-sunny-alert
- "\U000F14E4" # mdi-weather-sunny-off
- "\U000F059A" # mdi-weather-sunset
- "\U000F059B" # mdi-weather-sunset-down
- "\U000F059C" # mdi-weather-sunset-up
- "\U000F0F38" # mdi-weather-tornado
- "\U000F059D" # mdi-weather-windy
- "\U000F059E" # mdi-weather-windy-variant
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_medium
size: 44
glyphs: *mdi-weather-glyphs
# This is an image file I made that is a transparent PNG with some art on it from the game Deltarune. Just for fun.
image:
- file: 'images/dr.png'
type: BINARY
id: 'deltarune'
# Check if motion is detected in the living room.
# Note: I set this sensor to be "ON" all the time since I don't actually own a motion sensor. The reason
# there's a motion sensor at all is because you don't want to update the display every minute of every day,
# because the display itself is only rated for a few million refreshes. Every refresh you save extends device life.
# So the original implementation only updates the display when motion is detected nearby. What I did instead
# was connect the display to a smart power plug that turns off from 11pm to 6am when I don't really need it. -Darius
binary_sensor:
- platform: homeassistant
entity_id: binary_sensor.weatherman_motion_detected
id: motion_detected
sensor:
# Create sensors for monitoring Weatherman remotely.
- platform: template
name: "Weatherman - Display Last Update"
device_class: timestamp
entity_category: "diagnostic"
id: display_last_update
- platform: template
name: "Weatherman - Recorded Display Refresh"
accuracy_decimals: 0
unit_of_measurement: "Refreshes"
state_class: "total_increasing"
entity_category: "diagnostic"
lambda: 'return id(recorded_display_refresh);'
- platform: wifi_signal
name: "Weatherman - WiFi Signal Strength"
id: wifisignal
unit_of_measurement: "dBm"
entity_category: "diagnostic"
update_interval: 60s
# Call Transit and Weather sensors from HA.
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_0
id: weather_temperature_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_1
id: weather_temperature_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_2
id: weather_temperature_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_temperature_3
id: weather_temperature_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
text_sensor:
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_now
id: weather_condition_now
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_0
id: weather_condition_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_0
id: weather_timestamp_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_1
id: weather_condition_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_1
id: weather_timestamp_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_2
id: weather_condition_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_2
id: weather_timestamp_2
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_condition_3
id: weather_condition_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: weather_timestamp_3
id: weather_timestamp_3
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_burnside_e_0
id: bus_status_burnside_e_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_burnside_e_1
id: bus_status_burnside_e_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_burnside_w_0
id: bus_status_burnside_w_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_burnside_w_1
id: bus_status_burnside_w_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_trimet_72_n_0
id: bus_status_trimet_72_n_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_trimet_72_n_1
id: bus_status_trimet_72_n_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_trimet_72_s_0
id: bus_status_trimet_72_s_0
on_value:
then:
- lambda: 'id(data_updated) = true;'
- platform: homeassistant
entity_id: sensor.weatherman_data
attribute: bus_status_trimet_72_s_1
id: bus_status_trimet_72_s_1
on_value:
then:
- lambda: 'id(data_updated) = true;'
# Define colors
# This design is white on black so this is necessary.
color:
- id: color_bg
red: 0%
green: 0%
blue: 0%
white: 0%
- id: color_text
red: 0%
green: 0%
blue: 0%
white: 100%
# Pins for Waveshare ePaper ESP Board
spi:
clk_pin: GPIO13
mosi_pin: GPIO14
# Now render everything on the ePaper screen.
display:
- platform: waveshare_epaper
id: eink_display
cs_pin: GPIO15
dc_pin: GPIO27
busy_pin:
number: GPIO25
inverted: true
reset_pin: GPIO26
reset_duration: 2ms
model: 7.50inV2
update_interval: never
rotation: 90°
lambda: |-
// Map weather states to MDI characters.
std::map<std::string, std::string> weather_icon_map
{
{"cloudy", "\U000F0590"},
{"cloudy-alert", "\U000F0F2F"},
{"cloudy-arrow-right", "\U000F0E6E"},
{"fog", "\U000F0591"},
{"sleet", "\U000F0592"},
{"hazy", "\U000F0F30"},
{"hurricane", "\U000F0898"},
{"lightning", "\U000F0593"},
{"lightning-rainy", "\U000F067E"},
{"clear-night", "\U000F0594"},
{"partly-cloudy-night", "\U000F0F31"},
{"partly-cloudy-day", "\U000F0595"},
{"partly-lightning", "\U000F0F32"},
{"partly-rainy", "\U000F0F33"},
{"partly-snowy", "\U000F0F34"},
{"partly-snowy-rainy", "\U000F0F35"},
{"pouring", "\U000F0596"},
{"rain", "\U000F0597"},
{"snow", "\U000F0598"},
{"snowy-heavy", "\U000F0F36"},
{"snowy-rainy", "\U000F067F"},
{"clear-day", "\U000F0599"},
{"sunny-alert", "\U000F0F37"},
{"sunny-off", "\U000F14E4"},
{"sunset", "\U000F059A"},
{"sunset-down", "\U000F059B"},
{"sunset-up", "\U000F059C"},
{"tornado", "\U000F0F38"},
{"wind", "\U000F059D"},
{"windy-variant", "\U000F059E"},
};
// Show loading screen before data is received.
if (id(initial_data_received) == false) {
it.printf(240, 390, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "WAITING FOR DATA...");
} else {
// Weather Section
it.printf(100, 158-114, id(font_mdi_large), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());
it.printf(300, 158-114, id(font_large_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°F", id(weather_temperature_0).state);
it.printf(105, 282-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_0).state.c_str());
it.printf(105, 306-104, id(font_mdi_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_0).state.c_str()].c_str());
it.printf(105, 354-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°F", id(weather_temperature_0).state);
it.printf(195, 282-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_1).state.c_str());
it.printf(195, 306-104, id(font_mdi_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_1).state.c_str()].c_str());
it.printf(195, 354-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°F", id(weather_temperature_1).state);
it.printf(285, 282-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_2).state.c_str());
it.printf(285, 306-104, id(font_mdi_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_2).state.c_str()].c_str());
it.printf(285, 354-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°F", id(weather_temperature_2).state);
it.printf(375, 282-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(weather_timestamp_3).state.c_str());
it.printf(375, 306-104, id(font_mdi_medium), color_text, TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_3).state.c_str()].c_str());
it.printf(375, 354-104, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%2.0f°F", id(weather_temperature_3).state);
// Transit section, shows Portland bus arrival times from some custom sensors I set up previously
it.print(125, 330, id(font_medium_bold), color_text, TextAlign::TOP_CENTER, "20 W");
it.printf(125, 372, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_burnside_w_0).state.c_str());
it.printf(125, 405, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_burnside_w_1).state.c_str());
it.print(355, 330, id(font_medium_bold), color_text, TextAlign::TOP_CENTER, "20 E");
it.printf(355, 372, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_burnside_e_0).state.c_str());
it.printf(355, 405, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_burnside_e_1).state.c_str());
it.print(125, 430+32, id(font_medium_bold), color_text, TextAlign::TOP_CENTER, "72 N");
it.printf(125, 472+32, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_trimet_72_n_0).state.c_str());
it.printf(125, 505+32, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_trimet_72_n_1).state.c_str());
it.print(355, 430+32, id(font_medium_bold), color_text, TextAlign::TOP_CENTER, "72 S");
it.printf(355, 472+32, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_trimet_72_s_0).state.c_str());
it.printf(355, 505+32, id(font_small_bold), color_text, TextAlign::TOP_CENTER, "%s", id(bus_status_trimet_72_s_1).state.c_str());
// Cute image of Lanino and Elnina!
it.image(75, 610, id(deltarune));
// Refresh Timestamp
// Code by EnsconcE from https://community.home-assistant.io/t/esphome-show-time/348903
char str[17];
time_t currTime = id(homeassistant_time).now().timestamp;
strftime(str, sizeof(str), "%H:%M", localtime(&currTime));
it.printf(0, 0, id(font_small_book), color_text, TextAlign::TOP_LEFT, "REFRESHED AT %s", str);
}
captive_portal:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment