display link
driver board link
code is below
substitutions:
name: barn_dashboard
friendly_name: Barn Dashboard
room_name: Barn
gpio_spi_clk_pin: GPIO13
gpio_spi_mosi_pin: GPIO14
gpio_cs_pin: GPIO15
gpio_dc_pin: GPIO27
gpio_reset_pin: GPIO26
gpio_busy_pin: GPIO25
esphome:
name: ${name}
friendly_name: ${friendly_name}
min_version: 2024.6.0
name_add_mac_suffix: false
on_boot:
then:
- switch.turn_on: display_power
- script.execute: update_screen
on_shutdown:
then:
- switch.turn_off: display_power
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
static_ip: 192.168.1.182
gateway: 192.168.1.1
subnet: 255.255.255.0
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Barn-Dashboard Fallback Hotspot"
password: "Q9LbdglSFG4r"
captive_portal:
# Enable Web server.
web_server:
port: 80
font:
- file: 'fonts/Roboto-Medium.ttf'
id: roboto_med_28
size: 30
- file: 'fonts/Roboto-Regular.ttf'
id: footer_font
size: 12
glyphs:
['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/','º','µ','³']
- file: 'fonts/Roboto-Regular.ttf'
id: font_medium
size: 20
glyphs:
['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/','º','µ','³']
- file: 'fonts/Roboto-Medium.ttf'
id: font_small
size: 14
glyphs:
['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/','º','µ','³']
- file: 'fonts/Roboto-Bold.ttf'
id: font_large
size: 24
- file: 'fonts/materialdesignicons-webfont.ttf'
id: mdi_small
size: 28
glyphs: [
# Wifi
'', # mdi-wifi-strength-alert-outline
'', # mdi-wifi-strength-1
'', # mdi-wifi-strength-2
'', # mdi-wifi-strength-3
'', # mdi-wifi-strength-4
]
- file: 'fonts/materialdesignicons-webfont.ttf'
id: mdi_wifi
size: 20
glyphs: [
# Wifi
'', # mdi-wifi-strength-alert-outline
'', # mdi-wifi-strength-1
'', # mdi-wifi-strength-2
'', # mdi-wifi-strength-3
'' # mdi-wifi-strength-4
]
- file: 'fonts/materialdesignicons-webfont.ttf'
id: mdi_med
size: 30
glyphs: [
# Wifi
'', # mdi-wifi-strength-alert-outline
'', # mdi-wifi-strength-1
'', # mdi-wifi-strength-2
'', # mdi-wifi-strength-3
'', # mdi-wifi-strength-4
'' # mdi-alert
]
# Include Material Design Icons font
# Thanks to https://community.home-assistant.io/t/display-materialdesign-icons-on-esphome-attached-to-screen/199790/16
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_large
size: 90
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-clear-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: 30
glyphs: *mdi-weather-glyphs
time:
- platform: homeassistant
id: homeassistant_time
on_time_sync:
- component.update: uptime_timestamp
text_sensor:
- platform: version
name: ${friendly_name} ESPHome version
- platform: homeassistant
id: weather_now
entity_id: sensor.pirateweather_hourly_summary
binary_sensor:
- platform: status
name: ${friendly_name} Status
id: barn_dash_status
- platform: homeassistant
name: "OTA Mode"
id: otamode
entity_id: input_boolean.display_ota_mode
switch:
- platform: restart
name: $(friendly_name) Restart
- platform: gpio
pin: GPIO32 #display power enable pin
id: display_power
internal: true
button:
- platform: restart
name: "Dashboard - Restart"
- platform: template
name: "Dashboard - Refresh Screen"
entity_category: config
on_press:
- script.execute: update_screen
sensor:
- platform: uptime
name: $(friendly_name) Uptime Sec
id: uptime_sec
internal: true
- platform: homeassistant
entity_id: sensor.shelf_temp
id: shelf_temp
- platform: homeassistant
entity_id: sensor.shelf_humidity
id: shelf_humidity
- platform: homeassistant
entity_id: sensor.outdoor_humidity
id: outdoor_humidity
- platform: homeassistant
entity_id: sensor.outdoor_temperature
id: outdoor_temperature
- platform: homeassistant
entity_id: sensor.greenhouse_temp
id: temperature_greenhouse
- platform: homeassistant
entity_id: sensor.greenhouse_humidity
id: greenhouse_humid
- platform: homeassistant
entity_id: sensor.barn_temp
id: barn_temperature
- platform: homeassistant
entity_id: sensor.barn_humidity
id: barn_humidity
- platform: homeassistant
entity_id: sensor.bed_temp_1
id: bed_temp_1
- platform: homeassistant
entity_id: sensor.bed_temp_2
id: bed_temp_2
- platform: homeassistant
entity_id: sensor.bed_temp_3
id: bed_temp_3
- platform: homeassistant
entity_id: sensor.bed_temp_4
id: bed_temp_4
- platform: homeassistant
entity_id: sensor.soil_moisture_4_in_2
id: soil_moisture_4_percent
- platform: homeassistant
entity_id: sensor.soil_moisture_8_pc
id: moisture_soil_8_pct
- platform: homeassistant
entity_id: sensor.soil_moisture_4_in
id: soil_moisture_4_in
- platform: homeassistant
entity_id: sensor.soil_moisture_8_in
id: in_8_moisture
- platform: homeassistant
entity_id: sensor.soil_moisture_12_in
id: in_12_moisture
- platform: homeassistant
entity_id: sensor.soil_moisture_16_in
id: in_16_moisture
- platform: homeassistant
entity_id: sensor.today_s_rainfall
id: rainfall_today
- platform: homeassistant
entity_id: sensor.rainfall_last_7_days
id: rainfall_7_day
- platform: homeassistant
entity_id: sensor.monthly_rainfall
id: rainfall_monthly
- platform: homeassistant
entity_id: sensor.yearly_rainfall
id: rainfall_yearly
- platform: homeassistant
entity_id: sensor.solar_energy
id: solar_energy
- platform: wifi_signal
name: "WiFi Signal Sensor"
id: wifisignal
update_interval: 60s
- platform: template
id: uptime_timestamp
name: $(friendly_name) Uptime
device_class: "timestamp"
accuracy_decimals: 0
update_interval: never
lambda: |-
static float timestamp = (
id(homeassistant_time).utcnow().timestamp - id(uptime_sec).state
);
return timestamp;
graph:
- id: temperature_graph
duration: 48h
x_grid: 30min
y_grid: 5.0 # degF/div
width: 500
height: 115
traces:
- sensor: temperature_greenhouse
line_type: SOLID
line_thickness: 4
- sensor: barn_temperature
line_type: DASHED
line_thickness: 4
continuous: true
- sensor: outdoor_temperature
line_type: DOTTED
line_thickness: 4
script:
- id: update_screen
then:
- component.update: screen
spi:
clk_pin: $gpio_spi_clk_pin
mosi_pin: $gpio_spi_mosi_pin
id: epaper_display
display:
- platform: waveshare_epaper
cs_pin: $gpio_cs_pin
busy_pin: $gpio_busy_pin
reset_pin: $gpio_reset_pin
dc_pin: $gpio_dc_pin
#model: 7.50in-bc
#model: 7.50inV2
# model: 7.50in
#model: 7.50in-bV2
model: 7.50inV2alt
update_interval: 5min
reset_duration: 2ms
id: screen
lambda: |-
int offsetY = 140;
// Map weather states to MDI characters.
std::map<std::string, std::string> weather_icon_map
{
{"Cloudy", "\U000F0590"},
{"cloudy", "\U000F0590"},
{"cloudy-alert", "\U000F0F2F"},
{"cloudy-arrow-right", "\U000F0E6E"},
{"Fog", "\U000F0591"},
{"Hail", "\U000F0592"},
{"Hazy", "\U000F0F30"},
{"hurricane", "\U000F0898"},
{"Lightning", "\U000F0593"},
{"lightning-rainy", "\U000F067E"},
{"Clear Night", "\U000F0594"},
{"Night Partly Cloudy", "U000F0F31"},
{"Partly Cloudy", "\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"},
{"Sunny", "\U000F0599"},
{"sunny-alert", "\U000F0F37"},
{"sunny-off", "\U000F14E4"},
{"sunset", "\U000F059A"},
{"sunset-down", "\U000F059B"},
{"sunset-up", "\U000F059C"},
{"tornado", "\U000F0F38"},
{"Windy", "\U000F059D"},
{"windy-variant", "\U000F059E"},
};
char unit[] = "cbn";
float temp_outdoor = id(outdoor_temperature).state;
float humid_outdoor = id(outdoor_humidity).state;
float energy_solar = id(solar_energy).state;
float temp_barn = id(barn_temperature).state;
float greenhouse_temp = id(temperature_greenhouse).state;
float humid_greenhouse = id(greenhouse_humid).state;
float humid_barn = id(barn_humidity).state;
float temp_bed_1 = id(bed_temp_1).state;
float temp_bed_2 = id(bed_temp_2).state;
float temp_bed_3 = id(bed_temp_3).state;
float temp_bed_4 = id(bed_temp_4).state;
float soil_4in_percent = id(soil_moisture_4_percent).state;
float soil_percent_8in = id(moisture_soil_8_pct).state;
int soil_4in_cnb = id(soil_moisture_4_in).state;
int soil_8in_cnb = id(in_8_moisture).state;
int soil_12in_cnb = id(in_12_moisture).state;
int soil_16in_cnb = id(in_16_moisture).state;
float todays_rainfall =id(rainfall_today).state;
float day_7_rainfall = id(rainfall_7_day).state;
float monthly_rainfall = id(rainfall_monthly).state;
float yearly_rainfall = id(rainfall_yearly).state;
float soil_12in_pct = id(in_12_moisture).state;
float soil_16in_pct = id(in_16_moisture).state;
float temp_shelf = id(shelf_temp).state;
float humidity_shelf = id(shelf_humidity).state;
/* Date and Time */
it.strftime(400, 10, id(font_medium), TextAlign::CENTER_HORIZONTAL, "%A %B %d, %Y", id(homeassistant_time).now());
it.strftime(400, 30, id(font_large), TextAlign::CENTER_HORIZONTAL, "%H:%M:%S", id(homeassistant_time).now());
/* Current Weather */
it.printf(400, 60, id(font_small), TextAlign::CENTER_HORIZONTAL, "Currently: %s", id(weather_now).state.c_str());
it.printf(400, 85, id(font_mdi_large), TextAlign::CENTER_HORIZONTAL, "%s", weather_icon_map[id(weather_now).state.c_str()].c_str());
/* Outdoor */
it.print(10, 50, id(font_large), "Outdoors & Barn");
it.rectangle(10,80,250,80);
it.print(15, 105, id(font_small), TextAlign::BASELINE_LEFT , "Outdoor Temperature:");
it.print(15, 125, id(font_small), TextAlign::BASELINE_LEFT , "Outdoor Humidity:");
it.print(15, 145, id(font_small), TextAlign::BASELINE_LEFT , "Solar Energy:");
it.printf(240, 105, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_outdoor);
it.printf(240, 125, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% %", humid_outdoor);
it.printf(240, 145, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% w/m2", energy_solar);
/* Greenhouse and Barn */
it.print(10, 35 + offsetY, id(font_large), "Greenhouse/Barn");
it.rectangle(10, 65 + offsetY,250,255);
it.print(15, 68 + offsetY, id(font_small), "Greenhouse");
it.printf(240, 95 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", greenhouse_temp);
it.printf(240, 115 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% %", humid_greenhouse);
it.print(15, 120 + offsetY, id(font_small), "Barn");
it.printf(240, 140 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_barn);
it.printf(240, 160 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% %", humid_barn);
it.print(15, 170 + offsetY, id(font_small), "Greenhouse Bed Temps");
it.printf(240, 190 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_bed_1);
it.printf(240, 210 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_bed_2);
it.printf(240, 230 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_bed_3);
it.printf(240, 250 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_bed_4);
it.print(15, 255 + offsetY, id(font_small), "Greenhouse in a Greenhouse");
it.printf(240, 285 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f ºF", temp_shelf);
it.printf(240, 305 + offsetY, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% %", humidity_shelf);
/* Rain Data */
it.print(280, 175, id(font_large), "Rain Data");
it.rectangle(280,205,230,100);
it.print(285, 225, id(font_small), TextAlign::BASELINE_LEFT , "Rain Today");
it.print(285, 245, id(font_small), TextAlign::BASELINE_LEFT , "7 Day Rain");
it.print(285, 265, id(font_small), TextAlign::BASELINE_LEFT , "Monthly Rain");
it.print(285, 285, id(font_small), TextAlign::BASELINE_LEFT , "Yearly Rain");
it.printf(500, 225, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f in", todays_rainfall);
it.printf(500, 245, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f in", day_7_rainfall);
it.printf(500, 265, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f in", monthly_rainfall);
it.printf(500, 285, id(font_small), TextAlign::BASELINE_RIGHT , "%2.1f in", yearly_rainfall);
/* Lavender Bed */
it.print(595, 50, id(font_large), "Lavender Bed");
it.rectangle(595,80,180,225);
it.print(600, 85, id(font_small), "Percent:");
it.printf(765, 115, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% %", soil_4in_percent);
it.printf(765, 135, id(font_small), TextAlign::BASELINE_RIGHT , "%.1f% %", soil_percent_8in);
it.printf(765, 155, id(font_small), TextAlign::BASELINE_RIGHT, "%.1f% %", (255-soil_12in_pct)/255 * 100 );
it.printf(765, 175, id(font_small), TextAlign::BASELINE_RIGHT, "%.1f% %", (255-soil_16in_pct)/255 * 100 );
it.print(603, 115, id(font_small), TextAlign::BASELINE_LEFT , "4 inches");
it.print(603, 135, id(font_small), TextAlign::BASELINE_LEFT , "8 inches");
it.print(603, 155, id(font_small), TextAlign::BASELINE_LEFT , "12 inches");
it.print(603, 175, id(font_small), TextAlign::BASELINE_LEFT , "16 inches");
it.print(600, 185, id(font_small), "Centibars:");
it.printf(740, 215, id(font_small), TextAlign::BASELINE_RIGHT , "%d%", soil_4in_cnb);
it.printf(740, 235, id(font_small), TextAlign::BASELINE_RIGHT , "%d%", soil_8in_cnb);
it.printf(740, 255, id(font_small), TextAlign::BASELINE_RIGHT , "%d%", soil_12in_cnb);
it.printf(740, 275, id(font_small), TextAlign::BASELINE_RIGHT , "%d%", soil_16in_cnb);
it.print(603, 215, id(font_small), TextAlign::BASELINE_LEFT , "4 inches");
it.print(603, 235, id(font_small), TextAlign::BASELINE_LEFT , "8 inches");
it.print(603, 255, id(font_small), TextAlign::BASELINE_LEFT , "12 inches");
it.print(603, 275, id(font_small), TextAlign::BASELINE_LEFT , "16 inches");
it.print(765, 215, id(font_small), TextAlign::BASELINE_RIGHT , unit);
it.print(765, 235, id(font_small), TextAlign::BASELINE_RIGHT , unit);
it.print(765, 255, id(font_small), TextAlign::BASELINE_RIGHT , unit);
it.print(765, 275, id(font_small), TextAlign::BASELINE_RIGHT , unit);
/* Temperature Graph */
it.print(280, 310, id(font_large), "Temperature Graph");
it.graph(280, 335, id(temperature_graph));
/* FOOTER */
it.strftime(380, 460, id(footer_font), TextAlign::CENTER_HORIZONTAL , "Updated at %d/%b/%Y %H:%M", id(homeassistant_time).now());
/* WiFi Signal Strenght */
if(id(wifisignal).has_state()) {
int x = 478;
int y = 472;
if (id(wifisignal).state >= -50) {
//Excellent
it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "");
ESP_LOGI("WiFi", "Exellent");
} else if (id(wifisignal).state >= -60) {
//Good
it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "");
ESP_LOGI("WiFi", "Good");
} else if (id(wifisignal).state >= -75) {
//Fair
it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "");
ESP_LOGI("WiFi", "Fair");
} else if (id(wifisignal).state >= -100) {
//Weak
it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "");
ESP_LOGI("WiFi", "Weak");
} else {
//Unlikely working signal
it.print(x, y, id(mdi_wifi), TextAlign::BASELINE_CENTER, "");
ESP_LOGI("WiFi", "Unlikely");
}
}