E-paper display

This is my weather station.

@psp888
thanks for your inspiration

WeAct E-Ink 2.9" displays were used. Unfortunately, they are not yet supported in ESPHome. But they can be downloaded here as a beta.

In addition, a Zigbee repeater was installed to extend the distance of my sensors

the 3D data can be loaded onto thingiverse.

font:
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_85_font
    size: 85  
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_75_font
    size: 75
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_60_font
    size: 60
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_50_font
    size: 50
  - file: 'fonts/Roboto-Light.ttf'
    id: size_12_font
    size: 12
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_15_font
    size: 15
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_14_font
    size: 14    
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_20_font
    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','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/']    
    size: 20
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_25_font
    size: 25
  - file: 'fonts/Roboto-Medium.ttf'
    id: size_30_font
    size: 30
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: weather_font
    size: 120
    glyphs: [
      # Weather
      "\U000F0599", # mdi-weather-sunny
      "\U000F0590", # mdi-weather-cloudy
      "\U000F0596", # mdi-weather-pouring
      "\U000F067F", # mdi-weather-snowy-rainy
      "\U000F0F36", # mdi-weather-snowy-heavy
      "\U000F059E", # mdi-weather-windy-variant
      "\U000F0591", # mdi-weather-fog
      "\U000F0F31", # mdi-weather-night-partly-cloudy
      "\U000F0595", # mdi-weather-partly-cloudy
      "\U000F0597", # mdi-weather-rainy
      "\U000F0598", # mdi-weather-snowy
      "\U000F0594", # mdi-weather-clear-night
      "\U000F199F", # unknown
      ]
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: weather_font_smal
    size: 35
    glyphs: [
      # Weather
      "\U000F0599", # mdi-weather-sunny
      "\U000F0590", # mdi-weather-cloudy
      "\U000F0596", # mdi-weather-pouring
      "\U000F067F", # mdi-weather-snowy-rainy
      "\U000F0F36", # mdi-weather-snowy-heavy
      "\U000F059E", # mdi-weather-windy-variant
      "\U000F0591", # mdi-weather-fog
      "\U000F0F31", # mdi-weather-night-partly-cloudy
      "\U000F0595", # mdi-weather-partly-cloudy
      "\U000F0597", # mdi-weather-rainy
      "\U000F0598", # mdi-weather-snowy
      "\U000F0594", # mdi-weather-clear-night
      "\U000F199F", # unknown
      ]      
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: weather_temp_icon_font
    size: 25
    glyphs: [
      "\U000F0E03", # mdi-down
      "\U000F0E02", # mdi-up
      "\U000F058C", # raindrop
      "\U000F059D", # wind
      ]
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: home_icon_font
    size: 30
    glyphs: [
      "\U000F0F48", # mdi-chair-rolling
      "\U000F02E3", # mdi-bed
      "\U000F04B9", # mdi-sofa
      "\U000F065A", # mdi-pot-steam
      "\U000F09A0", # mdi-shower
      "\U000F09A1", # mdi-shower-head
      ]
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: weather_font_45
    size: 45
    glyphs: [
      # Moon
      "\U000F0F64", # new_moon
      "\U000F0F67", # waxing_crescent
      "\U000F0F61", # first_quarter 
      "\U000F0F68", # waxing_gibbous
      "\U000F0F62", # full_moon
      "\U000F0F66", # waning_gibbous
      "\U000F0F63", # last_quarter
      "\U000F0F65", # waning_crescent
      "\U000F199F", # mdi-timer-sand-complete
      ]
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: sun_icon_font
    size: 20
    glyphs: [
      "\U000F059C", # sun rise
      "\U000F059B", # sun set
      ]      
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: wlan_icon_font
    size: 25
    glyphs: [
      "\U000F0920", # wifi-strength-1-alert
      "\U000F0922", # wifi-strenght-2
      "\U000F0925", # wifi-strenght-3
      "\U000F0928", # wifi-strenght-4    
      "\U000F092E", # wifi-strength-off-outline        
      ]    
    
spi:
  - id: bus_a
    clk_pin: GPIO18  #SCL   grün
    mosi_pin: GPIO23 #SDA  gelb 
    
  - id: bus_b   
    clk_pin: GPIO17  #SCL   grün
    mosi_pin: GPIO15 #SDA  gelb   



display:
#Weater  
  - platform: waveshare_epaper
    id: display_wetter
    model: 2.90inBS
    spi_id:  bus_b    
    cs_pin: GPIO32      #CS    blau
    busy_pin: GPIO27    #BUSY  schwarz
    reset_pin: GPIO12   #RESET rot
    dc_pin: GPIO16      #DC    weiss       
    rotation: 90
    full_update_every: 12
    update_interval: 300s       
    lambda: |-
      int x, y;
      if (id(forecast_condition).has_state()) {
        x = 56, y = 100; 
        if (id(forecast_condition).state == "snowy-rainy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(forecast_condition).state == "snowy-heavy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(forecast_condition).state == "rainy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0597");
        } else if (id(forecast_condition).state == "pouring") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0596");
        } else if (id(forecast_condition).state == "cloudy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0590");
        } else if (id(forecast_condition).state == "partlycloudy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(forecast_condition).state == "sunny") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0599");
        } else if (id(forecast_condition).state == "windyvariant") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F059E");
        } else if (id(forecast_condition).state == "fog") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0591");
        } else if (id(forecast_condition).state == "nightpartlycloudy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0F31");
        } else if (id(forecast_condition).state == "partlycloudy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(forecast_condition).state == "snowy") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0598");
        } else if (id(forecast_condition).state == "clear-night") {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F0594");
        } else {
          it.printf(x, y, id(weather_font), TextAlign::BASELINE_CENTER , "\U000F199F");
        }
      }
      

      if (id(forecast_condition).has_state()) {
        x = 56, y = 125;      
        if (id(forecast_condition).state == "snowy-rainy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Schneeregen");
        } else if (id(forecast_condition).state == "snowy-heavy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "viel Schnee");
        } else if (id(forecast_condition).state == "rainy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Regen");
        } else if (id(forecast_condition).state == "pouring") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Strömend");
        } else if (id(forecast_condition).state == "cloudy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Bewölkt");
        } else if (id(forecast_condition).state == "partlycloudy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Durchzogen");
        } else if (id(forecast_condition).state == "sunny") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Sonnig");
        } else if (id(forecast_condition).state == "windyvariant") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Windig");
        } else if (id(forecast_condition).state == "fog") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Nebel");
        } else if (id(forecast_condition).state == "nightpartlycloudy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Durchzogen");
        } else if (id(forecast_condition).state == "partlycloudy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Durchzogen");
        } else if (id(forecast_condition).state == "snowy") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "Schnee");
        } else if (id(forecast_condition).state == "clear-night") {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "klare Nacht");
        } else {
          it.print(x, y, id(size_20_font), TextAlign::BASELINE_CENTER , "keine Ahnung");
        }
      }

      //Timne
      //it.strftime(0, 90, id(size_12_font), "%H:%M", id(sntp_time).now());


      it.printf(128, 26, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "\U000F0E03");
      if (id(MaxTemp12h).has_state()) {
        it.printf(202, 24, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(MaxTemp12h).state);
        it.printf(203, 18, id(size_20_font), TextAlign::BASELINE_LEFT , "°");
        it.printf(204, 24, id(size_20_font), TextAlign::BASELINE_LEFT , "C");
      }
      
      it.printf(128, 57, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "\U000F0E02");
      if (id(MinTemp12h).has_state()) {
        it.printf(202, 55, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(MinTemp12h).state);
        it.printf(203, 49, id(size_20_font), TextAlign::BASELINE_LEFT , "°");
        it.printf(204, 55, id(size_20_font), TextAlign::BASELINE_LEFT , "C");
      }
      
      std::string str = id(forecast_precipitation).state;
      //ESP_LOGI("Weather", "%s", str.c_str());

      it.printf(123, 88, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "\U000F058C");
      if (id(forecast_precipitation).has_state()) {
        if (str != "unknown") {
          it.printf(202, 86, id(size_30_font), TextAlign::BASELINE_RIGHT , "%s", id(forecast_precipitation).state.c_str());
          it.printf(203, 86, id(size_12_font), TextAlign::BASELINE_LEFT , "mm");
        }
        else {
          it.printf(202, 86, id(size_30_font), TextAlign::BASELINE_RIGHT , "0.0");
          it.printf(203, 86, id(size_12_font), TextAlign::BASELINE_LEFT , "mm");
        }
      }

      
      it.printf(123, 119, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "\U000F059D");
      if (id(forecast_wind_speed).has_state()) {
        it.printf(202, 121, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(forecast_wind_speed).state * 2.237);
        it.printf(203, 121, id(size_12_font), TextAlign::BASELINE_LEFT , "km/h");
      }
      
      //line
      it.line(242, 0, 242, 128);

      if (id(wettervorhesage3h).has_state()) {
        x = 270, y = 30; 
        if (id(wettervorhesage3h).state == "snowy-rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage3h).state == "snowy-heavy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage3h).state == "rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0597");
        } else if (id(wettervorhesage3h).state == "pouring") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0596");
        } else if (id(wettervorhesage3h).state == "cloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0590");
        } else if (id(wettervorhesage3h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage3h).state == "sunny") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0599");
        } else if (id(wettervorhesage3h).state == "windyvariant") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F059E");
        } else if (id(wettervorhesage3h).state == "fog") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0591");
        } else if (id(wettervorhesage3h).state == "nightpartlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0F31");
        } else if (id(wettervorhesage3h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage3h).state == "snowy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0598");
        } else if (id(wettervorhesage3h).state == "clear-night") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0594");
        } else {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F199F");
        }
      }
      
      if (id(wettervorhesage6h).has_state()) {
        x = 270, y = 62; 
        if (id(wettervorhesage6h).state == "snowy-rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage6h).state == "snowy-heavy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage6h).state == "rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0597");
        } else if (id(wettervorhesage6h).state == "pouring") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0596");
        } else if (id(wettervorhesage6h).state == "cloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0590");
        } else if (id(wettervorhesage6h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage6h).state == "sunny") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0599");
        } else if (id(wettervorhesage6h).state == "windyvariant") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F059E");
        } else if (id(wettervorhesage6h).state == "fog") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0591");
        } else if (id(wettervorhesage6h).state == "nightpartlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0F31");
        } else if (id(wettervorhesage6h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage6h).state == "snowy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0598");
        } else if (id(wettervorhesage6h).state == "clear-night") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0594");
        } else {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F199F");
        }
      }

      if (id(wettervorhesage9h).has_state()) {
        x = 270, y = 94; 
        if (id(wettervorhesage9h).state == "snowy-rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage9h).state == "snowy-heavy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage9h).state == "rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0597");
        } else if (id(wettervorhesage9h).state == "pouring") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0596");
        } else if (id(wettervorhesage9h).state == "cloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0590");
        } else if (id(wettervorhesage9h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage9h).state == "sunny") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0599");
        } else if (id(wettervorhesage9h).state == "windyvariant") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F059E");
        } else if (id(wettervorhesage9h).state == "fog") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0591");
        } else if (id(wettervorhesage9h).state == "nightpartlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0F31");
        } else if (id(wettervorhesage9h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage9h).state == "snowy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0598");
        } else if (id(wettervorhesage9h).state == "clear-night") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0594");
        } else {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F199F");
        }
      }

      if (id(wettervorhesage12h).has_state()) {
        x = 270, y = 126; 
        if (id(wettervorhesage12h).state == "snowy-rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage12h).state == "snowy-heavy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F067F");
        } else if (id(wettervorhesage12h).state == "rainy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0597");
        } else if (id(wettervorhesage12h).state == "pouring") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0596");
        } else if (id(wettervorhesage12h).state == "cloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0590");
        } else if (id(wettervorhesage12h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage12h).state == "sunny") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0599");
        } else if (id(wettervorhesage12h).state == "windyvariant") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F059E");
        } else if (id(wettervorhesage12h).state == "fog") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0591");
        } else if (id(wettervorhesage12h).state == "nightpartlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0F31");
        } else if (id(wettervorhesage12h).state == "partlycloudy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0595");
        } else if (id(wettervorhesage12h).state == "snowy") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0598");
        } else if (id(wettervorhesage12h).state == "clear-night") {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F0594");
        } else {
          it.printf(x, y, id(weather_font_smal), TextAlign::BASELINE_CENTER , "\U000F199F");
        }
      }





#In_Out
  - platform: waveshare_epaper
    model: 2.90inBS
    spi_id:  bus_a    
    cs_pin: GPIO25      #CS    blau
    busy_pin: GPIO1     #BUSY  schwarz
    reset_pin: GPIO2    #RESET rot
    dc_pin: GPIO4       #DC    weiss  
    rotation: 90
    full_update_every: 12
    update_interval: 300s
    lambda: |-
      it.print(0, 20, id(size_20_font), TextAlign::BASELINE_LEFT , "OUT");
      it.printf(190, 60, id(size_75_font), TextAlign::BASELINE_RIGHT , "%.1f", id(outside_temp).state);
      it.printf(190, 45, id(size_30_font), TextAlign::BASELINE_LEFT , "°");
      it.printf(191, 60, id(size_30_font), TextAlign::BASELINE_LEFT , "C");
      it.printf(280, 60, id(size_50_font), TextAlign::BASELINE_RIGHT , "%.0f", id(outside_humidity).state);
      it.printf(296, 60, id(size_20_font), TextAlign::BASELINE_RIGHT , "%%");
      
      //line
      it.line(0, 70, 296, 70);
      
      //it.print(0, 95, id(size_20_font), TextAlign::BASELINE_LEFT , "IN");
      //it.printf(190, 125, id(size_60_font), TextAlign::BASELINE_RIGHT , "%.1f", id(inside_temp).state);
      //it.printf(190, 110, id(size_30_font), TextAlign::BASELINE_LEFT , "°");
      //it.printf(191, 125, id(size_30_font), TextAlign::BASELINE_LEFT , "C");
      //it.printf(280, 125, id(size_50_font), TextAlign::BASELINE_RIGHT , "%.0f", id(inside_humidity).state);
      //it.printf(296, 125, id(size_20_font), TextAlign::BASELINE_RIGHT , "%%");
      
      //Time
      //it.strftime(0, 40, id(size_12_font), "%H:%M", id(sntp_time).now());     
      
      //Wohnzimmer
      it.printf(0, 101, id(home_icon_font), TextAlign::BASELINE_LEFT , "\U000F04B9");
      it.printf(95, 100, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(living_room).state);
      
      //Büro
      it.printf(0, 128, id(home_icon_font), TextAlign::BASELINE_LEFT , "\U000F0F48");
      it.printf(95, 127, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(office).state);
      
      //Küche
      it.printf(102, 101, id(home_icon_font), TextAlign::BASELINE_LEFT , "\U000F065A");
      it.printf(197, 100, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(kitchen).state);
      
      //Schlafzimmer
      it.printf(102, 128, id(home_icon_font), TextAlign::BASELINE_LEFT , "\U000F02E3");
      it.printf(197, 127, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(bedroom).state);      
     
      //Bad
      it.printf(204, 101, id(home_icon_font), TextAlign::BASELINE_LEFT , "\U000F09A0");
      it.printf(296, 100, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(bath).state);
      
      //Dusche
      it.printf(204, 128, id(home_icon_font), TextAlign::BASELINE_LEFT , "\U000F09A1");
      it.printf(296, 127, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(shower).state);       
     


