Use ESPHome with e-ink Displays to blend in with your home decor!

I was so inspired by your e ink display on the release party @madelena so I went straight to Amazon and order what I need to do this my self. Thanks for sharing your project!

I have got everything up and running but I have an issue the brightness of the display is so poor that I almost can’t read anything. I have tried everything I can think of but can’t find a solution. Anyone has stumbled across this issue and know how to fix it?

If you look closely you can se what´s on the screen :slight_smile:

How do you control the e-ink display? Check the switches on the board as in the post above.

3 Likes

You are a star! I am using an e-Paper ESP32 Driver board and I changed the PIN 1 to on and now it´s working properly! Thanks!

Maybe a stupid question but is the only way to update the ESP32 with the new configuration to install in ESP Home on HA? Or is there an easier and quicker way I haven’t found?

You can use different ways to work with ESP devices, ESPHome as an Add-on in HA is the most comfortable one. But you can install ESPHome on its own, see here:

https://esphome.io/guides/installing_esphome.html

There are other projects to write software for ESP devices, it should even work if you want to use your Arduino IDE, but there I’m not sure.

I wouldn’t bother and use ESPHome, installed whatever way seems comfortable for you. The thing is, you need some kind of method to save the configuration of your devices, and ESPHome is a convenient way to do so.

This is what the ESPHome website says:

If you want to create and edit ESPHome projects, install ESPHome on your computer or inside Home Assistant (it’s free!).

1 Like

Just finished mine, based on @makai work published here Air Quality Sensors + E-Ink Display using ESPHome.

WhatsApp Image 2023-07-15 at 15.04.28

I had to rotate the screen because that’s the space I had on the wall. Also changed a few data fields
and positions because of the sensors I am using and from a designed prospective.
The frame was DIYed from red oak, powered AC power with a small USB adapter.

code and more info can be found here: GitHub - idan-shine/4.2-e-ink-display: conf and fonts for a e-ink displayed based on esphome for displaying temp and other info

2 Likes

Really nice! Also put mine in a frame

1 Like

Thanks, I have installed the Home Assistant add-on, it works great! What is the easiest way to upload a new configuration to the esp?

Another question, I have looked for the logic around the placement, the it.printf(100, 235, part but I cant find anything, Does anyone know where to read about the logic so there is easier to calculate the placement on the screen?

You need to upload every code change to the ESP board by clicking on “Save and Install” in the top-right corner of the project. The first value in parentheses represents the right-left position, while the second one represents the top-bottom position. You can read more on Display Component — ESPHome

1 Like

Thanks for the link, that explains a lot. But what I don’t understand is what number is the center of the screen for example. I first taught that one digit was one pixel but it doesn’t seams like that. It is possible to know that to plan the layout a lite better?

This is how far I have come now

You have a screen with a resolution of 480x800 pixels. Using these values, you determine the coordinates of the anchoring point. You can use various text alignments, for example: TextAlign::TOP_CENTER, TextAlign::CENTER_RIGHT, TextAlign::CENTER_LEFT, TextAlign::TOP_RIGHT, etc.

1 Like

ok, that probably way I can’t get it right, because of the text alignments. Thanks, will try that!

I don’t quite understand if it’s worth displaying the clock on this screen. The manufacturer recommends updating it at least once every 180 seconds. Otherwise, there will be artifacts

Hi All,

Just wanted to drop in and say thanks for all the help, below is mine now complete. The Sun turns to the moon position at night.

I only have the time update when there is motion in the main room.

3 Likes

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:
4 Likes

Thanks Chris, really appreciate it. I will dive in to the code :grinning_face_with_smiling_eyes:

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

2 Likes

Battery usage looks promising :grin:


Running for about 90 days now.

2 Likes

Where did you buy your ESP32 controler - Ali or ???