185 lines
8.2 KiB
Markdown
185 lines
8.2 KiB
Markdown
---
|
|
title: "Making an Email-Powered E-Paper Picture Frame"
|
|
date: 2021-05-12T00:00:00+00:00
|
|
draft: false
|
|
canonical_url: https://www.viget.com/articles/making-an-email-powered-e-paper-picture-frame/
|
|
featured: true
|
|
---
|
|
|
|
Over the winter, inspired by this [digital photo
|
|
frame](http://toolsandtoys.net/aura-mason-smart-digital-picture-frame/)
|
|
that uses email to add new photos, I built and programmed a trio of
|
|
e-paper picture frames for my family, and I thought it'd be cool to
|
|
walk through the process in case someone out there wants to try
|
|
something similar.
|
|
|
|

|
|
|
|
In short, it's a Raspberry Pi Zero connected to a roughly 5-by-7-inch
|
|
e-paper screen, running some software I wrote in Go and living inside a
|
|
frame I put together. This project consists of four main parts:
|
|
|
|
1. The email-to-S3 gateway, [described in detail in a previous
|
|
post](/elsewhere/email-photos-to-an-s3-bucket-with-aws-lambda-with-cropping-in-ruby/);
|
|
2. The software to display the photos on the screen;
|
|
3. Miscellaneous Raspberry Pi configuration; and
|
|
4. The physical frame itself.
|
|
|
|
As for materials, you'll need the following:
|
|
|
|
- [A Raspberry Pi Zero with
|
|
headers](https://www.waveshare.com/raspberry-pi-zero-wh.htm)
|
|
- [An e-paper
|
|
display](https://www.waveshare.com/7.5inch-hd-e-paper-hat.htm)
|
|
- A micro SD card (and some way to write to it)
|
|
- Some 1x4 lumber (I used oak)
|
|
- [4x metal standoffs](https://www.amazon.com/gp/product/B00TX464XQ)
|
|
- [A 6x8 piece of
|
|
acrylic](https://www.amazon.com/gp/product/B07J4WX7BH)
|
|
- Some wood glue to attach the boards, and some wood screws to attach
|
|
the standoffs
|
|
|
|
I'll get more into the woodworking tools down below.
|
|
|
|
## The Email-to-S3 Gateway
|
|
|
|
Like I said, [I've already documented this part pretty
|
|
thoroughly](/elsewhere/email-photos-to-an-s3-bucket-with-aws-lambda-with-cropping-in-ruby/),
|
|
but in short, we use an array of AWS services to set up an email address
|
|
that fires off a Lambda function when it receives an email. The function
|
|
extracts the attachments from the email, crops them a couple of ways
|
|
(one for display on a webpage, the other for display on the screen), and
|
|
uploads the results into an S3 bucket.
|
|
|
|

|
|
|
|
## The Software
|
|
|
|
The next task was to write the code that runs on the Pi that can update
|
|
the display periodically. I also thought it'd be cool if it could
|
|
expose a simple web interface on the local network to let my family
|
|
members browse the photos and display them on the frame. When selecting
|
|
a language, I could have gone with either Ruby or Python, the former
|
|
since that's what I'm most familiar with, the latter because that's
|
|
what [the code provided by
|
|
Waveshare](https://github.com/waveshare/e-Paper/tree/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd),
|
|
the manufacturer, is written in.
|
|
|
|
But I chose neither of those options, reader, opting instead for Go. Why
|
|
Go, you ask?
|
|
|
|
- **I wanted something robust.** Ideally, this code will run on these
|
|
devices for years with no downtime. If something does go wrong, I
|
|
won't have any way to debug the problems remotely, instead having
|
|
to wait until the next time I'm on the same wifi network with the
|
|
failing device. Go's explicit error checking was appealing in this
|
|
regard.
|
|
|
|
- **I wanted deployment to be simple.** I didn't have any appetite
|
|
for all the configuration required to get a Python or Ruby app
|
|
running on the Pi. The fact that I could compile my code into a
|
|
single binary that I could `scp` onto the device and manage with
|
|
`systemd` was compelling.
|
|
|
|
- **I wanted a web UI**, but it wasn't the main focus. With Go, I
|
|
could just import the built-in `net/http` to add simple web
|
|
functionality.
|
|
|
|
To interface with the screen, I started with [this super awesome GitHub
|
|
project](https://github.com/gandaldf/rpi). Out of the box, it didn't
|
|
work with my screen, I *think* because Waveshare offers a bunch of
|
|
different screens and the specific instructions differ between them. So
|
|
I forked it and found the specific Waveshare Python code that worked
|
|
with my screen ([this
|
|
one](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd7in5_HD.py),
|
|
I believe), and then it was just a matter of updating the Go code to
|
|
match the Python, which was tricky because I don't know very much about
|
|
low-level electronics programming, but also pretty easy since the Go and
|
|
Python are set up in pretty much the same way.
|
|
|
|
[Here's my
|
|
fork](https://github.com/dce/rpi/blob/master/epd7in5/epd7in5.go) --- if
|
|
you go with the exact screen I linked to above, it *should* work, but
|
|
there's a chance you end up having to do what I did and customizing it
|
|
to match Waveshare's official source.
|
|
|
|
Writing the main Go program was a lot of fun. I managed to do it all ---
|
|
interfacing with the screen, displaying a random photo, and serving up a
|
|
web interface --- in one (IMO) pretty clean file. [Here's the
|
|
source](https://github.com/dce/e-paper-frame), and I've added some
|
|
scripts to hopefully making hacking on it a bit easier.
|
|
|
|
## Configuring the Raspberry Pi
|
|
|
|
Setting up the Pi was pretty straightforward, though not without a lot
|
|
of trial-and-error the first time through:
|
|
|
|
1. Flash Raspberry Pi OS onto the SD card
|
|
2. [Configure your wifi
|
|
information](https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md)
|
|
and [enable
|
|
SSH](https://howchoo.com/g/ote0ywmzywj/how-to-enable-ssh-on-raspbian-without-a-screen#create-an-empty-file-called-ssh)
|
|
3. Plug it in --- if it doesn't join your network, you probably messed
|
|
something up in step 2
|
|
4. SSH in (`ssh pi@<192.168.XXX.XXX>`, password `raspberry`) and put
|
|
your public key in `.ssh`
|
|
5. Go ahead and run a full system update
|
|
(`sudo apt update && sudo apt upgrade -y`)
|
|
6. Install the AWS CLI and NTP (`sudo apt-get install awscli ntp`)
|
|
7. You'll need some AWS credentials --- if you already have a local
|
|
`~/.aws/config`, just put that file in the same place on the Pi; if
|
|
not, run `aws configure`
|
|
8. Enable SPI --- run `sudo raspi-config`, then select "Interface
|
|
Options", "SPI"
|
|
9. Upload `frame-server-arm` from your local machine using `scp`; I
|
|
have it living in `/home/pi/frame`
|
|
10. Copy the [cron
|
|
script](https://github.com/dce/e-paper-frame/blob/main/etc/random-photo)
|
|
into `/etc/cron.hourly` and make sure it has execute permissions
|
|
(then give it a run to pull in the initial photos)
|
|
11. Add a line into the root user's crontab to run the script on
|
|
startup: `@reboot /etc/cron.hourly/random-photo`
|
|
12. Copy the [`systemd`
|
|
service](https://github.com/dce/e-paper-frame/blob/main/etc/frame-server.service)
|
|
into `/etc/systemd/system`, then enable and start it
|
|
|
|
And that should be it. The photo gallery should be accessible at a local
|
|
IP and the photo should update hourly (though not ON the hour as that's
|
|
not how `cron.hourly` works for some reason).
|
|
|
|

|
|
|
|
## Building the Frame
|
|
|
|
This part is strictly optional, and there are lots of ways you can
|
|
display your frame. I took (a lot of) inspiration from this ["DIY
|
|
Modern Wood and Acrylic Photo
|
|
Stand"](https://evanandkatelyn.com/2017/10/modern-wood-and-acrylic-photo-stand/)
|
|
with just a few modifications:
|
|
|
|
- I used just one sheet of acrylic instead of two
|
|
- I used a couple small pieces of wood with a shallow groove to create
|
|
a shelf for the screen to rest on
|
|
- I used a drill press to make a 3/4" hole in the middle of the board
|
|
to run the cable through
|
|
- I didn't bother with the pocket holes --- wood glue is plenty
|
|
strong
|
|
|
|
The tools I used were: a table saw, a miter saw, a drill press, a
|
|
regular cordless drill (**do not** try to make the larger holes in the
|
|
acrylic with a drill press omfg), an orbital sander, and some 12"
|
|
clamps. I'd recommend starting with some cheap pine before using nicer
|
|
wood --- you'll probably screw something up the first time if you're
|
|
anything like me.
|
|
|
|
---
|
|
|
|
This project was a lot of fun. Each part was pretty simple --- I'm
|
|
certainly no expert at AWS, Go programming, or woodworking --- but
|
|
combined together they make something pretty special. Thanks for
|
|
reading, and I hope this inspires you to make something for your mom or
|
|
someone else special to you.
|
|
|
|
*Raspberry Pi illustration courtesy of [Jonathan
|
|
Rutheiser](https://commons.wikimedia.org/wiki/File:Raspberry_Pi_Vector_Illustration.svg)*
|