E-paper display

The dimensions are 145.5 x 105mm. 70mm deep.

This is so nice - are you able to share your yaml for the weather screen, i am just trying to set one up and an example config would be really helpful.

Andy

@psp888 it would really be in the spirit of this open source community if you could share your yaml and your 3D print files.

Community Guides https://community.home-assistant.io/c/community-guides/51 is a good place to put a howto, with a link back here. Also thingiverse is a good place to put the 3d print files.

It is not compulsory of course, but it would point to you being a good community citizen :slight_smile:

2 Likes

Nick … an emerging role in the pressure squad !

1 Like

Nah but plenty of people have expressed interest and I think it would make a good project to write up. I should have said that I am more than willing to help do a write up!

Me too but I don’t think there’s any onous. Would be appreciated though.

Afternoon - I have ploughed on and managed to get the display running - i am using my own weather data but the config could be easily changed for Open Weather etc.

Yaml so far is below (edited with the latest version) - i was wondering if anyone knows how to add the weather forecast element, looking to add three icons at the bottom of the display to show the next three days weather from openweather…

esphome:
  name: 2incheink
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: !secret WIFI
  password: !secret WIFIPASS

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "2Incheink Fallback Hotspot"
    password: "e3d2h2WY9LL3"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api: 
  

ota:

  
# Example configuration entry
sensor:
  - platform: homeassistant
    id: outtemp
    entity_id: sensor.outdoor_temp
    icon: "mdi:thermometer"
    
  - platform: homeassistant
    id: outtempmin
    entity_id: sensor.outdoor_temp_min
    
  - platform: homeassistant
    id: outtempmax
    entity_id: sensor.outdoor_temp_max  
    
  - platform: homeassistant
    id: pressure
    entity_id: sensor.pressure
    
  - platform: homeassistant
    id: pressuremin
    entity_id: sensor.pressure_min
    
  - platform: homeassistant
    id: pressuremax
    entity_id: sensor.pressure_max
    
  - platform: homeassistant
    id: wind
    entity_id: sensor.wind 
    
  - platform: homeassistant
    id: raintempest
    entity_id: sensor.tempest  
    
text_sensor:

  - platform: homeassistant
    id: winddir
    entity_id: sensor.wind_dir    
    
  - platform: homeassistant
    id: conditionswd
    entity_id: sensor.conditionswd
    
  - platform: homeassistant
    name: forecast
    id: weather_forecast
    entity_id: sensor.forecast
    internal: true    
      

font:

  - file: 'materialdesignicons-webfont.ttf'
    id: icon_font_30
    size: 30
    glyphs:
      - "\U000F050F" # Temp
      - "\U000F029A" # Pressure
      - "\U000F15FA" # Wind
      - "\U000F058C" # Rain
      
  - file: 'materialdesignicons-webfont.ttf'
    id: icon_font_10
    size: 20
    glyphs:
      - "\U000F0E02" # Tempmin
      - "\U000F0E03" # Tempmax
      
      
      
  - file: 'materialdesignicons-webfont.ttf'
    id: conditions
    size: 70
    glyphs:
      - "\U000F0594" # Night Time Clear
      - "\U000F0F31" # Night Time Dry/Part Cloudy
      - "\U000F0595" # Partly Cloudy
      - "\U000F0590" # Cloudy. 
      - "\U000F059B" #Dusk/Dry 
      
  - file: 'Roboto-Medium.ttf'
    id: roboto
    size: 25
    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: 'Roboto-Medium.ttf'
    id: robotosm
    size: 16
    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', '/', 'è']      

 
      
# Example configuration entry
spi:
  clk_pin: D0
  mosi_pin: D1

display:
  - platform: waveshare_epaper
    cs_pin: D2
    dc_pin: D6
    busy_pin: D7
    reset_pin: D5
    model: 2.90in
    full_update_every: 6000
    update_interval: 10s

    lambda: |-
    
     
   
      if (id(conditionswd).state == "Night Time, Clear") {
      it.print(30, 0, id(conditions), "\U000F0594");}
      if (id(conditionswd).state == "Partly Cloudy") {
      it.print(30, 0, id(conditions), "\U000F0595");}
      if (id(conditionswd).state == "Cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0590");}
      if (id(conditionswd).state == "Dusk/Dry") {
      it.print(30, 0, id(conditions), "\U000F059B");}
      if (id(conditionswd).state == "Night_time/Dry") {
      it.print(30, 0, id(conditions), "\U000F0F31");}
      
      
      it.print(5, 70, id(icon_font_30), "\U000F050F");
      it.printf(40, 85, id(roboto), "%.1f", id(outtemp).state);
      
      
      it.print(5, 105, id(icon_font_30), "\U000F029A");
      it.printf(40, 120, id(roboto), "%.1f", id(pressure).state);
      
      
      it.print(5, 140, id(icon_font_30), "\U000F15FA");
      it.printf(40, 155, id(roboto), "%.1f", id(wind).state);
      it.printf(40, 180, id(roboto), "%s", id(winddir).state.c_str());
      
      
      it.print(5, 200, id(icon_font_30), "\U000F058C");
      it.printf(40,215, id(roboto), "%.1f", id(raintempest).state);
      
      
      it.line(5, 240, 120, 240);
      
       it.print(15, 250, id(icon_font_10), "\U000F0E03");
      it.printf(40,260, id(robotosm), "%.1f", id(outtempmax).state);
      
      it.print(15, 270, id(icon_font_10), "\U000F0E02");
      it.printf(40,280, id(robotosm), "%.1f", id(outtempmin).state);
      
      
      
      
      
      
      
