Need help with epaper_templates?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

190 Stars 19 Forks MIT License 204 Commits 17 Opened issues


Template-oriented driver for e-paper displays

Services available


Need anything else?

Contributors list

# 133,298
140 commits
# 592,429
10 commits

e-Paper Templates Build Status release License

Template-oriented driver for e-paper displays using Arduino. Define a layout with a JSON template, and update the display by changing variables via a REST API or MQTT.



The examples directory has a few sample templates. Here are a few:

Alarm clock

Weather Dashboard



  1. An ESP32.
  2. A WaveShare e-Paper module. Any module supported by GxEPD2 will work.


  1. Connect display to MCU. See Hardware Setup below for more information.
  2. Flash your MCU.
    1. Use a pre-compiled binary from the releases page. Make sure to select the file starting with
      . You can use esptool or the ESP32 flash tool. Example command: --chip esp32 --baud 460800 write_flash 0x1000 INITIALIZER_epaper_templates_esp32-v2.3.0.bin
    2. With PlatformIO: for example
      pio run -e esp32 -t upload
      . You will need to have nodejs installed in order to buidl the web assets.
  3. Setup WiFi. A setup AP will appear named
    . The default password is waveshare.
  4. Visit the Web UI to configure further. If you used custom pins, make sure to configure those.

Hardware Setup

Waveshare SPI modules have six total data pins that needs to be mapped onto your ESP32. There are 3x SPI pins and 3x configurable non-SPI pins you'll need to connect:

|Pin Name|Description|Default pin| |-|-|-| |DIN|SPI MOSI|GPIO 13 (HSPI MOSI)| |CLK|SPI clock|GPIO 14 (HSPI CLK)| |CS|SPI chip select|GPIO 15 (HSPI SS) |DC|Data/Command control pin (configurable)|GPIO 17| |RST|External reset|GPIO 16| |BUSY|Busy state output pin|GPIO 7|

If you wish to use different data (non-SPI) pins, those are all configurable in the UI.

Custom SPI bus

The ESP32 has two available SPI busses. The default is HSPI, but you can select VSPI in the settings page. Some driver boards like the Waveshare ESP32 Driver use custom SPI pins.

In the Hardware tab of the settings page, you can select one of the two free SPI busses on the ESP32. (HSPI and VSPI)

| | VSPI | HSPI (default) | Waveshare Custom | |-----------|------|----------------|-| | DI (MOSI) | 19 | 12 |14| | CLK | 18 | 14 |13| | CS (SS) | 5 | 15 |15|

Ensure that you do not select pins that conflict with the your SPI Bus/Deep Sleep configurations.

Deep Sleep

e-paper templates can function in deep sleep mode. When configured, the system will continuously:

  1. Wake from sleep
  2. Check if a configurable GPIO pin is set. If it is, stays awake until next reboot
  3. Otherwise, stay awake for a configurable period to receive updates and refresh the screen.
  4. Put both the ESP32 and the e-paper display into deep sleep mode.

This is useful if trying to conserve power. Deep sleep mode can be configured in the "Power" tab within the web UI.


This project aims to strike a particular balance of flexibility and ease-of-use. In order to understand how to make use of it, let's briefly discuss some primitives:


Variables are named values that power dynamic portions of your display (for example, you might have an

variable). They can be updated via the REST API or MQTT.

Special Variables

  • The
    variable contains the current unix timestamp. You can use the
    formatter (more on formatters below) to coerce it into the format you want. Time is synchronized using NTP.
  • wifi_state
    will be set to
  • mqtt_state
    will be set to
    when MQTT is configured.


A region defines a displayable unit. It can be text, an image, or various types of shapes.


Templates define the layout of your display, and consists of an arbitrary number of regions. Templates are made dynamic by binding variables to regions. You can, for example, define a text region that updates with a variable.

Templates are just JSON files (schema is available here). While you can generate these by hand, it's much easier to use the bundled web editor.


Formatters allow you to process the value of a variable within a region. For example, if the variable

corresponds to a thermometer reading, its value might contain more precision than you care about (e.g.,
). Here, you could use the
formatter to trim off excess digits.

You can either define a formatter inline with a variable, or you can create a reusable formatter and attach a reference to it from a variable (this is useful when you have many regions that need to use the same formatter).


Bitmaps are displayable images in a very raw format. Each pixel is represented as a bit in the file; rows ordered left-to-right, columns top-to-bottom. A

means the bit should be on (i.e., the pixel is black).

The bundled web UI comes with a tool to convert any browser-displayable image to this format, as well as a pixel editor to create your own or tweak ones you've already uploaded.


With the single exception of the timestamp, this variable updates are entirely push-based. In order to make a dynamic display, you'll need to push variable updates using one of the following mechanisms:


The RESTful

route allows you to update the variables document like so:
$ curl -v -X PUT -H'Content-Type: application/json' -d '{"variable_name":"variable_value"}' http://epaper-display/api/v1/variables

Any regions bound to updated variables are immediately updated.


MQTT works similarly, but requires a bit more setup. The easiest way to get started is by using the UI:

MQTT Setup

You can alternatively use the

REST route:
$ curl -v -X PUT -H'Content-Type: application/json' -d '{
  "mqtt_server": "my-mqtt-broker",
  "mqtt_username": "user",
  "mqtt_password": "hunter2",
  "mqtt_variables_topic_pattern": "template-displays/my_display/:variable_name"
}' http://epaper-display/api/v1/settings

Note here that the

is important!

After this is done, you can then publish messages to, for example

to update the value of the variable
mosquitto_pub -h my-mqtt-broker -u user -P hunter2 -t 'template-displays/display1/my_cool_variable' -m "variable_value"

Web UI

This project features a powerful, fully embedded Web UI. You can configure stuff, visually edit or tweak templates, upload or edit bitmaps, or change variables.

