An ePaper moon calendar powered by Raspberry Pi.
Based on Moon-Pi.
- Raspberry Pi Zero 2 W (or Raspberry Pi Zero W, though I found the 2 to be more reliable for this application)
- SD card (4GB or more)
- Waveshare 7.3in 7-Color e-Paper Display HAT, 800 x 480 pixels (can also be found on Amazon)
- Pisugar 2 battery power supply with RTC
- 5x7 Black Shadow Box
- 5x7 Pre-Cut Mat Boards with 4x6 inner, or cut your own
- micro-USB to USB-A cable
- (optional) Raspberry Pi heatsinks
- soldering iron, screwdriver, screws, standoffs, tape, a drill or Dremel tool, etc.
-
Burn an image onto an SD card, such as Raspberry Pi OS Lite 32-bit (no need for "full" version or 64-bit). You should configure the image with "moon" as the username, WiFi credentials, a hostname (like moonpi), SSH access enabled, etc.
-
Connect the PiSugar power supply to the Raspberry Pi according to the official instructions.
-
Plug the SD card into the Pi, fire it up, and run some installs:
sudo apt update && sudo apt upgrade sudo apt install python3-venv git sudo apt install libopenjp2-7 # for Python Pillow library curl https://pyenv.run | bash # follow instructions for enabling pyenv in .bashrc # PiSugar server (make sure to select the right PiSugar model -- the PiSugar 2 # (2-LED) if you bought it from the link above). Hint: look at the number of # LEDs next to the PiSugar charging port. # If you mess up and choose the wrong one, you can run: # sudo dpkg-reconfigure pisugar-server # PiSugar will ask you for a password for the web UI -- be aware that it # stores this in plain text on your system. curl http://cdn.pisugar.com/release/pisugar-power-manager.sh | sudo bash # optional development tools sudo apt install zsh neovim sudo apt install i2c-tools sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
-
Setup PiSugar RTC and auto-boot.
- Login to the PiSugar power manager server
- Sync the RTC/system clock by going into the sync settings and sync "Web > Pi & RTC". This should synchronize both the RPi system clock and the PiSugar's RTC with an internet NTP server
- Enable autoboot by changing "Scheduled Wake Up" to "enabled" and choose a suitable time, for example 1:00AM
- Note: you can also manually edit
/etc/pisugar-server/config.json
,/etc/default/pisugar-server
, and/etc/default/pisugar-poweroff
-
Enable the SPI interface (used by the e-Paper display) and the I2C interface (used by PiSugar):
-
sudo raspi-config
-
Choose Interfacing Options -> SPI -> Yes Enable SPI interface
-
Choose Interfacing Options -> I2C -> Yes
-
Reboot:
sudo shutdown -r now
-
cat /boot/config.txt | grep dtparam
, and verify you seedtparam=spi=on
there -
To make sure SPI is not occupied, it is recommended to close other drivers' coverage. You can use
ls /dev/spi\*
to check whether SPI is occupied. If the terminal outputs/dev/spidev0.1
and/dev/spidev0.1
, SPI is not occupied.
-
-
Clone the repo
cd ~
git clone https://github.com/de-mux/Moon-Pi
This should put the Moon-Pi directory under your home directory.
-
Setup Python.
-
You may be able to just use system version. Make sure it's a semi-recent version of Python 3:
$ python --version Python 3.9.2
If not, install a version 3 with:
pyenv install 3
-
Create a virtual environment:
pyenv virtualenv system moonpi # if your system version is recent enough # ... or ... pyenv virtualenv 3 moonpi # if you had to install version 3
-
Activate that virtual environment!
$ pyenv activate moonpi (moonpi) $
-
Install requirements
pip install -r requirements.txt
-
Download the Luminari font into the Moon-Pi/fonts directory. If you decide to go
with different fonts, you will need to update the FONTS
constant in the
moon_pi.py
script to point to the right ones. The directory tree should look
like:
├── README.md
├── fonts
│ ├── Luminari-Regular.ttf
│ ├── SourceSans3-Semibold.ttf
│ └── copy-fonts-here.txt
...
sudo systemctl disable hciuart
sudo systemctl disable bluealsa
sudo systemctl disable bluetooth
sudo systemctl disable man-db.timer
sudo systemctl disable apt-daily.service
sudo systemctl disable apt-daily.timer
sudo systemctl disable apt-daily-upgrade.timer
sudo systemctl disable apt-daily-upgrade.service
Edit /boot/config.txt
and add the following lines:
# Disable Bluetooth
dtoverlay=disable-bt
cd ~/Moon-Pi
sudo cp moonpi.service /etc/systemd/system
sudo systemctl enable moonpi
Note that the sudo
before the systemctl
command is important, because
although the script is run as the user, it needs sudo to issue the shutdown
command.
Now the Moon Pi script will run once at startup, and then the system will shut down(until woken up again the next day by the RTC).
When the Pi boots, it'll only run for about a minute before shutting itself
down. So if you realize you need to fix or tweak something, you'll need to be
sure to SSH into the Pi and run touch ~/noshutdown
before the script
completes. The script will detect the presence of ~/noshutdown
and disable
auto-shutdown. Don't forget to remove the file when you're done debugging.
Take a look at the moon-pi.py
script in this repository. Some things you may
want to change:
BIRTHDAY_MONTH
ANDBIRTHDAY_DAY
(so it says "Happy Birthday!" on the recipient's birthday)FONTS
if you want to use your own fontsWAVESHARE_DISPLAY
if you use a different one than what's used in these instructions- Note: if you change this, you may need to tweak
DISPLAY_MARGINS
,MOON_SIZE_PX
and some of the values under the methods of theImageBuilder
class
- Note: if you change this, you may need to tweak
LOCATION
based on where the recipient livesBATTERY_LOW_THRESHOLD
to display the battery low indicator at a different threshold
The moon images and background image included were obtained from NASA Dial-A-Moon, which are generally free for personal/educational use (see NASA Images and Media Guidelines). There are enough images to provide a different moon image for every day of a cycle (30 total to cover a complete ~29.5-day moon phase cycle).
Note the script will automatically downscale and convert images to the e-Paper display's color palette using the Floyd-Steinberg dithering method.
The background image used is ./images/screen-template-7in3.png
. If you change
this, you may want to convert it to the e-Paper display's color palette.
Some image manipulation programs like ImageMagick allow you to specify an arbitrary image as a "palette file", while others (like ffmpeg) require you to create a specific image format to be used as a palette file.
There is a reference palette image ./images/waveshare-7color-palette.png
for
the 7-color waveshare display.
You can also find reference files on the Waveshare website.
I found the best results were obtained by running source images through ImageMagick with the FloydSteinberg dither setting.
magick input.png -dither FloydSteinberg -remap images/waveshare-7color-palette.png output.png
(I also tried ffmpeg and Gimp with various dither settings including Floyd Steinberg, but ImageMagick seemed to yield the best results. Pillow, the Python library used in this project also has a decent conversion algorithm).
To batch convert multiple images, you can use:
mkdir converted
for f in /path/to/images/*.png; do magick $f -dither FloydSteinberg -remap images/waveshare-7color-palette.png "converted/$(basename "$f")"; done
The file comes with several quotations. You can also add your own. Each row
contains a quote, and a credit. The script will set the font size depending on
the length of the quote. Make sure your quotes aren't too long, or the text will
run off the edge of the screen! You can check the images generated by all quotes
using tests/test-quotes.py
.
This project uses the "ephem" library to determine the moon phase based on the date, allowing the project to run completely offline.
There are a total of 14 wired connections (not counting plugging the battery into the PiSugar). There are eight wires from the Raspberry Pi to the display and six wires from the Pi to the PiSugar.
Here is a pinout of the Raspberry Pi for reference.
Here's the PiSugar install guide. You'll need this to walk you through setting up the PiSugar to wake up the Pi on a schedule.
Before connecting the PiSugar to the Pi, solder the Pi header on so you can connect the e-Paper display wires in the next step. The PiSugar uses pogo pins to interface with the RPi, so they should work even when the header is populated. Alternatively, you can pull the 6 pins of the header corresponding to the PiSugar's pins prior to soldering so you can get a slightly more comfortable fit.
RPi pin | Description | PiSugar pin |
---|---|---|
2 | 5v | 2 |
3 | SDA | 3 |
4 | 5v | 4 |
5 | SCL | 5 |
6 | Gnd | 6 |
9 | Gnd | 9 |
Here's the guide to connect the display to the Pi
RPi pin | Description | e-Paper pin |
---|---|---|
11 | GPIO 17 | RST |
17 | 3.3v | VCC |
18 | GPIO 24 | BUSY |
19 | MOSI | DIN |
20 | Gnd | GND |
22 | GPIO 25 | DC |
23 | SCLK | SCLK |
24 | CE0 | CS |
cd ~/Moon-Pi
pyenv activate moonpi
python moon_pi.py
This should update the display with a moon image for the current date.
Note that running the script by itself will not power down the Pi -- this is done in the run.sh script that is run by the systemd service. This way you can test the script without worrying about the device rebooting and kicking you out every time.
Test that the systemd service will run the Moon Pi script at startup by powering the device off and on. After 30-45 seconds, the script should run, updating the display. If it didn't work, you can check the logs:
cat ~/moonpi.log # for the script log file
journalctl -u moonpi.service # for the systemd log
If you need to, you can disable auto-shutdown in the service by creating a file
in $HOME
called noshutdown
. Just remember to remove it again after you're
done debugging so the device doesn't remain on indefinitely.
To check on status of moonpi.service:
journalctl status moonpi
For system boot information, you can use journalctl:
# Show systemd logs for current boot
journalctl -b
# List all boot timestamps
journalctl --list-boots
# Show previous boot
journalctl -b -1
Align the display with the mat and tape it into place. You may need to modify the insert that comes with the shadow box a little to accomodate things like the e-Paper cable. I cut out a slot for the e-Paper cable so the insert wasn't pressing up against it, and also cut some channels for the tie-wrap fasteners that I used to mount the Raspberry Pi and PiSugar assembly.
Affix the RPi/PiSugar assembly to the shadow box insert, and check that it fits inside the shadow box. Make sure there is nothing touching the display that could damage it. You might want some padding to protect the back of the display from touching the Pi assembly.
Drill a hole in the back panel for the PiSugar charging port.
Mount the e-Paper HAT somehow (I used screws to mount it to the back of the back panel).
Connect all cables, power on the device, and you're done!
- Ideas for stats:
- Phase name: Waning Gibbous
- Moon age: 17.36 days
- Moon illumination: 87.95%
- Moon tilt: -34.731°
- Moon sign: Cancer
This project is licensed under GPL 3.0, except:
- ./fonts/SourceSans3-Semibold.ttf (SIL Open Font License 1.1)
- ./images/battery.png (Creative Commons Attribution Share Alike 4.0 International)
See LICENSE for details.