4 minutes
Add an ePaper display to your ESP32 (Waveshare)
Introduction ¶
With my desk being located in a more secluded part of the house, I wanted to build something that could notify me of important things. And while having a LED light up – maybe even with different colours – is nice, I wanted something more.
So I decided to test out a few displays.
These displays would then be able to show me more than just whether someone’s at the door or that someone dropped something in the mailbox.
In this blog post, I’ll be discussing the Waveshare 2.13" ePaper display.
Requirements (shopping list) ¶
Pretty obvious shopping list:
- 2.13 inch Waveshare ePaper Display HAT
- an ESP32 board (e.g., MH-ET LIVE ESP32)

Waveshare ePaper Display ¶
Waveshare has a wide range of ePaper displays and ESPHome supports most – if not all – of them.
I went with the HAT (Hardware Attached on Top) model because my plan was to mount it to my case using a 40-pin (double 20-pin) header.
However, even though I believe I managed to identify the pins in the pin header matching the pins on the 8-pin connector,
I was unable to get it to work using these pins.
So finally I decided to use the 8-pin connector already provided with the display.
The 2.13" model I purchased communicates over 4-wire SPI. It has a resolution of 250x122 pixels. And it supports partial refresh.
ESPHome config ¶
The ESPHome config is pretty easy.
- Open the ESPHome dashboard and add your ESP32 board as a new device.
- Pick the correct board so that the auto-generated code has the correct values.
- Add the definition for SPI
- Add the code below to display a “Hello World!” on your display.
Add it below the auto-generated config.
font:
- file: "fonts/monof55.ttf"
id: monofur
size: 28
spi:
clk_pin: 18
mosi_pin: 23
display:
- platform: waveshare_epaper
cs_pin: 5
dc_pin: 21
busy_pin: 19
reset_pin: 22
model: 2.13in-ttgo
rotation: 90°
id: my_display
lambda: |-
it.printf(125, 6, id(monofur), TextAlign::TOP_CENTER, "%s", "Hello World!");
it.strftime(125, 116, id(monofur), TextAlign::BOTTOM_CENTER, "%Y-%m-%d %H:%M", id(time_homeassistant).now());
time:
- platform: homeassistant
id: time_homeassistant
Make sure you match the pins in the config to your setup.
Fonts ¶
See that font
section?
For the display to show text, it’ll need a font.
Find yourself a TrueType Font (.ttf) file and upload it to the /config/esphome/
folder.
Note that I created a subfolder /config/esphome/fonts/
to store my font files,
so I adjusted the path accordingly.
Full configuration ¶
Below is the full configurations you can use. Replace your existing code with this and adapt where necessary (e.g., board type and naming).
---
# ESP32 board:
# - https://s.click.aliexpress.com/e/_97FTTR
# Waveshare 2.13" ePaper Display:
# - https://s.click.aliexpress.com/e/_9JZHkB
# ESPHome docs:
# - https://esphome.io/components/display/waveshare_epaper.html
# - https://esphome.io/components/spi.html
# - https://esphome.io/components/display/index.html
# Wiring diagram
# | ePaper | ESP32 | Description |
# | :-----: | :---: | :--------------- |
# | VCC | 3.3V | 3.3V power |
# | GND | GND | Ground |
# | CLK | 18 | Serial clock |
# | DIN | 23 | SPI MOSI |
# | CS | 5 | Chip Select |
# | DC | 21 | SPI DC |
# | BUSY | 19 | Busy (optional) |
# | RESET | 22 | Reset (optional) |
# Setup some variables
substitutions:
slug: esp32_waveshare
name: Waveshare
description: Demo by sequr.be for ESP32 with Waveshare ePaper display
# Basic config for the board
esphome:
name: "${slug}"
comment: "${description}"
platform: ESP32
board: mhetesp32devkit
# Connect with WiFi
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
# Enable logging
logger:
# Enable Home Assistant API
api:
password: !secret esphome_api_pass
# Enable Over-the-Air updates
ota:
password: !secret esphome_ota_pass
# Enable HTTP webserver
web_server:
port: 80
auth:
username: !secret esphome_web_user
password: !secret esphome_web_pass
# Sync time with Home Assistant
time:
- platform: homeassistant
id: time_homeassistant
# TrueType Font file stored in /config/esphome/fonts/
# https://all-free-download.com/font/monospace.html
font:
- file: "fonts/monof55.ttf"
id: monofur
size: 28
# Setup SPI
spi:
clk_pin: 18
mosi_pin: 23
# Configuration for the display
display:
- platform: waveshare_epaper
cs_pin: 5
dc_pin: 21
busy_pin: 19
reset_pin: 22
model: 2.13in-ttgo
rotation: 90°
id: my_display
lambda: |-
it.printf(125, 6, id(monofur), TextAlign::TOP_CENTER, "%s", "Hello World!");
it.strftime(125, 116, id(monofur), TextAlign::BOTTOM_CENTER, "%Y-%m-%d %H:%M", id(time_homeassistant).now());
# switches, sensors, text_sensors
switch:
- platform: restart
id: switch_restart
name: "${name} Restart"
sensor:
- platform: uptime
id: sensor_uptime
- platform: template
id: sensor_wifi_signal_percentage
name: "${name} Wi-Fi Signal Percentage"
icon: "mdi:wifi"
unit_of_measurement: "%"
update_interval: never
lambda: |-
if (id(sensor_wifi_signal).state) {
if (id(sensor_wifi_signal).state <= -100 ) {
return 0;
} else if (id(sensor_wifi_signal).state >= -50) {
return 100;
} else {
return 2 * (id(sensor_wifi_signal).state + 100);
}
} else {
return NAN;
}
- platform: wifi_signal
id: sensor_wifi_signal
name: "${name} Wi-Fi Signal"
update_interval: 300s
on_value:
- component.update: sensor_wifi_signal_percentage
text_sensor:
- platform: wifi_info
ip_address:
name: "${name} IP Address"
id: ip_address
ssid:
name: "${name} Connected SSID"
id: ssid
bssid:
name: "${name} Connected BSSID"
id: bssid
- platform: version
id: text_sensor_version
name: "${name} ESPHome Version"