#Date_Time
  - platform: waveshare_epaper
    model: 2.90inBS
    spi_id:  bus_a    
    cs_pin: GPIO21      #CS    blau
    busy_pin: GPIO1     #BUSY  schwarz
    reset_pin: GPIO2    #RESET rot
    dc_pin: GPIO4       #DC    weiss  
    rotation: 90
    full_update_every: 60
    update_interval: 60s
    lambda: |-   
      /* Moon icon */
      int x, y;
      if (id(moon_icon).has_state()) {
        x = 25, y = 42;       
        if (id(moon_icon).state == "new_moon") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F64");
        } else if (id(moon_icon).state == "waxing_crescent") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F67");
        } else if (id(moon_icon).state == "first_quarter") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F61");
        } else if (id(moon_icon).state == "waxing_gibbous") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F68");
        } else if (id(moon_icon).state == "full_moon") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F62");
        } else if (id(moon_icon).state == "waning_gibbous") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F66");
        } else if (id(moon_icon).state == "last_quarter") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F63");
        } else if (id(moon_icon).state == "waning_crescent") {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F0F65");
        } else {
          it.printf(x, y, id(weather_font_45), TextAlign::BASELINE_CENTER , "\U000F199F");
        }
      }     

      
      //sun set-rise
      it.printf(85, 22, id(sun_icon_font), TextAlign::BASELINE_RIGHT, "\U000F059C");
      it.printf(135, 22, id(size_20_font), TextAlign::BASELINE_RIGHT, "%s", id(sunset).state.c_str());
      it.printf(85, 44, id(sun_icon_font), TextAlign::BASELINE_RIGHT, "\U000F059B");
      it.printf(135, 44, id(size_20_font), TextAlign::BASELINE_RIGHT, "%s", id(sunrise).state.c_str());
      
      //date
      it.strftime(210, 43, id(size_50_font), TextAlign::BASELINE_RIGHT, "%d", id(sntp_time).now());
      it.printf(213, 43, id(size_14_font), TextAlign::BASELINE_LEFT, "D");
      it.strftime(280, 43, id(size_50_font), TextAlign::BASELINE_RIGHT, "%m", id(sntp_time).now());
      it.printf(283, 43, id(size_14_font), TextAlign::BASELINE_LEFT, "M");
    
      //line
      it.line(0, 54, 296, 54);
      
      //Time
      it.strftime(20, 45, id(size_85_font), "%H:%M", id(sntp_time).now());
      /* it.strftime(225, 68, id(size_60_font), "%S", id(sntp_time).now()); */
      
      it.strftime(250, 58, id(size_20_font), "%a", id(sntp_time).now());

      //wifi
      if (id(wifisignal).has_state()) {
        x = 265, y = 115;         
        if (id(wifisignal).state >= -67) {
          it.printf(x, y, id(wlan_icon_font), TextAlign::BASELINE_CENTER , "\U000F0928"); 
        } else if (id(wifisignal).state >= -70) {
          it.printf(x, y, id(wlan_icon_font), TextAlign::BASELINE_CENTER , "\U000F0925");
        } else if (id(wifisignal).state >= -80) {
          it.printf(x, y, id(wlan_icon_font), TextAlign::BASELINE_CENTER , "\U000F0922");
        } else if (id(wifisignal).state >= -90) {
          it.printf(x, y, id(wlan_icon_font), TextAlign::BASELINE_CENTER , "\U000F0920");                   
        } else {
          it.printf(x, y, id(wlan_icon_font), TextAlign::BASELINE_CENTER , "\U000F092E");            
        }
      }
      
      //Wifi Signal
      it.printf(265, 125, id(size_12_font), TextAlign::BASELINE_CENTER , "%.1f", id(wifisignal).state);


