Weatherpaper: Weatherforecast on a RPi Zero with E-Paper Display
Intro
Using a Raspberry Pi Zero W and a 2.13“ e-paper hat one can create a quite decent weatherstation with a few lines of python code. As source for weatherinformation the ASCII based weather-api wttr.in which can be easily used via http requests. The API follows the pattern https://wttr.in/<location>
. The help-page can be found at wttr.in/:help. To query, for example, the weatherinformation for Berlin one can use curl:
curl https://wttr.in/Berlin
Since there won’t be much space on the e-paper display we won’t use the query displayed above, but just the current weather:
curl https://wttr.in/Berlin?0T
Weather report: Berlin
\ / Clear
.-. +1(-3) °C
― ( ) ― ↘ 15 km/h
`-’ 10 km
/ \ 0.0 mm
Prerequisites
- Raspberry Pi Zero W, with an OS set up (e.g. Raspbian OS), connected to the internet
- Waveshare 2.13“ E-Paper Hat V2
- Virtualenv for Python3
The documentation for the e-paper display can be found on the Waveshare website. It also contains example code on how to use the display with other boards than the Raspberry Pi.
Setup
Waveshare provides a library to interact with the display using python at github.com/waveshareteam/e-Paper. Easiest is to clone this repository, but before one should create a python virtual environment to not steer up any other installed packages.
1 # Creating a directory for this project
2 mkdir weatherpaper
3 cd weatherpaper
4 # Creating the python virtualenv
5 virtualenv .venv
6 # Cloning the waveshare/e-paper repository
7 git clone https://github.com/waveshareteam/e-Paper.git
Next one can activate the virtualenv just created and install waveshare’s python library using pip
.
1 # Activating the virtualenv
2 source .venv/bin/activate
3 # Changing directory to the library
4 cd e-Paper/RaspberryPi_JetsonNano/python
5 # Installing the waveshare library
6 pip install .
7 # Installing the requests library
8 pip install requests
The font used to display the weatherforecast information will be Fira Code. This font can be found on github as well at github.com/tonsky/FiraCode. For the weatherpaper script the .ttf
font file is required in a directory called ttf
within the same path as the script itself. To set this up the following commands can be used.
1 cd weatherpaper
2 # Downloading the zip file using curl. Github redirects, thus -L is required.
3 curl -L --output Fira_Code_v6.2.zip https://github.com/tonsky/FiraCode/releases/download/6.2/Fira_Code_v6.2.zip
4 # Since we only need a single ttf file, we only extract the one needed.
5 unzip Fira_Code_v6.2.zip "ttf/FiraCode-Regular.ttf" -d "."
6 # Remove the unneeded zip file
7 rm Fira_Code_v6.2.zip
Now, everything is prepared for the weatherpaper python script.
The Weatherpaper Script
The script itself is quite compact. The code can also be found at github.com/derfalx/scripts.
Lines 1 to 8 contain any import needed, as well as the basic log configuration. The main function of the script is weatherpaper
. It takes three parameter: location
, language
and minutes
. The first parameter, location
contains the location name to be queried. The language to be used for the output of wttr.in is set using language
and the waiting time in minutes between two updates of the weatherinformation is passed using minutes
.
Preparation and initialization is done in line 17 to 26. First, the e-paper driver is initialized and the display is cleared. Next, the font to be used is loaded and an initial image is created, containing only white (= no content). For updates of the display epd.FULL_UPDATE
is used. This way, the display is fully refreshed each time a image is drawn. It would also be possible to do a full update only once a while, but this could lead to a “dirty display” which shows previous content as background shadow.
Fetching and displaying weather information is done in the while(True)
loop. It should only stop in case of an keyboard interrupt (or a major exception/error). To fetch the weather information python’s request
library is used. The returned content is properly decoded (line 34) and set as text on a new image (line 36 to 38). The image is then rotated by 180° to match the orientation of the display (line 41). In case one does not rotate the display, this line can be omitted. Finally, the image is displayed (line42). This code block is enclosed in a try-except block in case an exception is raised while fetching / processing the request to wttr.in.
Once a request was done - regardless if it was successful or not - the script sleeps for the previously defined amount of minutes.
1 import logging
2 logging.basicConfig(level=logging.DEBUG)
3 import os
4 from waveshare_epd import epd2in13_V2
5 import time
6 from PIL import Image, ImageDraw, ImageFont
7 import requests
8 import sys
9
10
11 def weatherpaper(location, language, minutes):
12 # Main try-except is used to intercept keyboardinterrupts to properly
13 # shut down the script.
14 try:
15 logging.info("== weatherpaper ==")
16 # Preparing and cleaning the Display
17 epd = epd2in13_V2.EPD()
18 epd.init(epd.FULL_UPDATE)
19 epd.Clear(0xFF)
20 # Loading the font and creating an initial, empty screen.
21 fontpath = os.path.join(os.path.dirname(os.path.realpath(__file__)))
22 font = ImageFont.truetype(os.path.join(fontpath, 'ttf/FiraCode-Regular.ttf'), 13)
23 image = Image.new('1', (epd.height, epd.width), 255)
24 draw = ImageDraw.Draw(image)
25 # Everytime an update is done, it will be a full (instead of a partial) update.
26 epd.init(epd.FULL_UPDATE)
27
28 while(True):
29 try:
30 r = requests.get(f'https://wttr.in/{location}?0T&lang={language}')
31 # In case r.status_code is not a successful status, raise an exception
32 r.raise_for_status()
33 # Setting proper encoding, so the text can be display correct
34 r.encoding = 'utf-8'
35 logging.info(r.text)
36 image = Image.new('1', (epd.height, epd.width), 255)
37 draw = ImageDraw.Draw(image)
38 draw.text((0,0), r.text, font=font, fill=0)
39 # Rotating the image is needed in my case, since I use the display bottom up.
40 # In case you use it the other way round, remove this line.
41 image = image.rotate(180)
42 epd.display(epd.getbuffer(image))
43 except requests.exceptions.RequestException as e:
44 logging.warn(f'An exception occurred while requesting wttr.in. Maybe it returned != 200. Skipping update.')
45
46 time.sleep(60 * minutes)
47 except KeyboardInterrupt:
48 epd2in13_V2.epdconfig.module_exit()
49 exit()
50
51
52 if __name__ == '__main__':
53 if len(sys.argv) != 4:
54 print("usage: python weatherpaper.py <location> <language> <minutes>")
55 exit()
56
57 weatherpaper(sys.argv[1], sys.argv[2], int(sys.argv[3]))
58
Running the Script in Background
To run the weatherpaper script in background one can use the follow bash script:
1 #! /bin/bash
2 source ./weatherpaper/.venv/bin/activate
3 nohup python ./weatherpaper/weatherpaper.py "<location>" "<language>" <minutes> &
Simply set location
, language
, minutes
and make the script executable using chmod u+x <scriptname>
.
There you go!