Skip to content

Instantly share code, notes, and snippets.

@idriszmy
Last active December 29, 2020 08:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idriszmy/21241005044636957b4c9fb49b30825d to your computer and use it in GitHub Desktop.
Save idriszmy/21241005044636957b4c9fb49b30825d to your computer and use it in GitHub Desktop.
Weather Display With e-Paper and Raspberry Pi
# This code was based on code taken from a tutorial on the Adafruit website.
# https://learn.adafruit.com/raspberry-pi-e-ink-weather-station-using-python
#
# e-Paper:
# - https://my.cytron.io/p-universal-e-paper-raw-panel-driver-hat?tracking=idris
# - https://my.cytron.io/p-2.9-inch-e-ink-raw-display-panel-tri-color?tracking=idris
#
# Register at https://openweathermap.org/ and get the token (API key)
#
# Download meteocons font and unzip
# curl --remote-name https://www.alessioatzeni.com/meteocons/res/download/meteocons-font.zip && unzip meteocons-font.zip
import time
import urllib.request
import urllib.parse
import digitalio
import busio
import board
from adafruit_epd.il0373 import Adafruit_IL0373
from weather_graphics import Weather_Graphics
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D25)
rst = digitalio.DigitalInOut(board.D17)
busy = digitalio.DigitalInOut(board.D24)
srcs = None
# You'll need to get a token from openweathermap.org, looks like:
# 'b6907d289e10d714a6e88b30761fae22'
OPEN_WEATHER_TOKEN = ""
# Use cityname, country code where countrycode is ISO3166 format.
# E.g. "New York, US" or "London, GB"
LOCATION = "Kuala Lumpur, MY"
DATA_SOURCE_URL = "http://api.openweathermap.org/data/2.5/weather"
if len(OPEN_WEATHER_TOKEN) == 0:
raise RuntimeError(
"You need to set your token first. If you don't already have one, you can register for a free account at https://home.openweathermap.org/users/sign_up"
)
# Set up where we'll be fetching data from
params = {"q": LOCATION, "appid": OPEN_WEATHER_TOKEN}
data_source = DATA_SOURCE_URL + "?" + urllib.parse.urlencode(params)
# Initialize the Display
display = Adafruit_IL0373(
128, 296, spi,
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy
)
display.rotation = 3
gfx = Weather_Graphics(display, am_pm=True, celsius=True)
weather_refresh = None
while True:
# only query the weather every 10 minutes (and on first run)
if (not weather_refresh) or (time.monotonic() - weather_refresh) > 600:
response = urllib.request.urlopen(data_source)
if response.getcode() == 200:
value = response.read()
print("Response is", value)
gfx.display_weather(value)
weather_refresh = time.monotonic()
else:
print("Unable to retrieve data at {}".format(url))
gfx.update_time()
time.sleep(300) # wait 5 minutes before updating anything again
from datetime import datetime
import json
from PIL import Image, ImageDraw, ImageFont
from adafruit_epd.epd import Adafruit_EPD
small_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16
)
medium_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20
)
large_font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 24
)
icon_font = ImageFont.truetype(
"./meteocons.ttf", 48
)
# Map the OpenWeatherMap icon code to the appropriate font character
# See http://www.alessioatzeni.com/meteocons/ for icons
ICON_MAP = {
"01d": "B",
"01n": "C",
"02d": "H",
"02n": "I",
"03d": "N",
"03n": "N",
"04d": "Y",
"04n": "Y",
"09d": "Q",
"09n": "Q",
"10d": "R",
"10n": "R",
"11d": "Z",
"11n": "Z",
"13d": "W",
"13n": "W",
"50d": "J",
"50n": "K",
}
# RGB Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
class Weather_Graphics:
def __init__(self, display, *, am_pm=True, celsius=True):
self.am_pm = am_pm
self.celsius = celsius
self.small_font = small_font
self.medium_font = medium_font
self.large_font = large_font
self.display = display
self._weather_icon = None
self._city_name = None
self._main_text = None
self._temperature = None
self._description = None
self._time_text = None
def display_weather(self, weather):
weather = json.loads(weather.decode("utf-8"))
# set the icon/background
self._weather_icon = ICON_MAP[weather["weather"][0]["icon"]]
city_name = weather["name"] + ", " + weather["sys"]["country"]
print(city_name)
self._city_name = city_name
main = weather["weather"][0]["main"]
print(main)
self._main_text = main
temperature = weather["main"]["temp"] - 273.15 # its...in kelvin
print(temperature)
if self.celsius:
self._temperature = "%d °C" % temperature
else:
self._temperature = "%d °F" % ((temperature * 9 / 5) + 32)
description = weather["weather"][0]["description"]
description = description[0].upper() + description[1:]
print(description)
self._description = description
# "thunderstorm with heavy drizzle"
self.update_time()
def update_time(self):
now = datetime.now()
self._time_text = now.strftime("%I:%M %p").lstrip("0").replace(" 0", " ")
self.update_display()
def update_display(self):
self.display.fill(Adafruit_EPD.WHITE)
image = Image.new("RGB", (self.display.width, self.display.height), color=WHITE)
draw = ImageDraw.Draw(image)
# Draw the Icon
(font_width, font_height) = icon_font.getsize(self._weather_icon)
draw.text(
(
self.display.width // 2 - font_width // 2,
self.display.height // 2 - font_height // 2 - 5,
),
self._weather_icon,
font=icon_font,
fill=BLACK,
)
# Draw the city
draw.text(
(5, 5), self._city_name, font=self.medium_font, fill=BLACK,
)
# Draw the time
(font_width, font_height) = medium_font.getsize(self._time_text)
draw.text(
(5, font_height * 2 - 5),
self._time_text,
font=self.medium_font,
fill=BLACK,
)
# Draw the main text
(font_width, font_height) = large_font.getsize(self._main_text)
draw.text(
(5, self.display.height - font_height * 2),
self._main_text,
font=self.large_font,
fill=BLACK,
)
# Draw the description
(font_width, font_height) = small_font.getsize(self._description)
draw.text(
(5, self.display.height - font_height - 5),
self._description,
font=self.small_font,
fill=BLACK,
)
# Draw the temperature
(font_width, font_height) = large_font.getsize(self._temperature)
draw.text(
(
self.display.width - font_width - 5,
self.display.height - font_height * 2,
),
self._temperature,
font=self.large_font,
fill=BLACK,
)
self.display.image(image)
self.display.display()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment