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

Already shared this, feel free to copy:

1 Like

How did you implement the battery sensor? I have a FireBeetle 2 ESP32-E IoT. There is a built-in battery connector

2 Likes

I have Aqara Zigbee Temp / Humidity / Pressure sensor which also shows battery level in Home Assistant. From there, it’s only a matter of adding it to the config. If yours is visible in HA then all you need to do is change the portion of my code to match your entity.

How on earth do I get stuff aligned? Look at the bottom there with the “Sons Of T(he) forest” countdown. The icon and the text as al wrong but the others seems fine?!

Here comes the code! I’ve tried all of the text alignments but I can’t figure it out… Really wish there was some software so that one could try the code out and view the result without rewriting the microcontroller and refreshing the E-ink display.

      // Show loading screen before data is received.
        if (id(initial_data_received) == false) {
          it.printf(240, 390, id(font_small_bold),  TextAlign::BASELINE_CENTER, "VÄNTAR PÅ DATA...");
        } else {


        // FORECAST

        it.printf(240, 75, id(font_title), TextAlign::TOP_CENTER, "VÄDER");

        it.printf(100, 149, id(font_mdi_large), TextAlign::TOP_CENTER, "%s", weather_icon_map[id(weather_condition_now).state.c_str()].c_str());

        it.printf(300, 149, id(font_large_bold), TextAlign::TOP_CENTER, "%2.0f°C", id(weather_temperature_now).state);

        // FORECAST
        it.printf(55, 291, id(font_mdi_medium), TextAlign::BASELINE_CENTER , "\U000F00F6"); 
        it.printf(143, 291, id(font_mdi_medium), TextAlign::BASELINE_CENTER , "\U000F18D6");                 
        it.printf(228, 291, id(font_mdi_medium), TextAlign::BASELINE_CENTER  , "\U000F050F"); 
        it.printf(316, 291, id(font_mdi_medium), TextAlign::BASELINE_CENTER, "\U000F054A"); 
        it.printf(404, 291, id(font_mdi_medium), TextAlign::BASELINE_CENTER , "\U000F15FA"); 

        it.printf(55, 326, id(font_small_bold), TextAlign::BASELINE_CENTER , "%s", id(weather_timestamp_0).state.c_str()); 
        it.printf(146, 326, id(font_mdi_small), TextAlign::BASELINE_CENTER , "%s", weather_icon_map[id(weather_condition_0).state.c_str()].c_str());                  
        it.printf(228, 326, id(font_small_bold),  TextAlign::BASELINE_CENTER , "%2.0f °C", id(weather_temperature_0).state);
        it.printf(316, 326, id(font_small_bold),  TextAlign::BASELINE_CENTER , "%2.0f mm", id(weather_precipitation_0).state);
        it.printf(404, 326, id(font_small_bold),  TextAlign::BASELINE_CENTER  , "%2.0f m/s", id(weather_wind_speed_0).state);        

        it.printf(55, 351, id(font_small_bold), TextAlign::BASELINE_CENTER , "%s", id(weather_timestamp_1).state.c_str()); 
        it.printf(146, 351, id(font_mdi_small), TextAlign::BASELINE_CENTER , "%s", weather_icon_map[id(weather_condition_1).state.c_str()].c_str());                    
        it.printf(228, 351, id(font_small_bold),  TextAlign::BASELINE_CENTER , "%2.0f °C", id(weather_temperature_1).state);
        it.printf(316, 351, id(font_small_bold),  TextAlign::BASELINE_CENTER , "%2.0f mm", id(weather_precipitation_1).state);
        it.printf(404, 351, id(font_small_bold),  TextAlign::BASELINE_CENTER  , "%2.0f m/s", id(weather_wind_speed_1).state);   

        it.printf(55, 376, id(font_small_bold), TextAlign::BASELINE_CENTER  , "%s", id(weather_timestamp_2).state.c_str()); 
        it.printf(146, 376, id(font_mdi_small), TextAlign::BASELINE_CENTER  , "%s", weather_icon_map[id(weather_condition_2).state.c_str()].c_str());                    
        it.printf(228, 376, id(font_small_bold),  TextAlign::BASELINE_CENTER  , "%2.0f °C", id(weather_temperature_2).state);
        it.printf(316, 376, id(font_small_bold),  TextAlign::BASELINE_CENTER  , "%2.0f mm", id(weather_precipitation_2).state);
        it.printf(404, 376, id(font_small_bold),  TextAlign::BASELINE_CENTER   , "%2.0f m/s", id(weather_wind_speed_2).state);           

        it.printf(55, 401, id(font_small_bold), TextAlign::BASELINE_CENTER, "%s", id(weather_timestamp_3).state.c_str()); 
        it.printf(146, 401, id(font_mdi_small), TextAlign::BASELINE_CENTER, "%s", weather_icon_map[id(weather_condition_3).state.c_str()].c_str());                     
        it.printf(228, 401, id(font_small_bold),  TextAlign::BASELINE_CENTER, "%2.0f °C", id(weather_temperature_3).state);
        it.printf(316, 401, id(font_small_bold),  TextAlign::BASELINE_CENTER, "%2.0f mm", id(weather_precipitation_3).state);
        it.printf(404, 401, id(font_small_bold),  TextAlign::BASELINE_CENTER , "%2.0f m/s", id(weather_wind_speed_3).state);

        // CALENDAR

        it.printf(240, 441, id(font_medium_bold),  TextAlign::BASELINE_CENTER, "KALENDER");

        it.printf(35, 491, id(font_mdi_medium), TextAlign::BASELINE_LEFT, "\U000F1823"); 
        it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_familj_event).state.c_str());
        it.printf(300, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_familj_txt_days).state.c_str());


        it.printf(35, 541, id(font_mdi_medium), TextAlign::BASELINE_LEFT, "\U000F0E7C"); 
        it.printf(85, 541, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_mossen_event).state.c_str());
        it.printf(300, 541, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_mossen_txt_days).state.c_str());


        it.printf(35, 591, id(font_mdi_medium), TextAlign::BASELINE_LEFT, "\U000F00EB"); 
        it.printf(85, 591, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_fodelsedagar_event).state.c_str());
        it.printf(300, 591, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_fodelsedagar_txt_days).state.c_str());


        it.printf(35, 641, id(font_mdi_medium), TextAlign::BASELINE_LEFT, "\U000F02B4");                 
        it.printf(85, 641, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_media_event).state.c_str());
        it.printf(300, 641, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(calendar_media_txt_days).state.c_str());


        // FOOTER
        //Divider draw a line from [x=0,y=0] to [x=50,y=50]
        it.line(0, 665, 480, 665);
        // Show date and time of last update          
        it.strftime(240, 700, id(font_small_bold), TextAlign::BASELINE_CENTER, "UPPDATERAD: %Y-%m-%d  %H:%M", id(ntp).now());

        }