text_sensor:
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_condition
    id: forecast_condition
    internal: true
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_precipitation
    id: forecast_precipitation
    internal: true
  - platform: homeassistant
    entity_id: sensor.moon_phase
    id: moon_icon
  - platform: homeassistant
    id: sunrise
    entity_id: sensor.sonnenaufgang
  - platform: homeassistant
    id: sunset
    entity_id: sensor.sonnenuntergang
  - platform: homeassistant
    entity_id: sensor.wettervorhesage3h
    id: wettervorhesage3h
    internal: true    
  - platform: homeassistant
    entity_id: sensor.wettervorhesage6h
    id: wettervorhesage6h
    internal: true        
  - platform: homeassistant
    entity_id: sensor.wettervorhesage9h
    id: wettervorhesage9h
    internal: true        
  - platform: homeassistant
    entity_id: sensor.wettervorhesage12h
    id: wettervorhesage12h
    internal: true    
  - platform: homeassistant
    entity_id: sensor.wettervorhesage15h
    id: wettervorhesage15h
    internal: true    



time:
  - platform: sntp
    timezone: Europe/Zurich
    id: sntp_time 


sensor:
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_temperature
    id: forecast_temperature
    internal: true
  - platform: homeassistant
    entity_id: sensor.MinTemp12h
    id: MinTemp12h
    internal: true
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_wind_speed
    id: forecast_wind_speed
    internal: true
  - platform: homeassistant
    entity_id: sensor.0xa4c13870d71f2d18_temperature
    id: bedroom
    internal: true
  - platform: homeassistant
    entity_id: sensor.0xa4c138e3fdf5f483_temperature
    id: office
    internal: true
  - platform: homeassistant
    entity_id: sensor.0xa4c1384a262efff1_temperature
    id: living_room
    internal: true
  - platform: homeassistant
    entity_id: sensor.0xa4c1382ae3bae706_temperature
    id: kitchen
    internal: true
  - platform: homeassistant
    entity_id: sensor.0xa4c13839f5bd7ae1_temperature
    id: bath
    internal: true    
  - platform: homeassistant
    entity_id: sensor.0xa4c13803ee056ff7_temperature
    id: shower
    internal: true    
  - platform: homeassistant
    entity_id: sensor.MinTempOut
    id: outside_temp
    internal: true
  - platform: homeassistant
    entity_id: sensor.durchschnitt_temp
    id: inside_temp
    internal: true
  - platform: homeassistant
    entity_id: sensor.HumidityOut
    id: outside_humidity
    internal: true
  - platform: homeassistant
    entity_id: sensor.0xa4c1382ae3bae706_humidity
    id: inside_humidity
    internal: true
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: "wifisignal"
    update_interval: 60s   
  - platform: homeassistant
    entity_id: sensor.MaxTemp12h
    id: MaxTemp12h
    internal: true    
4 Likes

Project repo:

Hi, I just finished my first battery-powered ESP8266 project for displaying weather forecasts and sensor data retrieved from HA on a Waveshare 7.5-inch e-paper display. The ESP refreshes every 10 minutes and goes to deep sleep again. The code is using partial display refresh and performs a full refresh every two hours (a counter is saved in the RTC memory). Estimated battery lifetime is 1-2 months, let’s see how it works out :grinning_face_with_smiling_eyes:

6 Likes

What do the dog icons on your display symbolize? Intrigued…

Here is my current project. It is a display destined for the kitchen to show the meal plan for today and tomorrow.

This should stop the users and their “What’s for dinner?”

This is so good. Are you using Grocy? What is this display?

I’m not using Grocy or Mealie for this. I actually do use Mealie for recipes but I wanted this screen to be easy to update for my users. All I am using is a bunch of Home Assistant Helper Input Texts. The display refreshes when someone changes a meal or the next day.

My users have access to Home Assistant and can very easily update the meal plan by typing in the meals.

I made a few changes to the layout since my last screenshot. Here is what I currently have in production. The red bar is showing the “next” meal. It changes from lunch to dinner at 1pm.

The screen is this one with the 4.2" screen, https://www.tindie.com/products/electronics-by-nic/openepaperlink-mini-ap-v3-zigbee-wifi-gateway/ which is discussed on this thread Anyone looked into using Electronic Price Tag screens with HA? - #12 by lonebaggie

1 Like

amazing… Wanna share the code ??

I use two free custom fonts, links below. You drop the .ttf into the custom_components / open_epaper_link directory. The Lato font shows the battery level.

Marker Felt Font.ttf
Lato-Hairline.ttf

https://dwl.freefontsfamily.com/download/Marker-Felt-Font/

When the battery is getting low the whole display is red. The battery threshold is a Home Assistant Input Number. I have it set to 10% and move it to 100% for testing. In my case, input_number.epaper_low_battery_threshold.

Here is the automation code. Enjoy!

alias: EPaper Tag 02b3349c341e
description: ""
trigger:
  - platform: homeassistant
    event: start
  - platform: state
    entity_id:
      - input_number.epaper_low_battery_threshold
    to: null
  - platform: state
    entity_id:
      - sensor.000002b3349c341e_battery
    to: null
  - platform: state
    entity_id:
      - input_text.meal_plan_01_monday_lunch
      - input_text.meal_plan_01_monday_dinner
      - input_text.meal_plan_02_tuesday_lunch
      - input_text.meal_plan_02_tuesday_dinner
      - input_text.meal_plan_03_wednesday_lunch
      - input_text.meal_plan_03_wednesday_dinner
      - input_text.meal_plan_04_thursday_lunch
      - input_text.meal_plan_04_thursday_dinner
      - input_text.meal_plan_05_friday_lunch
      - input_text.meal_plan_05_friday_dinner
      - input_text.meal_plan_06_saturday_lunch
      - input_text.meal_plan_06_saturday_lunch
      - input_text.meal_plan_06_saturday_dinner
      - input_text.meal_plan_07_sunday_lunch
      - input_text.meal_plan_07_sunday_dinner
  - platform: time
    at: "13:00:00"
  - platform: state
    entity_id:
      - sensor.day_of_the_week
