Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Raspberry pi zero w used with an inkyphat e-ink display

Using the raspberry pi zero w with an inkyphat e-ink display

raspberry-pi-inky-phat

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

The script

#!/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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.