E-paper and ESP32 signs
A battery-powered sign with no browser on it. The board wakes, asks the server for a picture, draws it, and goes back to sleep — the rendering happens on the server, so the hardware can be a microcontroller and a coin cell.
Why this is different
Every other player on this site is a web page: the device runs a browser, fetches your content and renders it. A microcontroller cannot do that, and a battery-powered panel should not want to — a browser is the single most expensive thing you could ask a coin cell to run.
So the work moves to the server. ScreenTinker resolves which playlist item is due, resizes it to your panel, dithers it to the colours the panel actually has, packs it into the byte layout the controller expects, and sends that. The board’s entire job is: wake, one HTTP GET, push bytes to the panel, sleep.
What the device does
- Wake from deep sleep.
- GET the render endpoint with its device token and the ETag of the frame it already has.
- Receive a packed frame — or 304 Not Modified, and skip the refresh entirely.
- Read the expiry header and deep sleep for exactly that long.
The 304 is the part that matters for battery life. An e-paper refresh is the most power-hungry thing the device does, and most wakes find nothing has changed — so most wakes cost one small HTTP round trip and nothing else.
There is no local state to keep. Playlist timing and the cursor live on the server, so a board that loses power and reboots asks for the current frame and is immediately correct.
Panels it already knows
Give a preset name and the rest is filled in. Or set width, height, rotation, colour depth, dithering and output format yourself — the presets are a convenience, not a whitelist.
| Preset | Panel | Output |
|---|---|---|
seeed-reterminal-sticky | Seeed reTerminal Sticky, 800×480 B/W | 1-bit, Floyd–Steinberg |
waveshare-7.5in-v2 | Waveshare 7.5″, 800×480 | 1-bit, Floyd–Steinberg |
waveshare-4.2in-v2 | Waveshare 4.2″, 400×300 | 1-bit, Floyd–Steinberg |
waveshare-2.9in-v2 | Waveshare 2.9″, 296×128 | 1-bit, Floyd–Steinberg |
waveshare-1.54in-v2 | Waveshare 1.54″, 200×200 | 1-bit, Floyd–Steinberg |
waveshare-5.65in-acep | 7-colour ACeP, 600×448 | 24-bit RGB, PNG |
generic-320x240-rgb565 | ILI9341-class TFT | 16-bit RGB565, raw |
generic-480x320-rgb565 | Larger TFT | 16-bit RGB565, raw |
generic-128x64-1bit | SSD1306 OLED | 1-bit, Atkinson |
generic-128x32-1bit | Small SSD1306 OLED | 1-bit, Atkinson |
Two dithering algorithms, and they are not interchangeable. Floyd–Steinberg diffuses the full error and suits a large e-paper panel showing a photograph. Atkinson diffuses three quarters of it, which keeps small OLED text legible instead of smearing it into grey — which is why the OLED presets use it and the e-paper ones do not.
What you can actually put on one
The same content library as every other screen, rendered down: images, and a layout renderer for multi-zone frames. A 296×128 panel is not going to show a video, and nothing pretends otherwise — these are for the signs that carry a room name, a price, a status, a QR code, a meeting.
Honest limits
- No video, no audio, no widgets that animate. A frame is a picture.
- Refresh is measured in seconds to minutes, not frames per second. E-paper physically cannot do better, and a battery does not want it to.
- The device token is permanent and does not rotate. It lives in the board’s flash and stays valid until you delete the display or re-pair it — treat a board you are throwing away as a credential you should revoke.
- You write the firmware. A reference ESP32 implementation ships in the repository documentation; it is a starting point, not a product.
None of these panels are on the certified hardware list, which means exactly what it says: the renderer is tested, and we have not sat a given panel on a bench for a month. Tell us how yours goes.