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:
- An ESP32.
- A WaveShare e-Paper module. Any module supported by GxEPD2 will work.
- Connect display to MCU. See Hardware Setup below for more information.
- Flash your MCU.
- Use a pre-compiled binary from the releases page. Make sure to select the file starting with
INITIALIZER_
. You can use esptool or the ESP32 flash tool. Example command:esptool.py --chip esp32 --baud 460800 write_flash 0x1000 INITIALIZER_epaper_templates_esp32-v2.3.0.bin
- With PlatformIO: for example
pio run -e esp32 -t upload
. You will need to have nodejs installed in order to buidl the web assets.
- Use a pre-compiled binary from the releases page. Make sure to select the file starting with
- Setup WiFi. A setup AP will appear named
epaper_XXXXXX
. The default password is waveshare. - Visit the Web UI to configure further. If you used custom pins, make sure to configure those.
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.
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.
e-paper templates can function in deep sleep mode. When configured, the system will continuously:
- Wake from sleep
- Check if a configurable GPIO pin is set. If it is, stays awake until next reboot
- Otherwise, stay awake for a configurable period to receive updates and refresh the screen.
- 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 outside_temperature
variable). They can be updated via the REST API or MQTT.
- The
timestamp
variable contains the current unix timestamp. You can use thetime
formatter (more on formatters below) to coerce it into the format you want. Time is synchronized using NTP. wifi_state
will be set toconnected
ordisconnected
.mqtt_state
will be set todisconnected
orconnected
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 outside_temperature
corresponds to a thermometer reading, its value might contain more precision than you care about (e.g., 72.013045
). Here, you could use the round
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 1
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 /api/v1/variables
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:
You can alternatively use the /api/v1/settings
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 :variable_name
is important!
After this is done, you can then publish messages to, for example template-displays/display1/my_cool_variable
to update the value of the variable my_cool_variable
:
mosquitto_pub -h my-mqtt-broker -u user -P hunter2 -t 'template-displays/display1/my_cool_variable' -m "variable_value"
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.
The UI includes a full-featured template editor:
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.
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.
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:
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).
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
5px
in the appropriate direction. Hold down shift while doing so to nudge by1px
.
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 5px in the appropriate direction. Hold down shift while doing so to nudge by 1px . |
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.
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 w
or h
because text doesn't have those fields, but you will see x
and y
.
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.
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.
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 .bin
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:
/api/v1/variables
- GET, PUT./api/v1/templates
- GET, POST./api/v1/templates/:template_name
- GET, DELETE, PUT./api/v1/bitmaps
- GET, POST./api/v1/bitmaps/:bitmap_name
- GET, DELETE./api/v1/settings
- GET, PUT./api/v1/system
- GET, POST./api/v1/resolve_variables
- GET. (For debugging)/api/v1/screens
- GET. (For debugging)/api/v1/about
- GET./firmware
- POST./
- 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 withnvm
.
Compile the project from source using PlatformIO:
platformio run -e esp32 --target buildprog
To iterate on the web assets locally, update the API_SERVER_ADDRESS
constant in ./web/.neutrinorc.js
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 localhost:5000
and open a browser window.