condition: []
action:
  - variables:
      battery_sensor: sensor.000002b3349c341e_battery
      battery_low_threshold: "{{ states('input_number.epaper_low_battery_threshold') | int }}"
      battery_low: >-
        {% if states(battery_sensor) | int <= battery_low_threshold %}true{%
        else %}false{% endif %}
      background_color: "{% if battery_low == 'true' %}red{% else %}white{% endif %}"
      text_color: "{% if battery_low == 'true' %}white{% else %}black{% endif %}"
      next_meal: "{% if now().hour <= 12 %}lunch{% else %}dinner{% endif %}"
      lunch_highlight_color: "{% if next_meal == 'lunch' %}red{% else %}black{% endif %}"
      dinner_highlight_color: "{% if next_meal == 'dinner' %}red{% else %}black{% endif %}"
      current_day: "{{ states('sensor.day_of_the_week') | string }}"
      today_lunch: |
        {% if current_day == "Monday" %}
          {{ states('input_text.meal_plan_01_monday_lunch') | string }}
        {% elif current_day == "Tuesday" %}
          {{ states('input_text.meal_plan_02_tuesday_lunch') | string }}
        {% elif current_day == "Wednesday" %}
          {{ states('input_text.meal_plan_03_wednesday_lunch') | string }}
        {% elif current_day == "Thursday" %}
          {{ states('input_text.meal_plan_04_thursday_lunch') | string }}
        {% elif current_day == "Friday" %}
          {{ states('input_text.meal_plan_05_friday_lunch') | string }}
        {% elif current_day == "Saturday" %}
          {{ states('input_text.meal_plan_06_saturday_lunch') | string }}
        {% elif current_day == "Sunday" %}
          {{ states('input_text.meal_plan_07_sunday_lunch') | string }}
        {% endif %}
      today_dinner: |
        {% if current_day == "Monday" %}
          {{ states('input_text.meal_plan_01_monday_dinner') | string }}
        {% elif current_day == "Tuesday" %}
          {{ states('input_text.meal_plan_02_tuesday_dinner') | string }}
        {% elif current_day == "Wednesday" %}
          {{ states('input_text.meal_plan_03_wednesday_dinner') | string }}
        {% elif current_day == "Thursday" %}
          {{ states('input_text.meal_plan_04_thursday_dinner') | string }}
        {% elif current_day == "Friday" %}
          {{ states('input_text.meal_plan_05_friday_dinner') | string }}
        {% elif current_day == "Saturday" %}
          {{ states('input_text.meal_plan_06_saturday_dinner') | string }}
        {% elif current_day == "Sunday" %}
          {{ states('input_text.meal_plan_07_sunday_dinner') | string }}
        {% endif %}
      tomorrow_lunch: |
        {% if current_day == "Monday" %}
          {{ states('input_text.meal_plan_02_tuesday_lunch') | string }}
        {% elif current_day == "Tuesday" %}
          {{ states('input_text.meal_plan_03_wednesday_lunch') | string }}
        {% elif current_day == "Wednesday" %}
          {{ states('input_text.meal_plan_04_thursday_lunch') | string }}
        {% elif current_day == "Thursday" %}
          {{ states('input_text.meal_plan_05_friday_lunch') | string }}
        {% elif current_day == "Friday" %}
          {{ states('input_text.meal_plan_06_saturday_lunch') | string }}
        {% elif current_day == "Saturday" %}
          {{ states('input_text.meal_plan_07_sunday_lunch') | string }}
        {% elif current_day == "Sunday" %}
          {{ states('input_text.meal_plan_01_monday_lunch') | string }}
        {% endif %}
      tomorrow_dinner: |
        {% if current_day == "Monday" %}
          {{ states('input_text.meal_plan_02_tuesday_dinner') | string }}
        {% elif current_day == "Tuesday" %}
          {{ states('input_text.meal_plan_03_wednesday_dinner') | string }}
        {% elif current_day == "Wednesday" %}
          {{ states('input_text.meal_plan_04_thursday_dinner') | string }}
        {% elif current_day == "Thursday" %}
          {{ states('input_text.meal_plan_05_friday_dinner') | string }}
        {% elif current_day == "Friday" %}
          {{ states('input_text.meal_plan_06_saturday_dinner') | string }}
        {% elif current_day == "Saturday" %}
          {{ states('input_text.meal_plan_07_sunday_dinner') | string }}
        {% elif current_day == "Sunday" %}
          {{ states('input_text.meal_plan_01_monday_dinner') | string }}
        {% endif %}
  - service: open_epaper_link.drawcustom
    data:
      background: "{{ background_color }}"
      rotate: 0
      payload:
        - type: rectangle
          x_start: 0
          x_end: 25
          y_start: 0
          y_end: 72
          width: 1
          fill: "{{ lunch_highlight_color }}"
          outline: "{{ lunch_highlight_color }}"
        - type: text
          value: "{{ today_lunch }}"
          anchor: lm
          font: Marker Felt Font.ttf
          x: 40
          "y": 36
          size: 30
          color: "{{ text_color }}"
        - type: rectangle
          x_start: 0
          x_end: 25
          y_start: 76
          y_end: 148
          width: 1
          fill: "{{ dinner_highlight_color }}"
          outline: "{{ dinner_highlight_color }}"
        - type: text
          value: "{{ today_dinner }}"
          anchor: lm
          font: Marker Felt Font.ttf
          x: 40
          "y": 112
          size: 30
          color: "{{ text_color }}"
        - type: line
          x_start: 40
          x_end: 380
          y_start: 150
          y_end: 150
          width: 1
          fill: black
        - type: rectangle
          x_start: 0
          x_end: 25
          y_start: 152
          y_end: 224
          width: 2
          fill: white
          outline: black
        - type: text
          value: "{{ tomorrow_lunch }}"
          anchor: lm
          font: Marker Felt Font.ttf
          x: 40
          "y": 188
          size: 30
          color: "{{ text_color }}"
        - type: rectangle
          x_start: 0
          x_end: 25
          y_start: 228
          y_end: 300
          width: 2
          fill: white
          outline: black
        - type: text
          value: "{{ tomorrow_dinner }}"
          anchor: lm
          font: Marker Felt Font.ttf
          x: 40
          "y": 264
          size: 30
          color: "{{ text_color }}"
        - type: icon
          value: numeric-positive-1
          x: 355
          "y": 145
          size: 50
          color: black
        - type: text
          value: "{{ states(battery_sensor) | int | string }}%"
          anchor: lm
          font: Lato-Hairline.ttf
          x: 360
          "y": 285
          size: 15
          color: "{{ text_color }}"
    target:
      entity_id:
        - open_epaper_link.000002b3349c341e
mode: restart

I bought two of the 4.2" displays. I’ve got this on the second one. It sits in the kitchen and shows the date and the Anniversaries / Holidays coming up. The Anniversaries come from that HACS integration.

The upcoming Anniversaries come from a sensor. Let me know if anyone wants that code or the epaper code. The sensor is based on code lifted from this discussion

1 Like

They were just placeholders, as I didn’t have the time to enlarge the living room icons yet :sweat_smile:

1 Like

What about using these to display and enter items into a shopping list?

Hi! Totally new with ESPHome, I tried this project with a Lilygo TTGO 2.9" epaper display. I got it to work properly with HA integration, but there is one thing that doesn´t work, and that is to get the MDI icons to show on the display.

I downloaded the fontm and tried with code seen in other projects shown in this thread, but no icons show up on the display.

Here is the code I have tried. I tried to refer to the glyphs in 2 different ways as I have seen other do.

……………

font:

  • file: “materialdesignicons-webfont.ttf”
    id: mdi_1
    size: 30
    glyphs: [
    ‘󰽔’, # F0F54 mdi-home-thermometer
    ]

  • file: “materialdesignicons-webfont.ttf”
    id: mdi_2
    size: 30
    glyphs:

    • “\U000F050F” # mdi-thermometer

……………

 it.printf(0, 20,  id(mdi_1), "󰽔"); 
 it.printf(35, 20, id(font_temp), "%.1f°c", id(temp_inne).state);
  
 it.printf(0, 50, id(mdi_2), "\U000F050F");
 it.printf(35, 50, id(font_temp), "%.1f°c", id(temp_ute).state);

The path used in the font section of you config differs from what I’m using. Have you tried ‘fonts/materialdesignicons-webfont.ttf’ as the path?

Here’s a segment from a file I’m working on.

font:
  - file: 'fonts/materialdesignicons-webfont.ttf'
    id: font_mdi_large
    size: 96
    glyphs: &mdi-sprinkler-glyphs
      - "\U000F0590" # mdi-weather-cloudy
      - "\U000F0F2F" # mdi-weather-cloudy-alert

Note the addition of ‘fonts’ in the file name.

Thank you for the feedback. the “fonts/” is only the path to where the font is stored, and I have it stored in the root folder as for now, so it doesn´t make any difference.

SOLVED:

Found a way to get it to work. Instead of referring to the glyphs taken from MDI icons page, I opened the materialdesignicons-webfont.ttf locally on my mac and copied the glyphs from there, and that worked.

Wanted to share my M5paper party mode sign

So when I engage party mode, I wanted a sign to welcome my guests and tell them the doors unlocked, and most of my friends know to don’t bother knocking or ringing the doorbell. The sign should be clear and visible when they approach the front door and have enough battery to run the length of the party.

My first attempt was using a M5Stack Core 2, and while very clear and visible, even after adjusting brightness and tweaking ESPHome it would last at most an hour. So I picked up an M5paper with a 4.7" eink display

Using ESPHome and GitHub - Passific/m5paper_esphome: Repository for ESPHOME components for m5paper got a great party mode sign. Shout out to Passific for all the work to get the device working. When I engage party mode, Home Assistant reminds me to put the sign out. I printed a horizonal holder over my doorbell and place the sign in there.

Also considered this magnetic mount but went with the cradle mount instead.

Using a conditional picture elements card in HomeAssistant dashboard I have a mockup of the sign where I can tap and modify the text on the sign.

With some tweaking, the M5Paper on battery is currently lasting about 6 hours, so I’m thrilled with that.

When I end party mode (or if the battery drops below 10% for 5 minutes), I get a reminder to remove the party sign. Other amazing thing is full charge takes a few minutes.

1 Like

6 hours? Are you sending new images with 100hz?

1 Like

Still in the early stages and have been tweaking different things to try and maximize battery life. Honestly, this is my first epaper device that I’ve played with so have no relative idea how long it SHOULD last, but am thrilled that it’s lasting longer than the 1 hour that the LED display based M5Stack Core 2 I was originally using was.

The very idea of an e-ink display is to show what it is showing “forever”, if you don’t update it. It shouldn’t have any noticeable battery drainage within a day.

First epaper device and that’s sort of what I was anticipating that I’d get really long ‘forever’ battery life. Kinda new to esphome as well, and so I have been tweaking settings on the esphome such as when the display updates (say for example if I change the text, or when my house mode changes, etc)

Used yaml from Passific/m5paper_esphome: Repository for ESPHOME components for m5paper (github.com) and am just super grateful that they actually got it working, so didn’t wanna complain too much about a 6 hour battery life. But am continuing to tweak.