I have the same problem. Tried some things but still no solution found yet.

Hey guys,

Picked up this project again after a little bit.

Code is not my thing sadly :frowning: wondering if someone can give me a code example for having the display show a list from a calendar entity?

I can get it to show the titles (although the latest ESPHome update seems to have kinda broken it again), but unsure how to get it to display the list from the sensor?

If anyone can have a look and point me in the right direction, would super appreciate that? Here is what I got so far.

esphome:
  name: to-do
  on_boot:
      priority: 200.0
      then:
        - component.update: eink_display  

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: ""

ota:
  password: ""

# 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'

# 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_title
    size: 54
    #glyphs: ['W', 'E', 'A', 'T', 'H', 'R', 'L', 'I', 'N', ' ']
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_medium_bold
    size: 30
    # glyphs: [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'M', 'I', 'N']
  - file: 'fonts/GothamRnd-Bold.ttf'
    id: font_small_bold
    size: 18
    # glyphs: ['°', '0', '1', +'2', '3', '4', '5', '6', '7', '8', '9', 'C', 'M', 'I', 'N']


# 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:
                lambda: 'return id(data_updated) == true;'
              then:
                - lambda: 'id(initial_data_received) = true;'
                - if:
                    condition:
                      binary_sensor.is_on: motion_detected
                    then:
                      - logger.log: "Sensor data updated and activity in home detected: Refreshing display..."
                - component.update: eink_display
                - lambda: 'id(data_updated) = false;'
              else:
                      - logger.log: "Sensor data updated but no activity in home - skipping display refresh."


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "To-Do Fallback Hotspot"
    password: ""


# Check if motion is detected in the bathroom.
binary_sensor:
  - platform: homeassistant
    entity_id: binary_sensor.bathroom_mmwave
    id: motion_detected    

# Call calender sensors from HA.
sensor:
  - platform: homeassistant
    entity_id: calendar.home_assistant_tasks
    id: home_assistant_tasks
    on_value:
      then:
         - lambda: 'id(data_updated) = true;'

  - platform: homeassistant
    entity_id: calendar.alexa_to_do_list
    id: alexa_to_do_list
    on_value:
      then:
         - lambda: 'id(data_updated) = true;'
    
  - platform: homeassistant
    entity_id: calendar.alexa_shopping_list
    id: alexa_shopping_list
    on_value:
      then:
         - lambda: 'id(data_updated) = true;'

# 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
    cs_pin: GPIO15
    dc_pin: GPIO27
    busy_pin: GPIO25
    reset_pin: GPIO26
    reset_duration: 2ms
    model: 7.50inV2
    update_interval: 1h
    rotation: 90°
    lambda: |-


      // Fill background.
      // it.fill(color_bg);

      // Show loading screen before data is received.
      if (id(initial_data_received) == false) {
        it.printf(240, 390, id(font_title), color_black, TextAlign::TOP_CENTER, "WAITING FOR DATA...");
      } else {

        // To Do List
        it.printf(240, 84, id(font_title), color_black, TextAlign::TOP_CENTER, "To Do");


        // Shopping List Section
        it.printf(240, 408, id(font_title), color_black, TextAlign::TOP_CENTER, "Shopping List");




      }


  

captive_portal:

Did you check if the strings sent from HA was not truncated?

I didn’t integrate calendar into my setup, but looks like @filikun did so they might be able to point you in the right direction. :slight_smile:

Awesome, thank you!

I was looking at what other people did, but missed that because its just one value, not a list.

Ill give it a go tonight, I wonder how it will do a list of text. Ill post back

Thanks again for spotting it :slight_smile:

1 Like

So trying to update to 2023.2.4

and getting this error, which is a good thing because its pointing me to why the thing wont work lol

/config/esphome/to-do.yaml: In lambda function:
/config/esphome/to-do.yaml:173:102: error: request for member 'c_str' in 'alexa_to_do_list->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
         it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(alexa_to_do_list).state.c_str());
                                                                                                      ^~~~~
/config/esphome/to-do.yaml:178:105: error: request for member 'c_str' in 'alexa_shopping_list->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
         it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(alexa_shopping_list).state.c_str());
                                                                                                         ^~~~~
*** [/data/to-do/.pioenvs/to-do/src/main.cpp.o] Error 1

So not sure how this works, but I’m trying to show my todoist list.

Todoist - Home Assistant

I have the “.c_str()” added, but I guess the error says it does not get text from the entity?

If I look at that entity in dev tools, I don’t get any attributes other then the friendly name. So not really sure how to get the data out of it to display.

EDIT*

So I had a look in the custom card that actually displays this info on my dashboard and it seems its;

tasksList = hass.states[entityId].attributes.all_tasks

So I tried that. But get the following error, didnt work. Clearly no idea what Im doing HAHA

/config/esphome/to-do.yaml: In lambda function:
/config/esphome/to-do.yaml:173:96: error: 'class esphome::homeassistant::HomeassistantSensor' has no member named 'attributes'; did you mean 'attribute_'?
         it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(alexa_to_do_list).attributes.all_tasks.state.c_str());
                                                                                                ^~~~~~~~~~
                                                                                                attribute_
/config/esphome/to-do.yaml:178:99: error: 'class esphome::homeassistant::HomeassistantSensor' has no member named 'attributes'; did you mean 'attribute_'?
         it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(alexa_shopping_list).attributes.all_tasks.state.c_str());
                                                                                                   ^~~~~~~~~~
                                                                                                   attribute_
*** [/data/to-do/.pioenvs/to-do/src/main.cpp.o] Error 1

EDIT 2 Ok, one thing. The calendar was actually empty, fixed that and after a bit more reading and help from ChatGPT LOL

created the template sensor, its showing as as it should I guess.

But im still getting the same error?

/config/esphome/to-do.yaml: In lambda function:
/config/esphome/to-do.yaml:166:102: error: request for member 'c_str' in 'alexa_to_do_list->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
         it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(alexa_to_do_list).state.c_str());
                                                                                                      ^~~~~
/config/esphome/to-do.yaml:171:105: error: request for member 'c_str' in 'alexa_shopping_list->esphome::homeassistant::HomeassistantSensor::<anonymous>.esphome::sensor::Sensor::state', which is of non-class type 'float'
         it.printf(85, 491, id(font_small_bold),  TextAlign::BASELINE_LEFT, "%s", id(alexa_shopping_list).state.c_str());
                                                                                                         ^~~~~

Oh I also updated the the sensors in the ESPHome yaml

sensor:
  - platform: homeassistant
    entity_id: sensor.esphome_to_do
    id: alexa_to_do_list
    on_value:
      then:
         - lambda: 'id(data_updated) = true;'
    
  - platform: homeassistant
    entity_id: sensor.epshome_shopping_list
    id: alexa_shopping_list
    on_value:
      then:
         - lambda: 'id(data_updated) = true;'

Edit 3

text_sensor

LOL ok, its now updated… and kind of working

Now if anyone has any idea why it looks like complete rubbish HAHA, I would be most grateful :slight_smile:

Check that the A / B switch on the board is correct. I believe it should be set to B for this display if I remember correctly.

No I intentionally truncate them to make them not take the whole area, so the sensor is truncated. Can that affect it’s alignment?

@liminal I have done something like that! Here’s my code, modify it and add it to the weatherman sensor as an attribute (as the rest of them). It is in Swedish but you can translate it to whatever you want :slight_smile:

        calendar_familj_event: >
          {% set event = state_attr('calendar.familj', 'message')  %}
          {{ event |truncate(13, True, '...',0) |upper    }}
        calendar_familj_txt_days: >          
          {% set t = now() %}
          {% set midnight = today_at() %}
          {% set event = state_attr('calendar.familj', 'start_time') | as_datetime | as_local %}
          {% set delta = event - midnight %}
          {% if delta.days == 0 %}
            IDAG
          {% elif delta.days == 1 %}
            IMORGON
          {% elif delta.days == 2 %}
            IÖVERMORGON
          {% else %}
            OM {{ delta.days }} DAGAR
          {% endif %}
1 Like

Its set on the right one for the 7.5" screen. I’ve actually tried both.

I just wish I knew why it was showing so badly.

I think its having these issues because I got the red and black one. Did anyone get that one and have a workaround?

Thanks for that!!! I kinda got it working.

Im really just looking not to have one entry per line. Ive been looking around, but cant seem to see how that works :frowning: if anyone knows :slight_smile: Id appreciate it

1 Like

I also have the black & red board, and for me changing the board model to 7.50in-bV2 seems to have fixed the rendering issue :

display:
  - platform: waveshare_epaper
    id: epaper_display
    cs_pin: GPIO15
    dc_pin: GPIO27
    busy_pin: GPIO25
    reset_pin: GPIO26
    model: 7.50in-bV2
    reset_duration: 200ms
    update_interval: never
    rotation: 90°
1 Like

You are a legend!!! Thank you so much for that, it works :slight_smile:

2 Likes

Today my e-Paper and e-Paper driver board with integrated ESP32 board arrived.
Beginners question :grin:
As this is my first time working with these cables (I did do an mcu with seperate plugs) is it just a matter of plugging the cable in with a little force or can I open the small connector on the board as a lever for low force plugin?
e-Paper-Adapter_24PIN-FFC

I don’t want to kill it before even switching it on.

Maybe post some pics?

Has anyone see this?

Have all my sensors set up right, data is coming though.

But on the actual screen. It shows the same thing???

[17:58:11][D][text_sensor:067]: 'Today Weather': Sending state 'partlycloudy'
[17:58:11][D][homeassistant.text_sensor:017]: 'sensor.esphome_to_do': Got state '['Work on lights', 'Fix Formatting ESP32']'
[17:58:11][D][text_sensor:067]: 'alexa_to_do_list': Sending state '['Work on lights', 'Fix Formatting ESP32']'
[17:58:11][D][homeassistant.text_sensor:017]: 'sensor.epshome_shopping_list': Got state '['tissues']'
[17:58:11][D][text_sensor:067]: 'alexa_shopping_list': Sending state '['tissues']'
[17:58:11][D][homeassistant.text_sensor:017]: 'sensor.bedroom_temperature': Got state '26.4'
[17:58:11][D][text_sensor:067]: 'bedroom_temp': Sending state '26.4'
[17:58:11][D][homeassistant.sensor:022]: 'weather.home::temperature': Got attribute state 23.90
[17:58:11][D][sensor:127]: 'weather_temperature': Sending state 23.90000  with 1 decimals of accuracy

Logs are different, as you can see

YAML is each its own sensor;

        // Outside Temp
        it.printf(80, 90, id(icon_font), TextAlign::BASELINE_LEFT, "\U000F18D7"); 
        // it.printf(100, 85, id(font_title), color_black, TextAlign::BASELINE_LEFT, "O:");
        it.printf(130, 85, id(font_title), color_black, TextAlign::BASELINE_LEFT, "%2.0f°", id(weather_temperature).state);        

        // Inside Temp
        it.printf(240, 90, id(icon_font), TextAlign::BASELINE_LEFT, "\U000F0F55"); 
        // it.printf(290, 85, id(font_title), color_black, TextAlign::BASELINE_LEFT, "I:");        
        it.printf(290, 85, id(font_title), color_black, TextAlign::BASELINE_LEFT, "%2.0f°", id(bedroom_temp).state);   

But they both show on the display as 24

WTF? LOL

Can anyone see anything wrong?

Thanks :slight_smile:

EDIT

Never mind, I moved it to sensor and it shows the right value…

You just have to pull up that little lever on the back of the connector (with your nail for example).

1 Like