While things are generally pretty viewable on mobile, the heftier pages like the template and bitmap editors don't work well. This is mostly due to my ineptitude in handling mobile browser events. Happy to collaborate on a PR for anyone wanting to fix this!

The sections below go into a bit more detail on each of the pages.

Template Editor

The UI includes a full-featured template editor:

Editor Overview

There's a lot going on here, but hopefully most of the useful features are either discoverable or intuitive. The important pieces are briefly detailed below.

Canvas preview

The white square in the middle of the screen is a computed preview of your template. It automatically resolves variable values from the server so you should be see a pretty faithful model of what the screen will really look like.

Adding regions

To add a new region of a particular type, click the "+" icon next to the corresponding section. You will then be prompted to click on a location within the canvas indicating where you'd like to place the newly added region. After doing so, you'll see a form appear allowing you to edit all of the fields relevant to the type of region you've added:

New Region Configuration

To bind a region to a variable, change its Value > Type to "variable" and type in the name of the variable you'd like to bind it to (the field should autocomplete).

Selecting and moving existing regions

The canvas preview features intuitive selection and movement functionality:

  • Click a region to select it, drag a selected region to move it around
  • Hold down Ctrl (or ⌘ on OS X) to select multiple regions
  • Click and drag to select many regions at once
  • Use arrow keys to nudge the location of a selection by
    in the appropriate direction. Hold down shift while doing so to nudge by

Keyboard Shortcuts

| Shortcut | Action | Description |---|---|---| |Ctrl+S
⌘+S|Save|Saves template. If template is active, refreshes the screen.| |Ctrl+Z
⌘+Z|Undo|Undoes the last action.| |Ctrl+Shift+Z
⌘+Shift+Z|Redo|Redoes the last action.| |Ctrl+C
⌘+C|Copy|Copies the selected regions to the clipboard.| |Ctrl+V
⌘+V|Paste|Pastes a previously copied selection from the clipboard onto the canvas.| |Arrow Keys|Move|Nudge the location of a selection by

in the appropriate direction. Hold down shift while doing so to nudge by
. |Backspace
Delete|Delete|Deletes currently selected regions|


The visual editor features a sidebar which lists all of the regions in your template:

You can select regions in this list by clicking on them. Standard selection conventions apply: holding Ctrl (⌘ on OS X) selects multiple items. Holding down Shift selects a range.

You can also delete regions by clicking on the trash can icon.

Region fields editor

When you have one or more regions selected, the fields editor becomes interesting. Access it by clicking on the "Editor" tab on the sidebar.

This does something slightly fancy: it shows only fields that the selected regions have in common. For example -- if you've got a text region and a bitmap region selected, you won't see

because text doesn't have those fields, but you will see

Fields where all of the selected regions have the same value show that value. When there's any variation, the field is blank.

Changing any field updates the value for all selected regions.

The "JSON" sub-tab shows and allows you to edit a more raw form of the same information:


This section is where you can configure pre-defined formatters:

Formatters defined here can be attached to any variable region. This allows you to define a formatter once and use it many times.

Raw mode

If you click on the "Raw" tab, you'll see the unadulterated JSON template. Here, you can paste in a template from somewhere else, or free-hand edit it if that tickles your fancy.


This is a rough interface to edit, add, or delete any variables registered with the system.


This is where you can upload, create, or edit bitmaps to be used in your templates!


This shows all of the bitmaps that you've previously uploaded. Click on a bitmap to edit it.


This allows you to make pixel-level changes to your bitmap. There are a two crude and familiar editor tools: a pencil and a fill bucket. Select your desired color by clicking on the appropriate button to the right.

Importing images

Click on the totally-intuitive-and-definitely-not-cryptic folder icon to open an existing image file on your computer. Because it must be mapped to a black/white bitfield, there is a sensitivity slider. This changes the threshold at which we should consider a remapped pixel to be "on" vs. "off."

Note that when you're opening a

file (an already processed bitmap), you'll have a different view. Because the raw format does not include dimension data (we only know the number of pixels, and don't have the aspect ratio), you'll see text boxes allowing you to select the appropriate values.


You can resize a bitmap by clicking on the totally-intuitive-and-definitely-not-cryptic "expand" icon (3rd from the left). This will bring up some text boxes that allow you to enter the desired dimensions. Click on the checkmark when you're done.


You can download a copy of the image by clicking on the "Download" icon (1st icon under "File" section).


A recent update (v2.4.0) brought a way to bring very simple coloring to bitmaps. The 2 color limitation still applies, but you can change the "on" and "off" pixel colors to any color your display supports.


The following RESTful routes are available:

  1. /api/v1/variables
    - GET, PUT.
  2. /api/v1/templates
    - GET, POST.
  3. /api/v1/templates/:template_name
  4. /api/v1/bitmaps
    - GET, POST.
  5. /api/v1/bitmaps/:bitmap_name
    - GET, DELETE.
  6. /api/v1/settings
    - GET, PUT.
  7. /api/v1/system
    - GET, POST.
  8. /api/v1/resolve_variables
    - GET. (For debugging)
  9. /api/v1/screens
    - GET. (For debugging)
  10. /api/v1/about
    - GET.
  11. /firmware
    - POST.
  12. /
    - GET.


A complete develop environment requires the following:

  • platformio
    to build the Arduino C++ sources. Installable via pip.
  • nodejs
    to build the web sources. Install with

Compiling from source

Compile the project from source using PlatformIO:

platformio run -e esp32 --target buildprog

Local webserver

To iterate on the web assets locally, update the

constant in
to point the address of an ESP32 running epaper_templates, and start a local webserver with this command:
cd ./web && npm install && npm run start

This will start a local webserver on

and open a browser window.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.