7 Likes

Nice one!

Have a look at my project above.

1 Like

Just to update - I have made some progress and have published a case on thingiverse (https://www.thingiverse.com/thing:4692418) I have also commented my Yaml as it might be useful for those starting out with eink and esphome (below).

will do a proper guide in the new year :slight_smile:

esphome:
  name: 2incheink
  platform: ESP8266
  board: nodemcuv2
  
# Set up your wifi - I am using !secret to keep it more secure.  

wifi:
  ssid: !secret WIFI
  password: !secret WIFIPASS

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "2Incheink Fallback Hotspot"
    password: "e3d2h2WY9LL3"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api: 
  

ota:

  
# Configuration  - simply change the id's for the sensors you want to display

sensor:
  - platform: homeassistant
    id: outtemp
    entity_id: sensor.outdoor_temp
    icon: "mdi:thermometer"
    
  - platform: homeassistant
    id: outtempmin
    entity_id: sensor.outdoor_temp_min
    
  - platform: homeassistant
    id: outtempmax
    entity_id: sensor.outdoor_temp_max  
    
  - platform: homeassistant
    id: pressure
    entity_id: sensor.pressure
    
  - platform: homeassistant
    id: pressuremin
    entity_id: sensor.pressure_min
    
  - platform: homeassistant
    id: pressuremax
    entity_id: sensor.pressure_max
    
  - platform: homeassistant
    id: wind
    entity_id: sensor.wind 
    
  - platform: homeassistant
    id: rainvue
    entity_id: sensor.vue
    
text_sensor:

  - platform: homeassistant
    id: winddir
    entity_id: sensor.wind_dir    
    
  - platform: homeassistant
    id: conditionswd
    entity_id: sensor.conditionswd
    
  - platform: homeassistant
    name: forecast
    id: weather_forecast
    entity_id: sensor.forecast
    internal: true   
    
  - platform: homeassistant
    name: temptrend
    id: temptrend
    entity_id: sensor.temperature_trend
    internal: true      
      
# Various fonts - Icons and text at various sizes
# Icons are mapped to the code next to the Material Design Icons Preview.html (fonts need to be uploaded to the esphome folder)
# I am using Roboto-medium from Google Fonts


font:

  - file: 'materialdesignicons-webfont.ttf'
    id: icon_font_30
    size: 30
    glyphs:
      - "\U000F050F" # Temp
      - "\U000F029A" # Pressure
      - "\U000F15FA" # Wind
      - "\U000F058C" # Rain 
      - "\U000F0737" # Rising
      - "\U000F072E" # Falling
      
  - file: 'materialdesignicons-webfont.ttf'
    id: icon_font_10
    size: 20
    glyphs:
      - "\U000F0E02" # Tempmin
      - "\U000F0E03" # Tempmax
      
      
      
  - file: 'materialdesignicons-webfont.ttf'
    id: conditions
    size: 70
    glyphs:
      - "\U000F0594" # Night Time Clear
      - "\U000F0F31" # Night Time Dry/Part Cloudy
      - "\U000F0595" # Partly Cloudy
      - "\U000F0590" # Cloudy. 
      - "\U000F059B" #Dusk/Dry 
      - "\U000F0599" #Sunny/Dry 
      - "\U000F0596" #Raining 
      - "\U000F0F33" #Stopped Raining
      - "\U000F067F" #Sleet
      - "\U000F0F36" #Snowing
      - "\U000F0591" #Fog
      
      
  - file: 'Roboto-Medium.ttf'
    id: roboto
    size: 25
    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: 'Roboto-Medium.ttf'
    id: robotosm
    size: 16
    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', '/', 'è']      

 
      
# Configuration for the 2.9inch Waveshare - note the pin numbers so they match your NodeMCU
# The screen does a full update every hour and partial every 10s - edit these according to your use

spi:
  clk_pin: D0
  mosi_pin: D1

display:
  - platform: waveshare_epaper
    cs_pin: D2
    dc_pin: D6
    busy_pin: D7
    reset_pin: D5
    model: 2.90in
    full_update_every: 3600
    rotation: 180
    update_interval: 10s

# Layout - The main part to edit will be the conditions state - this is set for my live weather feed, so edit according to your
# weather icons - probably codes. The Trend arrow reads -1 for falling, 1 for rising - edit out as needs be. The last two
# under the line are the smaller min/max temp icons and data. 

    lambda: |-
    
 
      if (id(conditionswd).state == "Night Time, Clear") {
      it.print(30, 0, id(conditions), "\U000F0594");}
      if (id(conditionswd).state == "Partly_cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0595");}
      if (id(conditionswd).state == "Cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0590");}
      if (id(conditionswd).state == "Mainly_cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0590");}
      if (id(conditionswd).state == "Sunny/Dry") {
      it.print(30, 0, id(conditions), "\U000F0599");}
      if (id(conditionswd).state == "Raining") {
      it.print(30, 0, id(conditions), "\U000F0599");}
      if (id(conditionswd).state == "Cloudy/Moderate_drizzle") {
      it.print(30, 0, id(conditions), "\U000F0596");}
      if (id(conditionswd).state == "Cloudy/Light_rain") {
      it.print(30, 0, id(conditions), "\U000F0596");}
      if (id(conditionswd).state == "Dusk/Dry") {
      it.print(30, 0, id(conditions), "\U000F059B");}
      if (id(conditionswd).state == "Night_time/Dry") {
      it.print(30, 0, id(conditions), "\U000F0F31");}
      if (id(conditionswd).state == "Dawn/Fog") {
      it.print(30, 0, id(conditions), "\U000F0591");}
       if (id(conditionswd).state == "Fog") {
      it.print(30, 0, id(conditions), "\U000F0591");}
      
      
      it.print(5, 70, id(icon_font_30), "\U000F050F");
      it.printf(40, 85, id(roboto), "%.1f", id(outtemp).state);
      if (id(temptrend).state == "-1") {
      it.print(75, 70, id(icon_font_30), "\U000F072E");}
      if (id(temptrend).state == "1") {
      it.print(75, 70, id(icon_font_30), "\U000F0737");}
      
      
      it.print(5, 105, id(icon_font_30), "\U000F029A");
      it.printf(40, 120, id(roboto), "%.1f", id(pressure).state);
      
      
      it.print(5, 140, id(icon_font_30), "\U000F15FA");
      it.printf(40, 155, id(roboto), "%.1f", id(wind).state);
      it.printf(40, 180, id(roboto), "%s", id(winddir).state.c_str());
      
      
      it.print(5, 200, id(icon_font_30), "\U000F058C");
      it.printf(40,215, id(roboto), "%.1f", id(rainvue).state);
      
      
      it.line(5, 240, 120, 240);
      
       it.print(15, 250, id(icon_font_10), "\U000F0E03");
      it.printf(40,260, id(robotosm), "%.1f", id(outtempmax).state);
      
      it.print(15, 270, id(icon_font_10), "\U000F0E02");
      it.printf(40,280, id(robotosm), "%.1f", id(outtempmin).state);
      
      
      
      
      
      
9 Likes

Evening - I am now looking at doing the same thing on the 4.2 inch waveshare screen - this screen does not have partial updates so I’m using a timed refresh.

My problem is all the sensors come in as NAN with the screen refreshing before the data arrives - I have looked up all the forums (and posted but prob should have posted in this thread first)

I thought i had solved it - by wrapping my print function in an has_state (for example):

Copy to clipboard

 if (id(outtemp).has_state()) {
      it.printf(40, 85, id(roboto), "%.1f", id(outtemp).state);
      }

but no joy.

I am at a loss, any ideas or hints would be great, the data is all in HA via mqtt, not sure if that would make a difference.

Andy

1 Like

@psp888. Is there a chance you will post your 3 display casing print file for everyone or is that a ‘no’?
I’m sure it would be much appreciated.

Have you verified there are actually MQTT topics with the information?
MQTT Explorer is great for this.
I have a 4.2" waveshare monocrome display; I at the moment just ran a python script to make a clock. I have it on a pi and not an ESP device. The display was a nice extra, the main purpose of the pi is the USB speaker I use for Text to Speech via Kodi on the pi via Home Assistant. I need to print a new case, but not bad for a first attempt.

2 Likes

Thanks for the reply - nice clock and case.

Yep i am using MQTT Explorer - your right it is great. I also have another display next to it, updating on a 2.9 inch screen (these have partial updates).

