That looks amazing! Do you mind to share the code? I am interested to learn how you have done with the images.
Here you go, let me know if you want the images as well.
esphome:
name: "ink-display-01"
friendly_name: Ink Display 1
on_boot:
priority: 200.0
then:
- component.update: eink_display
- delay: 10s
- 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:
api:
encryption:
key: "REMOVED"
ota:
# 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:
- component.update: eink_display
# Check whether the display needs to be refreshed every minute,
# based on whether new data is received or motion is detected. (Thanks @paviro!)
time:
- platform: homeassistant
id: homeassistant_time
on_time:
- seconds: 0
minutes: /1
then:
- if:
condition:
binary_sensor.is_on: motion_detected
then:
- script.execute: update_screen
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Esphome-Web-E1E44C"
password: "SomeRandomPasswordThatShouldBeLong&Secure"
reboot_timeout: 300s
#Include sun
sun:
latitude: INSERT YOUR OWN
longitude: INSERT YOUR OWN
# 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', 'C',]
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_time
size: 90
glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':']
- file: 'fonts/GothamRnd-Book.ttf'
id: font_items
size: 35
- file: 'fonts/GothamRnd-Book.ttf'
id: font_weekday
size: 45
- file: 'fonts/GothamRnd-Book.ttf'
id: font_day
size: 74
glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_month
size: 55
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_medium_bold
size: 40
#glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'M', 'I', 'N']
- file: 'fonts/GothamRnd-Bold.ttf'
id: font_small_bold
size: 25
#glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'M', 'I', 'N']
- file: 'fonts/GothamRnd-Bold.ttf'
id: header_small_bold
size: 18
# glyphs: ['°', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'M', 'I', 'N']
- file: 'fonts/GothamRnd-Bold.ttf'
id: inside_weather_small
size: 17
- file: 'fonts/GothamRnd-Bold.ttf'
id: outside_weather_large
size: 20
- file: 'fonts/GothamRnd-Bold.ttf'
id: aircon_small
size: 14
# glyphs: ['°', 'O', 'F', 'H', 'E', 'A', 'T', 'C', 'L', '8', '9', 'C', 'M', 'I', 'N']
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_large
size: 96
glyphs: &mdi-glyphs
#- "\U+00B5" #micro sign
#- "\U+00B3" #cubed
- "\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
- "\U000F05A9" # mdi-wifi
- "\U000F058E" # mdi-water-percent
- "\U000F0F61" # mdi-moon-first-quarter
- "\U000F0F62" # mdi-moon-full
- "\U000F0F63" # mdi-moon-last-quarter
- "\U000F0F64" # mdi-moon-new
- "\U000F0F65" # mdi-moon-waning-crescent
- "\U000F0F66" # mdi-moon-waning-gibbous
- "\U000F0F67" # mdi-moon-waxing-crescent
- "\U000F0F68" # mdi-moon-waxing-gibbous
- "\U000F001B" # mdi-air-conditioner
- "\U000F1A5F" # mdi-pool-thermometer
- file: 'fonts/GothamRnd-Bold.ttf'
id: inside_weather_smaller
size: 11
glyphs: ['p', 'm', '2', 'µ', '/', '3']
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_moon_phase
size: 50
glyphs: *mdi-glyphs
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_sun
size: 70
glyphs: *mdi-glyphs
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_medium
size: 36
glyphs: *mdi-glyphs
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_aircon
size: 25
glyphs: *mdi-glyphs
- file: 'fonts/materialdesignicons-webfont.ttf'
id: font_mdi_pool
size: 80
glyphs: *mdi-glyphs
- file: 'fonts/materialdesignicons-webfont.ttf'
id: mdi_custom_medium
size: 30
glyphs: *mdi-glyphs
# Include Images
image:
- file: "images/mountains.png"
id: image_mountains
type: BINARY
- file: "images/home_icon.png"
id: image_home
type: BINARY
- file: "images/pool.png"
id: image_pool
type: BINARY
- file: "images/filter.png"
id: image_filter
type: BINARY
- file: "images/jets.png"
id: image_jets
type: BINARY
# Check if motion is detected in the Kitchen via Home Assistant.
binary_sensor:
- platform: homeassistant
entity_id: binary_sensor.kitchen_sensor_motion
id: motion_detected
# Storage Sensors
sensor:
- platform: template
name: "Display Last Update"
device_class: timestamp
entity_category: "diagnostic"
id: display_last_update
- platform: template
name: "Recorded Display Refresh"
accuracy_decimals: 0
unit_of_measurement: "Refreshes"
state_class: "total_increasing"
entity_category: "diagnostic"
lambda: 'return id(recorded_display_refresh);'
# Home Assistant Sensors
# PM2 Sensor
- platform: homeassistant
entity_id: sensor.living_room_air_quality
id: living_room_pm2
# Roof Temperature
- platform: homeassistant
entity_id: sensor.roof_temp
id: roof_temperature
# Pool Temperature
- platform: homeassistant
entity_id: sensor.pool_water_temp
id: pool_temp
# Temperature - Home Outdoor Temperature
- platform: homeassistant
entity_id: sensor.balcony_temperature
# attribute: temperature
id: weather_temperature
# Temperature - Home Inside Temperature
- platform: homeassistant
entity_id: sensor.dining_room_ac_temperature
id: inside_temp
# Temperature - Home Sensors
- platform: homeassistant
entity_id: sensor.dining_room_ac_humidity
id: inside_humidity
# Humidity - Home Sensors
- platform: homeassistant
entity_id: weather.forecast_home
attribute: humidity
id: weather_humidity
# Air pressure - AccuWeather
- platform: homeassistant
entity_id: weather.forecast_home
attribute: pressure
id: weather_pressure
# Strong Wind
- platform: homeassistant
entity_id: sensor.accuweather_wind_gust
id: wind_warning
# Wind Speed
- platform: homeassistant
entity_id: sensor.accuweather_wind
# attribute: wind_speed
id: wind_speed
# UV Index
- platform: homeassistant
entity_id: sensor.accuweather_uv_index
id: uv_index
# WiFi Signal
- platform: wifi_signal
name: "WiFi Signal Sensor"
id: wifisignal
text_sensor:
# Temp Trend
- platform: homeassistant
entity_id: sensor.balcony_temperature
id: temp_trend
- platform: homeassistant
entity_id: switch.pool_filter
id: pool_filter
- platform: homeassistant
entity_id: switch.pool_jets
id: pool_jets
# Weather State
- platform: homeassistant
entity_id: weather.forecast_home
id: condition
# # Weatherman entities
- platform: homeassistant
entity_id: weather.forecast_home
id: weather_condition_now
# Day/Night Sensor
- platform: homeassistant
entity_id: input_boolean.day_night
id: day_night
- platform: homeassistant
entity_id: climate.aircon_1
id: aircon_1
- platform: homeassistant
entity_id: climate.aircon_2
id: aircon_2
- platform: homeassistant
entity_id: climate.aircon_3
id: aircon_3
- platform: homeassistant
entity_id: climate.aircon_4
id: aircon_4
- platform: homeassistant
entity_id: climate.aircon_5
id: aircon_5
# Sunrise
- platform: sun
type: sunrise
id: sun_sunrise
format: "%H:%M"
# Sunset
- platform: sun
type: sunset
id: sun_sunset
format: "%H:%M"
# Moon phase
- platform: homeassistant
entity_id: sensor.moon_phase
id: moon_phase
# Define colors
# This design is white on black so this is necessary.
color:
- id: color_black
red: 0%
green: 0%
blue: 0%
white: 50%
- id: color_white
red: 0%
green: 0%
blue: 0%
white: 0%
# 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
#id: epaper
cs_pin: 15
busy_pin: 25
reset_pin: 26
dc_pin: 27
model: 7.50inV2alt
update_interval: never
rotation: 90°
auto_clear_enabled: false
reset_duration: 2ms
lambda: |-
// Map weather states to MDI characters.
std::map<std::string, std::string> visibility_short
{
{"20-40", "30"},
{"20-30", "25"},
{"10-20", "15"},
};
std::map<std::string, std::string> moon_icon_map
{
{"first_quarter", "\U000F0F61"},
{"full_moon", "\U000F0F62"},
{"last_quarter", "\U000F0F63"},
{"new_moon", "\U000F0F64"},
{"waning_crescent", "\U000F0F65"},
{"waning_gibbous", "\U000F0F66"},
{"waning_crescent", "\U000F0F67"},
{"waxing_gibbous", "\U000F0F68"},
};
std::map<std::string, std::string> weather_icon_map
{
{"cloudy", "\U000F0590"},
{"cloudy-alert", "\U000F0F2F"},
{"cloudy-arrow-right", "\U000F0E6E"},
{"fog", "\U000F0591"},
{"hail", "\U000F0592"},
{"hazy", "\U000F0F30"},
{"hurricane", "\U000F0898"},
{"lightning", "\U000F0593"},
{"lightning-rainy", "\U000F067E"},
{"night", "\U000F0594"},
{"night-partly-cloudy", "\U000F0F31"},
{"partlycloudy", "\U000F0595"},
{"partly-lightning", "\U000F0F32"},
{"partly-rainy", "\U000F0F33"},
{"partly-snowy", "\U000F0F34"},
{"partly-snowy-rainy", "\U000F0F35"},
{"pouring", "\U000F0596"},
{"rainy", "\U000F0597"},
{"snowy", "\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"},
};
// Fill background in white.
it.fill(color_white);
// --IMAGES--------------------------
it.image(15, 370, id(image_mountains)); //MOUNTAINS IMAGE
it.image(40, 285, id(image_home)); //HOUSE IMAGE
it.image(265, 283, id(image_pool)); //POOL IMAGE
it.image(385, 326, id(image_filter)); //FILTER IMAGE
it.image(390, 285, id(image_jets)); //JETS IMAGE
// ---- POOL TEMPERATURE --------------------------------------------------------
it.printf(330, 338, id(outside_weather_large), color_white, TextAlign::CENTER, "%2.0f°C", id(pool_temp).state);
// --WEATHER INSIDE/OUTSIDE THE HOUSE IMAGE-------
it.printf(135, 330, id(inside_weather_small), color_black, TextAlign::CENTER, "%2.0f°C", id(inside_temp).state);
it.printf(126, 350, id(inside_weather_small), color_black, TextAlign::CENTER, "%2.0f", id(inside_humidity).state);
it.printf(147, 350, id(inside_weather_small), color_black, TextAlign::CENTER, "%s", "%");
it.printf(197, 353, id(inside_weather_small), color_black, TextAlign::CENTER, "%2.0f", id(living_room_pm2).state);
it.printf(198, 338, id(inside_weather_smaller), color_black, TextAlign::CENTER, "%s", "pm2");
it.printf(95, 295, id(inside_weather_small), color_black, TextAlign::CENTER, "%2.0f°C", id(roof_temperature).state);
// --HORIZONTAL & VERTICAL LINES----------------
it.rectangle(20, 240, 700, 1); //TOP
it.rectangle(20, 365, 705, 1); //UNDER HOUSE AND POOL IMAGES
it.rectangle(20, 585, 700, 1); //UNDER WOODFORDE
it.rectangle(20, 695, 710, 1); //UNDER WEATHER
it.rectangle(335, 90, 1, 150); //VERTICAL LINE
// --AC INFORMATION-------
std::string state = id(aircon_1).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(45, 244, id(font_mdi_aircon), color_black, TextAlign::TOP_LEFT, "\U000F001B");
it.printf(70, 250, id(aircon_small), color_black, TextAlign::TOP_LEFT, "1:%s", state.c_str());
state = id(aircon_2).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(127, 244, id(font_mdi_aircon), color_black, TextAlign::TOP_LEFT, "\U000F001B");
it.printf(152, 250, id(aircon_small), color_black, TextAlign::TOP_LEFT, "2:%s", state.c_str());
state = id(aircon_3).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(214, 244, id(font_mdi_aircon), color_black, TextAlign::TOP_LEFT, "\U000F001B");
it.printf(239, 250, id(aircon_small), color_black, TextAlign::TOP_LEFT, "3:%s", state.c_str());
state = id(aircon_4).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(301, 244, id(font_mdi_aircon), color_black, TextAlign::TOP_LEFT, "\U000F001B");
it.printf(326, 250, id(aircon_small), color_black, TextAlign::TOP_LEFT, "4:%s", state.c_str());
state = id(aircon_5).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(388, 244, id(font_mdi_aircon), color_black, TextAlign::TOP_LEFT, "\U000F001B");
it.printf(413, 250, id(aircon_small), color_black, TextAlign::TOP_LEFT, "5:%s", state.c_str());
// ---- POOL FILTER --------------------------------------------------------
state = id(pool_filter).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(445, 340, id(aircon_small), color_black, TextAlign::CENTER, "%s", state.c_str());
// ---- POOL JETS --------------------------------------------------------
state = id(pool_jets).state;
std::transform(state.begin(), state.end(), state.begin(), ::toupper);
it.printf(445, 305, id(aircon_small), color_black, TextAlign::CENTER, "%s", state.c_str());
// ---- PRINT FULL WEEKDAY NAME ----------------------------------------------------------
it.strftime(320, 100, id(font_weekday), TextAlign::TOP_RIGHT, "%A", id(homeassistant_time).now());
// ---- PRINT TIME in HH:MM FORMAT 335---------------------------------------------------
it.strftime(200, 195, id(font_time), TextAlign::CENTER, "%H:%M", id(homeassistant_time).now());
// ---- PRINT DATE -----------------------------------------------------------------------
it.strftime(405, 95, id(font_day), TextAlign::TOP_CENTER, "%d", id(homeassistant_time).now());
// ---- PRINT MONTH ABBREVIATION ----------------------------------------------------------
it.strftime(442, 220, id(font_month), TextAlign::BASELINE_RIGHT, "%b", id(homeassistant_time).now());
// ---PLACE NAME--------------------------------------------------------------------------
// it.print(300, 315, id(font_weekday), color_black, TextAlign::TOP_CENTER, "Mad House");
// ---LOCATION NAME-----------------------------------------------------------------------
it.print(250, 555, id(font_weekday), color_black, TextAlign::CENTER, "Woodforde");
// --WEATHER STATE ICON ------------------------------------------------------------------
it.printf(115, 640, id(font_mdi_large), color_black, TextAlign::CENTER, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());
// ---TEMPERATURE-------------------------------------------------------------------- TEMPERATURE
if(id(weather_temperature).has_state ()) {
it.printf(445, 590, id(font_large_bold), color_black, TextAlign::TOP_RIGHT, "%2.0f°C", id(weather_temperature).state);
}
// ----SUNRISE---------------------------------------------------------------------- SUNRISE
if(id(sun_sunrise).has_state ()) {
it.printf(45, 745, id(font_mdi_medium), color_black, TextAlign::CENTER_LEFT, "\U000F059C");
it.printf(85, 745, id(font_small_bold), color_black, TextAlign::CENTER_LEFT, "%s", id(sun_sunrise).state.c_str());
}
// ----SUNSET----------------------------------------------------------------------- SUNSET
if(id(sun_sunset).has_state ()) {
it.printf(465, 745, id(font_mdi_medium), color_black, TextAlign::CENTER_RIGHT, "\U000F059B");
it.printf(425, 745, id(font_small_bold), color_black, TextAlign::CENTER_RIGHT, "%s", id(sun_sunset).state.c_str());
}
// ----FOOTER HEADERS--------------------------------------------------------------- FOOTER HEADERS
it.printf(100, 718, id(header_small_bold), color_black, TextAlign::CENTER, "SUNRISE");
it.printf(260, 718, id(header_small_bold), color_black, TextAlign::CENTER, "WIND SPEED");
it.printf(410, 718, id(header_small_bold), color_black, TextAlign::CENTER, "SUNSET");
// ----WIND-------------------------------------------------------------------------- WIND
if(id(wind_speed).has_state ()) {
it.printf(215, 745, id(font_mdi_medium), color_black, TextAlign::CENTER, "\U000F059D");
it.printf(245, 745, id(font_small_bold), color_black, TextAlign::CENTER, "%2.0f", id(wind_speed).state);
it.printf(295, 745, id(font_small_bold), color_black, TextAlign::CENTER, "kmh");
}
// ----WIRELESS-------------------------------------------------------------------------- WIRELESS
it.printf(340, 645, id(mdi_custom_medium), color_black, TextAlign::TOP_CENTER, "\U000F05A9");
// ----- MOON PHASE ICON ------------------
if(id(day_night).has_state ()) {
if (id(day_night).state == "on") {
it.printf(305, 410, id(font_mdi_moon_phase), color_black, TextAlign::CENTER, "%s", moon_icon_map[id(moon_phase).state.c_str()].c_str());
}
}
// ---- HUMIDITY
if(id(weather_humidity).has_state ()) {
if (id(weather_humidity).state >= 1) {
it.printf(210, 500, id(font_mdi_medium), color_black, TextAlign::BASELINE_RIGHT, "\U000F058E");
it.printf(250, 500, id(font_items), color_black, TextAlign::BASELINE_RIGHT, "%2.0f", id(weather_humidity).state);
it.printf(255, 500, id(font_small_bold), color_black, TextAlign::BASELINE_LEFT, "%s", "%");
}
}
// ----- UV INDEX
if(id(day_night).has_state ()) {
if (id(day_night).state == "off") {
it.printf(305, 400, id(font_mdi_sun), color_black, TextAlign::CENTER, "\U000F0599");
it.printf(360, 413, id(font_items), color_black, TextAlign::BASELINE_RIGHT, "%2.0f", id(uv_index).state);
it.printf(370, 413, id(font_small_bold), color_black, TextAlign::BASELINE_LEFT, "UVI");
}
}
captive_portal:
Thanks Chris, really appreciate it. I will dive in to the code
I completed my dashboard, and I am pretty happy with the result so far. A lot of information is conditional and only shows when it´s necessary. For example when we need to pack fruit, or homework in the kids’ backpacks.
Uploaded everything here
Where did you buy your ESP32 controler - Ali or ???
How did you achieve this? I have enough battery ( 18650 2200 mAh) for about a week. I use deep sleep and it works 5 minutes per hour.
I use a 3700 mAh LIPO as battery and a low power optimized ESP board (Firebeetle ESP32E).
It updates all its sensors every hour with a deep sleep in between, this takes about 20 seconds for every update. During the night is has a 8-hour deep sleep, as nobody will look at the display.
Can you show me a settings of your deep sleep?
Thank you!
Does anyone knows if it ESPHome supports the 4 colors e-ink displays and if it does and example?
thanks.
Officially - no. Unofficially - I can make it work with 3 colour display
Hi,
So I bought all the equipment and plugged the ESP32 into my Mac and I cannot get the ESP32 to show up so that I can add it as a new device in HA.
I also tried this on Windows and I tried a second USB chord.
Any ideas?
Try to use ESP Home, you must use Chrome as a browser for it to work
I don’t know if the Home Assistant addon also requires Chrome, however, you can read more about it here
For everyone looking for a fix for the grainy picture of the Waveshare 7,5" ePaper:
here it is and it’s perfectly working for my 2 displays which were horribly grainy all the time:
All credits go to @prapador and @Egglestron for implementing this fix.
My pleasure!
Pulling my hair out trying to set this up. When I paste the contents of sensors.yaml into configuration.yaml, I receive the following error:
Invalid config for [sensor]: required key not provided @ data['platform']. Got None. (See /config/configuration.yaml, line 285).
Here is the code with the lines:
You are missing a template:
Try this
template:
- trigger:
platform: time_pattern
minutes: "/1"
sensor:
- name: Weatherman Data
state: "OK"
attributes:
train_status: >
Se line 41 in the code
So when I add template, I get the following error:
duplicated mapping key (311:1)
308 | - "service_changes"
309 |
310 |
311 | template:
-------^
312 |