Instructions on setting up a Raspberry Pi Zero WH with a Waveshare ePaper 7.5 Inch HAT. The screen will display date, time, weather icon with high and low, and calendar entries.
- Shopping list
- Setup the PI
- Using this application
- Setup dependencies
- Set your Waveshare version
- Set your location
- Pick a Weather provider
- Pick a severe weather warning provider
- Pick a Calendar provider
- Pick a layout
- Run it
- Adding custom data
- Choosing a different language
- Choosing a different font
- Privacy Mode
- Troubleshooting
- Waveshare documentation and sample code
- Debugging locally
Waveshare 7.5 inch epaper display HAT 640x384
Raspberry Pi Zero WH (presoldered header)
microSDHC card
Optional - a picture frame. I used a 18x13cm (7x5 inch) frame which just about fits the screen.
Use the Raspberry Pi imager and install Raspberry Pi OS Lite.
Ensure that you have SSH access, or direct access, to the Raspberry Pi, and that it can connect to the Internet to download packages. In most cases you would do this via the imager's settings screen: set the username and password, enable SSH and set up WiFi access.
Turn the Pi off, then put the HAT on top of the Pi's GPIO pins.
Connect the ribbon from the epaper display to the extension. To do this you will need to lift the black latch at the back of the connector, insert the ribbon slowly, then push the latch down.
Now turn the Pi back on and SSH into it.
git clone this repository in the /home/pi directory.
cd ~
sudo apt update && sudo apt upgrade
sudo apt install git
git clone --recursive https://github.com/mendhak/waveshare-epaper-display.git
This should create a /home/pi/waveshare-epaper-display directory.
cd waveshare-epaper-display
sudo apt install gsfonts fonts-noto python3 python3-pip pigpio libopenjp2-7 python3-venv libjpeg-dev libxslt1-dev fontconfig libcairo2
python3 -m venv --system-site-packages .venv
.venv/bin/pip3 install -r requirements.txt
sudo raspi-config nonint do_spi 0 #This enables SPI
sudo reboot
Copy the example config file to config.toml, this is where all the settings will be stored.
cd waveshare-epaper-display
cp config.example.toml config.toml
Set the version of your Waveshare 7.5" e-Paper Module (newer ones are version 2, red one is 2B):
[display]
waveshare_version = "2"
Whichever weather provider you use, you'll need to provide the location and units to display in.
Edit config.toml and update the latitude and longitude under the [weather] section.
[weather]
latitude = 51.5077
longitude = -0.1278
format = "CELSIUS"
You can pick between OpenWeatherMap, Met Office, AccuWeather, Met.no, Weather.gov, VisualCrossing, and Climacell to provide temperature and weather forecasts.
In config.toml, under the same [weather] section, set the provider to the provider you want to use. For example:
[weather]
... your location details from above ...
provider = "metoffice" # metoffice, climacell, accuweather, openweathermap, metno, met_eireann, weathergov, smhi, visualcrossing
Then configure the API key in the corresponding provider section below.
Register on the OpenWeathermap website, and go to the API Keys page, that's the key you'll need.
In config.toml, add your API key:
[weather.providers.openweathermap]
api_key = "xxxxxx"
Create an account on the Met Office Weather DataHub site. Next, under subscriptions - subscribe to the 'Site Specific' product 'Global Spot'. This will get you an API key.
In config.toml, add your API key:
[weather.providers.metoffice]
api_key = "eyJ........."
Register on the AccuWeather site. Next, register a new application. I just named it Personal, marked it as Limited Trial, Internal App, Business to Consumer. Once you do this you'll get an API Key, save it.
You'll also need an AccuWeather Location Key.
Do a normal AccuWeather search for your location.
The last number in the URL is the Location Key. In the example of London, it's 328328.
In config.toml, add both keys:
[weather.providers.accuweather]
api_key = "xxxxxx"
location_key = "328328"
Met.no's Terms of Service requires you to identify yourself. The purpose is to ensure they can contact you in case you overload or abuse their servers. For this reason, you just need to set your email address in config.toml:
[weather.providers.metno]
self_identification = "you@example.com"
Note that the Met.no API provides 6 hours of forecast, rather than a full day.
Met Éireann publish their forecast data under a Creative Commons Attribution 4.0 International license (CC BY 4.0). No API key required.
In config.toml, just set the provider:
[weather]
provider = "met_eireann"
Note that a condition of use of this data is that weather alerts also be displayed, so you should configure the Met Éireann alert provider below.
Weather.gov requires you to identify your application. This can be any made up string, or an email address.
In config.toml, set your identifier:
[weather.providers.weathergov]
self_identification = "you@example.com"
Warning: YMMV. During my testing, I found the weather.gov API would start returning errors and then suddenly work again.
Register on the Climacell site, and when you do you should be given an API Key.
In config.toml, add your API key:
[weather.providers.climacell]
api_key = "xxxxxx"
Register on VisualCrossing. Under Account Details, you should be able to generate an API key. Once you have that, add it to config.toml:
[weather.providers.visualcrossing]
api_key = "XXXXXXXXXXXXXXXXXXXXXX"
SMHI requires you to identify yourself. Just set your own email in config.toml:
[weather.providers.smhi]
self_identification = "you@example.com"
This is an optional step. By doing nothing you simply won't see severe weather warnings.
In config.toml, set enabled to true, and the provider name you wish to use under [alerts]:
[alerts]
enabled = true
provider = "metoffice" # metoffice, met_eireann, weathergov
Go to the Met Office RSS Feeds page and copy the URL of the RSS feed based on your region.
In config.toml, add the feed URL:
[alerts.providers.metoffice]
feed_url = "https://www.metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/se"
Weather.gov requires you to identify your application. This can be any made up string, or an email address.
In config.toml, set your identifier:
[alerts.providers.weathergov]
self_identification = "you@example.com"
This provider will use the same latitude and longitude as specified for the weather provider.
Warning: YMMV. During my testing, I found the weather.gov API would start returning errors and then suddenly work again.
To use alerts from Met Éireann, visit https://www.met.ie/Open_Data/json/ and choose the appropriate "warning_EIXX" JSON file for your region, using each county's FIPS code. This code can be found in the table on http://www.statoids.com/uie.html, in the pre-2014 section. For example, this is the file for Dublin:
[alerts.providers.met_eireann]
feed_url = "https://www.met.ie/Open_Data/json/warning_EI07.json"
You can use Google Calendar, Outlook Calendar, ICS, or CalDAV to display events.
You can mix and match providers, and add multiple calendars of each type.
Events from all enabled calendars will be merged and sorted by date.
You will need to run an Oauth process once manually to allow this application query your Google Calendar for information.
Run:
.venv/bin/python3 utils/google_calendar_util.py
The script will prompt you to visit a URL in your browser, then it will sit there and wait. The URL will look like https://accounts.google.com/o/... and will be very long.
Follow that URL in a browser window, you'll need to log in and choose your Google account.
On the "Make sure you trust Mendhak Waveshare Epaper Display" screen, you will see it's asking for permission to read your Google Calendar.
Click continue, and then let it fail when it tries to go to a http://localhost:8080/... URL.
Copy the URL it was trying to go to (eg: http://localhost:8080/...) and in another SSH session with the Raspberry Pi, run this (remember the double quotes):
curl "http://localhost:8080/..."
On the first screen you should see the auth flow complete, and a new data/token_google.pickle file appears.
The script should now be able to run in the future without prompting required.
The script will then print out a list of your Google Calendars with names and IDs. Copy the ID of the calendar you want, then add a section to config.toml to enable it, like this:
[[calendar.providers.google]]
enabled = true
id = "xyz12345@group.calendar.google.com"
time_zone = "Europe/London" # Optional: for family calendars
To add multiple Google calendars, include additional [[calendar.providers.google]] blocks.
You can also get a calendar's ID manually by opening up Google Calendar and going to the settings for your preferred calendar. Under the 'Integrate Calendar' section you will see a Calendar ID which looks like xyz12345@group.calendar.google.com.
The setup is much simpler, just run this script which will give instructions on how to login:
.venv/bin/python3 utils/outlook_util.py
Login with the Microsoft account you want to get the calendar from, and accept the consent screen.
After a moment, the script will then display a set of Calendar IDs and some sample events from those Calendars.
Copy the ID of the calendar you want, and add it to config.toml:
[[calendar.providers.outlook]]
enabled = true
calendar_id = "AQMkAxyz..."
To add multiple Outlook calendars, include additional [[calendar.providers.outlook]] blocks.
ICS is simple but can be buggy. Get the ICS URL for a calendar, and add it to config.toml:
[[calendar.providers.ics]]
enabled = true
url = "https://calendar.google.com/calendar/ical/xxxxxxxxxxxx/xxxxxxxxxxxxxx/basic.ics"
There is no username/password support.
To add multiple ICS calendars, include additional [[calendar.providers.ics]] blocks.
For CalDav you will need the CalDav URL, username, and password. Add them to config.toml:
[[calendar.providers.caldav]]
enabled = true
url = "https://nextcloud.example.com/remote.php/dav/principals/users/123456/"
username = "username"
password = "password"
id = "your-calendar-id"
Some CalDav features may not work well as the protocol is heavily undocumented, proprietary, and many servers don't implement it the same way.
To add multiple CalDav calendars, include additional [[calendar.providers.caldav]] blocks.
This is an optional step. There are a few different layouts to choose from.
In config.toml, set the layout under [display]:
[display]
screen_output_layout = "1"
screen_output_layout = "1" This is the default |
screen_output_layout = "2" More calendar entries and less emphasis on weather and time |
|---|---|
![]() |
![]() |
screen_output_layout = "3" Calendar entries on left, less emphasis on weather |
screen_output_layout = "4" Shows hour instead of time. Meant for color screens. |
|---|---|
![]() |
![]() |
screen_output_layout = "5" Calendar entries on left, with a month calendar for at-a-glance |
|
|---|---|
![]() |
Run ./run.sh which should query the weather provider and Google/Outlook Calendar. It will then create a png, convert to a 1-bit black and white bmp, then display the bmp on screen.
Using a 1-bit, low grade BMP is what allows the screen to refresh relatively quickly. Calling the BCM code to do it takes about 6 seconds. Rendering a high quality PNG or JPG and rendering to screen with Python takes about 35 seconds.
Once you've proven that the run works, and an image is sent to your epaper display, you can automate it by setting up a cronjob.
crontab -e
Add this entry so it runs every minute:
* * * * * cd /home/pi/waveshare-epaper-display && bash run.sh > run.log 2>&1
This will cause the script to run every minute, and write the output as well as errors to the run.log file.
Alternatively, you can use a systemd timer. There are example systemd units available to install a timer that starts a service every minute that runs the script. To achieve this, execute the following commands.
mkdir -p ~/.config/systemd/user/
cp utils/waveshare_epaper_display.service.example ~/.config/systemd/user/waveshare_epaper_display.service
cp utils/waveshare_epaper_display.timer.example ~/.config/systemd/user/waveshare_epaper_display.timer
systemctl --user daemon-reload
systemctl --user enable waveshare_epaper_display.timer
loginctl enable-linger
This is an optional step, to add your own custom data to the screen. For example this could be API calls, data from Home Assistant, PiHole stats, or something external.
Rename scripts/screen_custom_get.py.sample to scripts/screen_custom_get.py. Do your custom code, and set the value of custom_value_1 to the value you want to display. Run ./run.sh and it'll appear on screen.
Next, modify templates/screen_custom.svg and change the various x, y, font size values to adjust its appearance and position.
You can add more values by adding more SVG elements for custom_value_2, custom_value_3, and so on, and set its value in the output_dict in scripts/screen_custom_get.py.
The default locale of the system will be used to generate the time and date formats, including month and day names. On Raspberry Pi OS the default is usually en_GB.
Use the following instructions to install and try out other locales, or even force en_GB.
To see the current default locale, run locale.
To see all the locales installed on the system, use locale -a.
To install a new locale, go through the locale wizard:
sudo dpkg-reconfigure locales
Select the locales you want to install, be sure to pick the ones that have .UTF-8 in the name.
In config.toml, set the language under [locale]:
[locale]
language = "ko_KR.UTF-8"
The next time run.sh runs, the output should have the chosen language.
Some languages may not render well because the default Raspberry Pi system fonts don't have all the characters needed to display on screen. For such cases, you'll need to find and install a font that supports all the characters you want to display.
Chinese/Japanese/Korean should already be taken care of by installing the fonts-noto package. But sometimes just installing that isn't enough, you'll also have to set it as the default font, see the font instructions.
The reason this is necessary: the SVG renderer does not support fallback fonts which means that if a font doesn't have a certain character, it won't ask the system for other fonts to help plug the gaps. You'll just see squares.
The default font is set to sans-serif which on a Raspberry Pi defaults to DejaVu Sans. It's a decent font, wide, and visible, and works for most western languages.
In this example I'll replace it with Noto Sans. First run this command, it will show the current font being used.
$ fc-match sans-serif
DejaVuSans.ttf: "DejaVu Sans" "Book"
Install Noto fonts.
sudo apt install fonts-noto
Now create a font config file if it doesn't already exist.
mkdir -p ~/.config/fontconfig/conf.d
nano ~/.config/fontconfig/conf.d/00-fonts.conf
Set the contents of the 00-fonts.conf file:
<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
<alias>
<family>sans-serif</family>
<prefer>
<family>Noto Sans</family>
</prefer>
</alias>
</fontconfig>This tells the system to prefer 'Noto Sans' if the 'sans-serif' family is requested. You can test it by running:
$ fc-match sans-serif
NotoSans-Regular.ttf: "Noto Sans" "Regular"
The next time run.sh runs, the output image should have the chosen font.
This mode hides away everything and just displays an XKCD comic or a literary quote for the time. In config.toml, enable privacy mode and select the mode:
[privacy]
enabled = true
mode = "xkcd" # or "literature"
xkcd = true XKCD comic |
literature_clock = true Literature clock mode |
|---|---|
![]() |
![]() |
If the scripts don't work at all, try going through the Waveshare sample code linked below - if you can get those working, this script should work for you too.
You may want to further troubleshoot if you're seeing or not seeing something expected.
If you've set up the cron job as shown above, a run.log file will appear which contains some info and errors.
If there isn't enough information in there, you can set the log level in config.toml:
[locale]
log_level = "DEBUG"
The scripts cache the calendar and weather information, to avoid hitting weather API rate limits.
All temporary files are stored in the data/ folder.
If you want to force a weather update, delete data/cache_weather.json.
If you want to force a calendar update, delete data/cache_all_calendars.pickle.
If you want to force a re-login to Google or Outlook, delete data/token_google.pickle or data/token_outlook.bin.
To clear all cached data at once, run: rm -rf data/*
Waveshare have a user manual which you can get to from their Wiki
The Waveshare demo repo is here. Assuming all dependencies are installed, these demos should work.
git clone https://github.com/waveshare/e-Paper
cd e-Paper
This is the best place to start for troubleshooting - try to make sure the examples given in their repo works for you.
It's possible to run and debug the application locally with virtual environments. The last step fails, as it's trying to write to GPIO, but that's not an issue since the aim of local development is to generate and view the data/screen_output.png.
Do this before opening VSCode:
# Generate the virtual environment directory
python3 -m venv .venv
# Switch to it
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txtThen, open VSCode with the project, and it should automatically detect and switch to the virtual environment in the terminal.
Copy config.example.toml to config.toml and configure your settings.
To run the project, just run ./run.sh. It will read config.toml and run the various Python scripts.
To debug the project, open a Python script file such as scripts/screen_calendar_get.py or scripts/screen_weather_get.py, and press F5. It will use config.toml for settings and run the script. It can hit breakpoints, no problem.