The pi works well with eink screens and i guess I’m a little more at ease with python than c++ - i did a tutorial on making a Time, News and Headline device using the InkyWhat screen last year ([https://connected-environments.org/making/the/]

Just for the life of me I cant get it working with HA (well it works but NAN on all data).

edit - solved! i had somehow forgotten to integrate the new esp32 to HA! ugh a rookie error…

Andy

4 Likes

been busy. I have no problem sharing my clock STL files, but I cannot attach files on here

Main Clock YAML

font:
  - file: 'Roboto-Medium.ttf'
    id: clock_font
    size: 85
  - file: 'Roboto-Medium.ttf'
    id: clock_sec_font
    size: 60
  - file: 'Roboto-Medium.ttf'
    id: date_font
    size: 50
  - file: 'Roboto-Medium.ttf'
    id: date_text_font
    size: 14
  - file: 'Roboto-Medium.ttf'
    id: sun_font
    size: 20
  - file: 'materialdesignicons-webfont.ttf'
    id: weather_font
    size: 45
    glyphs: [
      # Moon
      "チ", # new_moon
      "ト", # waxing_crecent
      "セ", # first_quarter
      "ナ", # waxing_gibbous
      "ソ", # full_moon
      "テ", # waning_gibbous
      "タ", # last_quarter
      "ツ", # waning_crescent
      ]
  - file: 'materialdesignicons-webfont.ttf'
    id: sun_icon_font
    size: 20
    glyphs: [
      "", # sun rise
      "", # sun set
      ]
    
    
spi:
  clk_pin: D0
  mosi_pin: D1

display:
  - platform: waveshare_epaper
    id: epaper
    cs_pin: D2
    busy_pin: D7
    reset_pin: D5
    dc_pin: D6
    model: 2.90in
    rotation: 90
    full_update_every: 14400
    update_interval: 1s
    lambda: |-
      /* Moon icon */
      if(id(moon_icon).has_state()) {
        //ESP_LOGI("Moon icon", "%s", id(moon_icon).state.c_str());
        it.printf(25, 42, id(weather_font), TextAlign::BASELINE_CENTER, "%s", id(moon_icon).state.c_str());
      }
      
      //sun set-rise
      it.printf(85, 22, id(sun_icon_font), TextAlign::BASELINE_RIGHT, "");
      it.printf(135, 22, id(sun_font), TextAlign::BASELINE_RIGHT, "%s", id(sunrise).state.c_str());
      it.printf(85, 44, id(sun_icon_font), TextAlign::BASELINE_RIGHT, "");
      it.printf(135, 44, id(sun_font), TextAlign::BASELINE_RIGHT, "%s", id(sunset).state.c_str());
      
      //date
      it.strftime(210, 43, id(date_font), TextAlign::BASELINE_RIGHT, "%d", id(sntp_time).now());
      it.printf(213, 43, id(date_text_font), TextAlign::BASELINE_LEFT, "D");
      it.strftime(280, 43, id(date_font), TextAlign::BASELINE_RIGHT, "%m", id(sntp_time).now());
      it.printf(283, 43, id(date_text_font), TextAlign::BASELINE_LEFT, "M");
    
      //line
      it.line(0, 54, 296, 54);
      
      //Time
      it.strftime(3, 45, id(clock_font), "%H:%M", id(sntp_time).now());
      it.strftime(225, 68, id(clock_sec_font), "%S", id(sntp_time).now());
      
      it.strftime(250, 58, id(date_text_font), "%a", id(sntp_time).now());
    
    
text_sensor:
  - platform: homeassistant
    id: moon_icon
    entity_id: sensor.moon_tpl
  - platform: homeassistant
    id: sunrise
    entity_id: sensor.nextsunrise
  - platform: homeassistant
    id: sunset
    entity_id: sensor.nextsunset
    
time:
  - platform: sntp
    timezone: Europe/London
    id: sntp_time

Temperature Screen

font:
  - file: 'Roboto-Medium.ttf'
    id: main_75_font
    size: 75
  - file: 'Roboto-Medium.ttf'
    id: main_60_font
    size: 60
  - file: 'Roboto-Medium.ttf'
    id: main_50_font
    size: 50
  - file: 'Roboto-Medium.ttf'
    id: main_30_font
    size: 30
  - file: 'Roboto-Medium.ttf'
    id: main_20_font
    size: 20
  - file: 'materialdesignicons-webfont.ttf'
    id: icon_45_font
    size: 45
    glyphs: [
      # Moon
      "チ", # new_moon
      "ト", # waxing_crecent
      "セ", # first_quarter
      "ナ", # waxing_gibbous
      "ソ", # full_moon
      "テ", # waning_gibbous
      "タ", # last_quarter
      "ツ", # waning_crescent
      ]
  - file: 'materialdesignicons-webfont.ttf'
    id: icon_20_font
    size: 20
    glyphs: [
      "", # sun rise
      "", # sun set
      ]
    
spi:
  clk_pin: D0
  mosi_pin: D1
    
display:
  - platform: waveshare_epaper
    id: epaper
    cs_pin: D2
    busy_pin: D7
    reset_pin: D5
    dc_pin: D6
    model: 2.90in
    rotation: 90
    full_update_every: 14400
    update_interval: 60s
    lambda: |-
      it.print(0, 20, id(main_20_font), TextAlign::BASELINE_LEFT , "OUT");
      it.printf(190, 60, id(main_75_font), TextAlign::BASELINE_RIGHT , "%.1f", id(outside_temp).state);
      it.printf(190, 45, id(main_30_font), TextAlign::BASELINE_LEFT , "°");
      it.printf(191, 60, id(main_30_font), TextAlign::BASELINE_LEFT , "C");
      it.printf(280, 60, id(main_50_font), TextAlign::BASELINE_RIGHT , "%.0f", id(outside_humidity).state);
      it.printf(296, 60, id(main_20_font), TextAlign::BASELINE_RIGHT , "%%");
      
      //line
      it.line(0, 70, 296, 70);
      
      it.print(0, 95, id(main_20_font), TextAlign::BASELINE_LEFT , "IN");
      it.printf(190, 125, id(main_60_font), TextAlign::BASELINE_RIGHT , "%.1f", id(inside_temp).state);
      it.printf(190, 110, id(main_30_font), TextAlign::BASELINE_LEFT , "°");
      it.printf(191, 125, id(main_30_font), TextAlign::BASELINE_LEFT , "C");
      it.printf(280, 125, id(main_50_font), TextAlign::BASELINE_RIGHT , "%.0f", id(inside_humidity).state);
      it.printf(296, 125, id(main_20_font), TextAlign::BASELINE_RIGHT , "%%");
      
sensor:
  - platform: homeassistant
    entity_id: sensor.temperature_158d000245dc33
    id: outside_temp
    internal: true
  - platform: homeassistant
    entity_id: sensor.living_room_temperature
    id: inside_temp
    internal: true
  - platform: homeassistant
    entity_id: sensor.humidity_158d000245dc33
    id: outside_humidity
    internal: true
  - platform: homeassistant
    entity_id: sensor.living_room_humidity
    id: inside_humidity
    internal: true

Weather Screen

font:
  - file: 'Roboto-Light.ttf'
    id: size_12_font
    size: 12
  - file: 'Roboto-Medium.ttf'
    id: size_15_font
    size: 15
  - file: 'Roboto-Medium.ttf'
    id: size_20_font
    size: 20
  - file: 'Roboto-Medium.ttf'
    id: size_25_font
    size: 25
  - file: 'Roboto-Medium.ttf'
    id: size_30_font
    size: 30
  - file: 'materialdesignicons-webfont.ttf'
    id: weather_font
    size: 120
    glyphs: [
      # Weather
      "", # mdi-weather-sunny
      "", # mdi-weather-cloudy
      "", # mdi-weather-pouring
      "", # mdi-weather-snowy-rainy
      "s", # mdi-weather-snowy-heavy
      "", # mdi-weather-windy-variant
      "", # mdi-weather-fog
      "n", # mdi-weather-night-partly-cloudy
      "", # mdi-weather-partly-cloudy
      "", # mdi-weather-rainy
      "", # mdi-weather-snowy
      "", # mdi-weather-clear-night
      "", # unknown
      ]
  - file: 'materialdesignicons-webfont.ttf'
    id: weather_temp_icon_font
    size: 25
    glyphs: [
      "﹢", # mdi-down
      "﹣",  # mdi-up
      "", # raindrop
      "", # wind
      ]
  - file: 'materialdesignicons-webfont.ttf'
    id: home_icon_font
    size: 15
    glyphs: [
      "ﵜ", # mdi-house1
      "ﵝ",  # mdi-house2
      "ﵞ", # mdi-house3
      "", # mdi-bowl
      "", #mdi-knifeandfork
      ]

    
    
spi:
  clk_pin: D0
  mosi_pin: D1

display:
  - platform: waveshare_epaper
    id: epaper
    cs_pin: D2
    busy_pin: D7
    reset_pin: D5
    dc_pin: D6
    model: 2.90in
    rotation: 180
    full_update_every: 14400
    update_interval: 120s
    lambda: |-
      if (id(forecast_condition).has_state()) {
        if (id(forecast_condition).state == "snowy-rainy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "snowy-heavy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "s");
        } else if (id(forecast_condition).state == "rainy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "pouring") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "cloudy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "partlycloudy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "sunny") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "windyvariant") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "fog") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "nightpartlycloudy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "n");
        } else if (id(forecast_condition).state == "partlycloudy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "snowy") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else if (id(forecast_condition).state == "clear-night") {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        } else {
          it.printf(64, 98, id(weather_font), TextAlign::BASELINE_CENTER , "");
        }
      }
      
      it.printf(64, 122, id(size_20_font), TextAlign::BASELINE_CENTER , "%s", id(forecast_condition).state.c_str());

      it.printf(24, 152, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "﹣");
      if (id(forecast_temperature).has_state()) {
        it.printf(98, 154, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(forecast_temperature).state);
        it.printf(99, 148, id(size_20_font), TextAlign::BASELINE_LEFT , "°");
        it.printf(100, 154, id(size_20_font), TextAlign::BASELINE_LEFT , "C");
      }
      
      it.printf(24, 183, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "﹢");
      if (id(forecast_temperature_low).has_state()) {
        it.printf(98, 185, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(forecast_temperature_low).state);
        it.printf(99, 179, id(size_20_font), TextAlign::BASELINE_LEFT , "°");
        it.printf(100, 185, id(size_20_font), TextAlign::BASELINE_LEFT , "C");
      }
      
      std::string str = id(forecast_precipitation).state;
      //ESP_LOGI("Weather", "%s", str.c_str());

      it.printf(24, 214, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "");
      if (id(forecast_precipitation).has_state()) {
        if (str != "unknown") {
          it.printf(98, 216, id(size_30_font), TextAlign::BASELINE_RIGHT , "%s", id(forecast_precipitation).state.c_str());
          it.printf(99, 216, id(size_12_font), TextAlign::BASELINE_LEFT , "mm");
        }
        else {
          it.printf(98, 216, id(size_30_font), TextAlign::BASELINE_RIGHT , "0.0");
          it.printf(99, 216, id(size_12_font), TextAlign::BASELINE_LEFT , "mm");
        }
      }

      
      it.printf(24, 245, id(weather_temp_icon_font), TextAlign::BASELINE_CENTER , "");
      if (id(forecast_wind_speed).has_state()) {
        it.printf(98, 247, id(size_30_font), TextAlign::BASELINE_RIGHT , "%.1f", id(forecast_wind_speed).state * 2.237);
        it.printf(99, 247, id(size_12_font), TextAlign::BASELINE_LEFT , "mph");
      }
      
      //line
      it.line(0, 260, 128, 260);
    
      //bedroom1
      it.printf(0, 280, id(home_icon_font), TextAlign::BASELINE_LEFT , "ﵜ");
      it.printf(50, 280, id(size_15_font), TextAlign::BASELINE_RIGHT , "%.1f", id(bedroom1).state);
      
      //bedroom2
      it.printf(78, 280, id(home_icon_font), TextAlign::BASELINE_LEFT , "ﵝ");
      it.printf(128, 280, id(size_15_font), TextAlign::BASELINE_RIGHT , "%.1f", id(bedroom2).state);
      
      //bedroom3
      it.printf(0, 294, id(home_icon_font), TextAlign::BASELINE_LEFT , "ﵞ");
      it.printf(50, 294, id(size_15_font), TextAlign::BASELINE_RIGHT , "%.1f", id(bedroom3).state);
      
      //kitchen
      it.printf(78, 294, id(home_icon_font), TextAlign::BASELINE_LEFT , "");
      it.printf(128, 294, id(size_15_font), TextAlign::BASELINE_RIGHT , "%.1f", id(kitchen).state);
    
