Close
0%
0%

ESP32 WiFi E-Ink Photo Frame

Arduino Code for Waveshare ESP32-S3 Photo Painter that allows for retrieving JPEGs and BMPs over WiFi from nginx webserver and more!

Similar projects worth following
Custom firmware for the Waveshare ESP32-S3-PhotoPainter, a battery-powered e-ink photo frame featuring an ESP32-S3 and a 7.3" Spectra ACeP 6-colour display (800×480). This project replaces the stock firmware with an Arduino-based sketch that fetches random images from an nginx server over WiFi, resizes and Floyd–Steinberg dithers them to the 6-colour palette, and displays them on the panel. It also reports temperature, humidity, and battery voltage to Home Assistant via MQTT.

All code and setup instructions are available in the GitHub repository linked on the left. There’s also a YouTube overview video that walks through the project.

I recently ordered one of Waveshare’s E-Ink Photo Frames. The stock firmware allows images to be displayed from the SD card, but the major drawback is that photos must first be converted into a specific format using their supplied scripts.

My goal was to write custom firmware that would allow images to be updated simply by dropping them into a folder on a network drive.

For a few years I’ve had an Odroid HC2 running Ubuntu with a 6TB 3.5” drive shared across my home network via Samba. Initially, I considered having the ESP32 connect directly over SMB, SSH, or SFTP, but the development overhead for those protocols was more than I wanted for this project. The simplest and most reliable solution turned out to be hosting the image folder with NGINX as a basic HTTP server. The ESP32 can easily act as an HTTP client and download images from that directory onto its SD card.

Next came image rendering. I didn’t want to pre-process or resize images on the PC before placing them in the folder. Fortunately, Larry Bank’s JPEGDEC library makes decoding JPEG images on the ESP32 straightforward. BMP files are also easy to handle. I experimented with PNGDEC, but in my implementation I ran into RAM limitations when decoding PNG files. Since JPEG will be the primary format used, converting the occasional PNG to BMP is an acceptable compromise.

Once the ESP32 downloads an image into a temporary file on the SD card, it decodes and resizes it to match the E-Ink display resolution. Images are cover-cropped to fill the screen appropriately without requiring manual resizing beforehand.

The final stage of the display pipeline is dithering. Unlike LCD, LED, or OLED panels, this E-Ink display cannot blend colours at the pixel level. Each pixel can only display one of six discrete colours. Dithering creates the illusion of a wider colour range by distributing neighbouring pixels of different colours in carefully calculated patterns. This implementation uses the Floyd–Steinberg dithering algorithm.

As an additional feature, I integrated the frame with Home Assistant as a temperature and humidity sensor. The Waveshare board includes an onboard temperature and humidity sensor, so it made sense to expose that data via MQTT. The firmware publishes configuration data to the Home Assistant auto-discovery topic on startup, meaning no manual configuration is required.

Currently, the device wakes from deep sleep every 30 minutes to select a random image from the hosted folder and update the display. It also wakes every five minutes to record and publish temperature and humidity readings.

The GitHub repository includes instructions for flashing the board as well as an example NGINX configuration file for /etc/nginx/sites-available. Once configured, adding new images is as simple as copying JPEG or BMP files into the hosted folder. No resizing or pre-processing is required.

  • 1 × ESP32-S3-PhotoPainter 7.3inch E6 Full Color E-paper Display With Solid Wood Photo Frame, Ultra-long Standby, 800 × 480 Resolution, Battery Optional

  • Overview

    william.rigby02/27/2026 at 02:30 0 comments

    I recently ordered one of these E-Ink Photo Frames from Waveshare. The stock code allows it to display images from the SD card, however the drawbacks are you have to first convert the photo to the correct format using their supplied software scripts.


    My goal was to write some firmware that allows you to update the photos by only having to drop images in a folder on a network drive. I've had an Odroid HC2 running Ubuntu for a few years. It has a 6TB 3.5" drive and shares this drive on my home network using Samba. However between having the ESP32 connect using Samba or SSH or SFTP, the coding effort was too much. So the least effort method ended up being  setting up nginx to host a folder as a HTTP server. The ESP32 can easily act as a HTTP client and download images from that folder onto its SD card.

    Next was displaying the images, I didn't want to have to have to do any processing of the images if I could. Luckily Larry Bank has written a really great JPEG decoder library: JPEGDEC. This makes load JPEGs on the ESP32 easy, bitmap files (BMP) files were also easy, but I found using Larry's PNGDEC library, I was running out of RAM with my implementation, and as I intend to display JPEGs normally, saving a PNG as a BMP isn't that much effort as I won't do it very often. Once its downloaded the image into a temporary file on the SD card, it then decodes and resizes them to fit the E-Ink display.



    The last part of the image display pipeline is dithering. E-Ink display pixels can't colour mix like with LCD, LED and OLED displays. The pixel can only be one of the six colours. So to dithering is a way to create the illusion of other colours by patterning different colour pixels that are close together. I've used Floyd-Steinberg dithering algorithm.

    The last part of this code was to add an extra function. I recently setup home assistant on a raspberry pi. Since this Waveshare board has a temperature and humidity sensor on board, why not set it up as a temperature and humidity sensor for Home Assistant using MQTT. It will also publish on start up the correct data to the home assistant auto discovery topic so that it doesn't require any additional configuration.

    The current code has the device setup to come out of deep sleep ever 30 minutes, pick a random picture from the folder and display it, and to come out of deep sleep every five minutes to log the temperature and humidity.

    It the git repository is the setup instructions for flashing the board, and a nginx config file for your sites-available folder in /etc/nginx. Once you've pointed it at that folder, adding new images is as easy as adding JPEG and BMP files to that folder, you don't need to resize them!

View project log

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates