Hey,
My name's Nikhil. I'm a JavaScript developer who doesn't know any python - I hacked this script together till I got something I liked due to just wanting something that worked, and haven't touched this code since due to having a thing that worked. If you end up improving it, I'd really appreciate a shout.
I've written a post about it here https://nikhilvijayan.com/raspberry-pi-zero-weather-display.
If you end up making this, or improving this hacky script, I'd love to hear from you. My twitter is @nkhil
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import glob
import time
import argparse
from inky import InkyPHAT
from PIL import Image, ImageDraw, ImageFont
from font_fredoka_one import FredokaOne
try:
import requests
except ImportError:
exit("This script requires the requests module\nInstall with: sudo pip install requests")
try:
import geocoder
except ImportError:
exit("This script requires the geocoder module\nInstall with: sudo pip install geocoder")
try:
from bs4 import BeautifulSoup
except ImportError:
exit("This script requires the bs4 module\nInstall with: sudo pip install beautifulsoup4")
print("""Inky pHAT: Weather
Displays weather information for a given location. The default location is Sheffield-on-Sea.
""")
# Command line arguments to set display colour
# parser = argparse.ArgumentParser()
# parser.add_argument('--colour', '-c', type=str, required=True, choices=["red", "black", "yellow"], help="ePaper display colour")
# args = parser.parse_args()
# Set up the display
colour = "black"
inky_display = InkyPHAT(colour)
inky_display.set_border(inky_display.BLACK)
# Details to customise your weather display
CITY = "London"
COUNTRYCODE = "GB"
WARNING_TEMP = 25.0
# Convert a city name and country code to latitude and longitude
def get_coords(address):
g = geocoder.arcgis(address)
coords = g.latlng
return coords
# Query Dark Sky (https://darksky.net/) to scrape current weather data
def get_weather(address):
coords = get_coords(address)
weather = {}
res = requests.get(
"https://darksky.net/forecast/{}/uk212/en".format(",".join([str(c) for c in coords])))
if res.status_code == 200:
soup = BeautifulSoup(res.content, "lxml")
curr = soup.find_all("span", "currently")
weather["summary"] = curr[0].img["alt"].split()[0]
weather["temperature"] = int(curr[0].find(
"span", "summary").text.split()[0][:-1])
# press = soup.find_all("div", "pressure")
# weather["pressure"] = int(press[0].find("span", "num").text)
return weather
else:
return weather
def create_mask(source, mask=(inky_display.WHITE, inky_display.BLACK, inky_display.RED)):
"""Create a transparency mask.
Takes a paletized source image and converts it into a mask
permitting all the colours supported by Inky pHAT (0, 1, 2)
or an optional list of allowed colours.
:param mask: Optional list of Inky pHAT colours to allow.
"""
mask_image = Image.new("1", source.size)
w, h = source.size
for x in range(w):
for y in range(h):
p = source.getpixel((x, y))
if p in mask:
mask_image.putpixel((x, y), 255)
return mask_image
# Dictionaries to store our icons and icon masks in
icons = {}
masks = {}
# Get the weather data for the given location
location_string = "{city}, {countrycode}".format(
city=CITY, countrycode=COUNTRYCODE)
weather = get_weather(location_string)
# This maps the weather summary from Dark Sky
# to the appropriate weather icons
icon_map = {
"snow": ["snow", "sleet"],
"rain": ["rain"],
"cloud": ["fog", "cloudy", "partly-cloudy-day", "partly-cloudy-night"],
"sun": ["clear-day", "clear-night"],
"storm": [],
"wind": ["wind"]
}
# Placeholder variables
pressure = 0
temperature = 0
weather_icon = None
if weather:
temperature = weather["temperature"]
# pressure = weather["pressure"]
summary = weather["summary"]
for icon in icon_map:
if summary in icon_map[icon]:
weather_icon = icon
break
else:
print("Warning, no weather information found!")
# Create a new canvas to draw on
# img = Image.open("resources/backdrop.png")
img = Image.new("P", (inky_display.WIDTH, inky_display.HEIGHT))
draw = ImageDraw.Draw(img)
# Load our icon files and generate masks
for icon in glob.glob("resources/icon-*.png"):
icon_name = icon.split("icon-")[1].replace(".png", "")
icon_image = Image.open(icon)
icons[icon_name] = icon_image
masks[icon_name] = create_mask(icon_image)
print(icons)
print(masks)
# Load the FredokaOne font
font = ImageFont.truetype(FredokaOne, 22)
# Draw lines to frame the weather data
# draw.line((69, 36, 69, 81)) # Vertical line
# draw.line((31, 35, 184, 35)) # Horizontal top line
# draw.line((69, 58, 174, 58)) # Horizontal middle line
# draw.line((169, 58, 169, 58), 2) # Red seaweed pixel :D
# Write text with weather values to the canvas
# datetime = time.strftime("%d/%m %H:%M")
# draw.text((36, 12), datetime, inky_display.WHITE, font=font)
# draw.text((72, 34), "T", inky_display.WHITE, font=font)
draw.text((92, 34), u"{}°".format(temperature), inky_display.WHITE if temperature <
WARNING_TEMP else inky_display.RED, font=font)
# draw.text((72, 58), "P", inky_display.WHITE, font=font)
# draw.text((92, 58), "{}".format(pressure), inky_display.WHITE, font=font)
# Draw the current weather icon over the backdrop
if weather_icon is not None:
img.paste(icons[weather_icon], (28, 36), masks[weather_icon])
else:
draw.text((28, 36), "?", inky_display.RED, font=font)
# Display the weather data on Inky pHAT
inky_display.set_image(img)
inky_display.show()