text_sensor:
  - platform: homeassistant
    entity_id: sensor.openweathermaphourly_forecast_condition
    id: forecast_condition
    internal: true
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_precipitation
    id: forecast_precipitation
    internal: true
    
sensor:
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_temperature
    id: forecast_temperature
    internal: true
  - platform: homeassistant
    entity_id: sensor.openweathermap_forecast_temperature_low
    id: forecast_temperature_low
    internal: true
  - platform: homeassistant
    entity_id: sensor.openweathermaphourly_forecast_wind_speed
    id: forecast_wind_speed
    internal: true
  - platform: homeassistant
    entity_id: sensor.bedroom_temperature
    id: bedroom1
    internal: true
  - platform: homeassistant
    entity_id: sensor.kids_room_temperature
    id: bedroom2
    internal: true
  - platform: homeassistant
    entity_id: sensor.temperature_158d0002477c72
    id: bedroom3
    internal: true
  - platform: homeassistant
    entity_id: sensor.temperature_158d000237110c
    id: kitchen
    internal: true
1 Like

Thought those interested in the thread might like to see the 4.2 inch version of using eink for HA data. The layout is a little challenging as there is no style sheet so its x/y pixels and the centre align needs tweaking according to the data…

I was going to do a write up so people dont have to go through the hoops i had to to learn it… as ever with things its quite easy once you know how, but knowing how took a few threads, a couple of bricking the node mcu and a few tweaks on the 3D print (which i will put on thingiverse)…

Andy

12 Likes

Just updating the 2.9 inch display to include a clock, maximum wind gust and some minor layout changes - now also updated on Thingiverse (https://www.thingiverse.com/thing:4692418)

Yaml -

esphome:
  name: 2incheink
  platform: ESP8266
  board: nodemcuv2
  
time:
  - platform: homeassistant
    id: homeassistant_time 
  
  
# Set up your wifi - I am using !secret to keep it more secure.  

wifi:
  ssid: !secret WIFI
  password: !secret WIFIPASS

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "2Incheink Fallback Hotspot"
    password: "e3d2h2WY9LL3"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api: 
  


ota:


  
# Configuration  - simply change the id's for the sensors you want to display

sensor:


    
  - platform: homeassistant
    id: outtemp
    entity_id: sensor.outdoor_temp
    
  - platform: homeassistant
    id: outtempmin
    entity_id: sensor.outdoor_temp_min
    
  - platform: homeassistant
    id: outtempmax
    entity_id: sensor.outdoor_temp_max  
    
  - platform: homeassistant
    id: pressure
    entity_id: sensor.pressure
    
  - platform: homeassistant
    id: pressuremin
    entity_id: sensor.pressure_min
    
  - platform: homeassistant
    id: pressuremax
    entity_id: sensor.pressure_max
    
  - platform: homeassistant
    id: wind
    entity_id: sensor.wind 
    
  - platform: homeassistant
    id: windav10
    entity_id: sensor.wind_average_10_min  
    
  - platform: homeassistant
    id: rainvue
    entity_id: sensor.vue
    
  - platform: homeassistant
    id: windmax
    entity_id: sensor.max_wind      
    
 
    
text_sensor:


  - platform: homeassistant
    id: winddir
    entity_id: sensor.wind_dir    
    
    
  - platform: homeassistant
    id: conditionswd
    entity_id: sensor.conditionswd
    
  - platform: homeassistant
    name: forecast
    id: weather_forecast
    entity_id: sensor.forecast
    internal: true   
    
  - platform: homeassistant
    name: temptrend
    id: temptrend
    entity_id: sensor.temperature_trend
    internal: true      
      
# Various fonts - Icons and text at various sizes
# Icons are mapped to the code next to the Material Design Icons Preview.html (fonts need to be uploaded to the esphome folder)
# I am using Roboto-medium from Google Fonts


font:

  - file: 'materialdesignicons-webfont.ttf'
    id: icon_font_30
    size: 30
    glyphs:
      - "\U000F050F" # Temp
      - "\U000F029A" # Pressure
      - "\U000F15FA" # Wind
      - "\U000F058C" # Rain 
      - "\U000F0737" # Rising
      - "\U000F072E" # Falling
      
  - file: 'materialdesignicons-webfont.ttf'
    id: icon_font_10
    size: 20
    glyphs:
      - "\U000F0E02" # Tempmin
      - "\U000F0E03" # Tempmax
      - "\U000F15FA" # Wind
      - "\U000F0150" # Clock
      
      
      
  - file: 'materialdesignicons-webfont.ttf'
    id: conditions
    size: 70
    glyphs:
      - "\U000F0594" # Night Time Clear
      - "\U000F0F31" # Night Time Dry/Part Cloudy
      - "\U000F0595" # Partly Cloudy
      - "\U000F0590" # Cloudy. 
      - "\U000F059B" #Dusk/Dry 
      - "\U000F0599" #Sunny/Dry 
      - "\U000F0596" #Raining 
      - "\U000F0F33" #Stopped Raining
      - "\U000F067F" #Sleet
      - "\U000F0F36" #Snowing
      - "\U000F0591" #Fog
      
      
  - file: 'Roboto-Medium.ttf'
    id: roboto
    size: 25
    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: 'Roboto-Medium.ttf'
    id: robotosm
    size: 16
    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', '/', 'è']      

 
      
# Configuration for the 2.9inch Waveshare - note the pin numbers so they match your NodeMCU
# The screen does a full update every hour and partial every 10s - edit these according to your use

spi:
  clk_pin: D0
  mosi_pin: D1

display:
  - platform: waveshare_epaper
    cs_pin: D2
    dc_pin: D6
    busy_pin: D7
    reset_pin: D5
    model: 2.90in
    full_update_every: 60
    rotation: 180
    update_interval: 60s

# Layout - The main part to edit will be the conditions state - this is set for my live weather feed, so edit according to your
# weather icons - probably codes. The Trend arrow reads -1 for falling, 1 for rising - edit out as needs be. The last two
# under the line are the smaller min/max temp icons and data. 

    lambda: |-
    
 
      if (id(conditionswd).state == "Night Time, Clear") {
      it.print(30, 0, id(conditions), "\U000F0594");}
      if (id(conditionswd).state == "Partly_cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0595");}
      if (id(conditionswd).state == "Cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0590");}
      if (id(conditionswd).state == "Mainly_cloudy/Dry") {
      it.print(30, 0, id(conditions), "\U000F0590");}
      if (id(conditionswd).state == "Sunny/Dry") {
      it.print(30, 0, id(conditions), "\U000F0599");}
      if (id(conditionswd).state == "Raining") {
      it.print(30, 0, id(conditions), "\U000F0599");}
      if (id(conditionswd).state == "Cloudy/Moderate_drizzle") {
      it.print(30, 0, id(conditions), "\U000F0596");}
      if (id(conditionswd).state == "Cloudy/Light_rain") {
      it.print(30, 0, id(conditions), "\U000F0596");}
      if (id(conditionswd).state == "Night_time/Moderate_drizzle") {
      it.print(30, 0, id(conditions), "\U000F0596");}
      if (id(conditionswd).state == "Night_time/Moderate_rain") {
      it.print(30, 0, id(conditions), "\U000F0596");}  
      if (id(conditionswd).state == "Night_time/Stopped_raining") {
      it.print(30, 0, id(conditions), "\U000F0F31");}
      if (id(conditionswd).state == "Cloudy/Stopped_raining") {
      it.print(30, 0, id(conditions), "\U000F0F33");}
      if (id(conditionswd).state == "Dusk/Dry") {
      it.print(30, 0, id(conditions), "\U000F059B");}
      if (id(conditionswd).state == "Night_time/Dry") {
      it.print(30, 0, id(conditions), "\U000F0F31");}
      if (id(conditionswd).state == "Dawn/Fog") {
      it.print(30, 0, id(conditions), "\U000F0591");}
       if (id(conditionswd).state == "Fog") {
      it.print(30, 0, id(conditions), "\U000F0591");}
      if (id(conditionswd).state == "Night_time/Sleet_fall") {
      it.print(30, 0, id(conditions), "\U000F067F");}
      if (id(conditionswd).state == "Cloudy/Fog") {
      it.print(30, 0, id(conditions), "\U000F0591");}
    
      it.print(5, 70, id(icon_font_30), "\U000F050F");
      it.printf(40, 85, id(roboto), "%.1f", id(outtemp).state);
      if (id(temptrend).state == "-1") {
      it.print(95, 70, id(icon_font_30), "\U000F072E");}
      if (id(temptrend).state == "1") {
      it.print(95, 70, id(icon_font_30), "\U000F0737");}
  
      it.print(5, 105, id(icon_font_30), "\U000F029A");
      it.printf(40, 120, id(roboto), "%.1f", id(pressure).state);
      
      it.print(5, 140, id(icon_font_30), "\U000F15FA");
      it.printf(40, 155, id(roboto), "%.1f", id(windav10).state);
      it.printf(40, 180, id(roboto), "%s", id(winddir).state.c_str());
      
      it.print(5, 200, id(icon_font_30), "\U000F058C");
      it.printf(40,215, id(roboto), "%.1f", id(rainvue).state);
      
      it.line(5, 240, 125, 240);
      
      it.print(5, 250, id(icon_font_10), "\U000F0E03");
      it.printf(30,260, id(robotosm), "%.1f", id(outtempmax).state);
      
      it.print(5, 270, id(icon_font_10), "\U000F0E02");
      it.printf(30,280, id(robotosm), "%.1f", id(outtempmin).state);
      
      it.print(65, 250, id(icon_font_10), "\U000F15FA");
      it.printf(95,260, id(robotosm), "%.1f", id(windmax).state);
      it.print(61, 270, id(icon_font_10), "\U000F0150");
      it.strftime(87, 270, id(robotosm), "%H:%M", id(homeassistant_time).now());
      
     ```
2 Likes

I have a slightly unique issue. When I loose internet (due to power outages), I have have a generator for backup power but I loose connection to a time server. I noticed that over an 4 hour period my time is off by over 30 mins.

What are some good options here; I’m running my display on a pi and not an ESP.
My Home Assistant instance is on a PC with a real time clock.
So, should I pull the time from a GPS; a docker network time server, …

There is a chrony addon.

For anyone interested, the 4.2 inch case (pictured a few posts up) is now on Thingiverse to print:

https://www.thingiverse.com/thing:4721366

Andy

4 Likes