This is what I have so far:
# Display BBC Weather for Reading (2639577) on Pimoroni Inky Frame
# For the weather where you live goto https://www.bbc.co.uk/weather and find your number
# Just a modified news_headlines.py as pre-installed on Pimoroni Inky Frame
from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY # Inky Frame 4.0"
from network_manager import NetworkManager
import WIFI_CONFIG
import uasyncio
from urllib import urequest
import math, gc
weatherURL = "http://weather-broker-cdn.api.bbci.co.uk/en/forecast/rss/3day/2639577"
# Callback handler for Pioroni NetworkManager
# Lifted and shifted from Pimoroni news_headlines
def status_handler(mode, status, ip):
print(mode, status, ip)
# Reads through stream appending to result until char is found
# Lifted and shifted from Pimoroni news_headlines
def read_until(stream, char):
result = b""
while True:
c = stream.read(1)
if c == char:
return result
result += c
# Reads through stream ignoring everything, stop when char is found
# Lifted and shifted from Pimoroni news_headlines
def discard_until(stream, char):
while stream.read(1) != char:
pass
# Parses an XML stream
# Lifted and shifted from Pimoroni news_headlines
def parse_xml_stream(stream, accept_tags, group_by, max_items=3):
tag = []
text = b""
count = 0
current = {}
while True:
char = stream.read(1)
if len(char) == 0:
break
if char == b"<":
next_char = stream.read(1)
# Discard stuff like <?xml vers...
if next_char == b"?":
discard_until(stream, b">")
continue
# Detect <![CDATA
elif next_char == b"!":
stream.read(1) # Discard [
discard_until(stream, b"[") # Discard CDATA[
text = read_until(stream, b"]")
discard_until(stream, b">") # Discard ]>
gc.collect()
elif next_char == b"/":
current_tag = read_until(stream, b">")
top_tag = tag[-1]
# Populate our result dict
if top_tag in accept_tags:
current[top_tag.decode("utf-8")] = text.decode("utf-8")
# If we've found a group of items, yield the dict
elif top_tag == group_by:
yield current
current = {}
count += 1
if count == max_items:
return
tag.pop()
text = b""
gc.collect()
continue
else:
current_tag = read_until(stream, b">")
tag += [next_char + current_tag.split(b" ")[0]]
text = b""
gc.collect()
else:
text += char
# Parse tthe RSS feed extracting specific values for items
# Lifted and shifted from Pimoroni news_headlines but removed error handling
def get_rss(url, items, values):
stream = urequest.urlopen(url)
output = list(parse_xml_stream(stream, values, items))
return output
# Helper to abbreviate some common words
# Note this is totally hand cranked
def abbreviate(text):
retVal = text
retVal = retVal.replace("Temperature", "Temp")
retVal = retVal.replace("temperature", "temp")
retVal = retVal.replace("Minimum", "Min")
retVal = retVal.replace("Maximum", "Max")
retVal = retVal.replace("minimum", "min")
retVal = retVal.replace("maximum", "max")
return retVal
# Helper to calulate height of text (assuming bitmap8 font is 8 high)
def get_text_height(graphics, text, width, scale = 1, font_height = 8):
return math.ceil(graphics.measure_text(text, scale) / width) * font_height * scale
# Connect to WiFi
# Lifted and shifted from Pimoroni news_headlines
network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler)
uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
# Gets the weather image which includes a meaningful title
image = get_rss(weatherURL, b"image", [b"title", b"url"])
# Gets the weather entries/items, we oonly want the titles
feed = get_rss(weatherURL, b"item", [b"title"])
heading = image[0]["title"]
weather1 = abbreviate(feed[0]["title"])
weather2 = abbreviate(feed[1]["title"])
del feed
# output some debug info
print(heading)
print(weather1)
print(weather2)
# Create a PicoGraphics object for the display
# Lifted and shifted from Pimoroni news_headlines
graphics = PicoGraphics(DISPLAY)
WIDTH, HEIGHT = graphics.get_bounds()
# Clear the display (1 = white)
graphics.set_pen(1)
graphics.clear()
# Use the bitmap8 font
graphics.set_font("bitmap8")
# Set a nice padding value
PADDING = 5
# All text will be the same width
TEXT_WIDTH = WIDTH - PADDING * 2
# Keep track of our Y position on the display
Y = PADDING
# Add a heading (3 = blue)
graphics.set_pen(3)
graphics.text(heading, PADDING, Y, TEXT_WIDTH, scale=3)
Y += get_text_height(graphics, heading, TEXT_WIDTH, scale=3) + PADDING
# Add today's weather (0 = black)
graphics.set_pen(0)
graphics.text(weather1, PADDING, Y, TEXT_WIDTH, scale=3)
Y += get_text_height(graphics, weather1, TEXT_WIDTH, scale=3) + PADDING
# Add tomorrow's weather (same pen, i.e. black)
graphics.text(weather2, PADDING, Y, TEXT_WIDTH, scale=3)
Y += get_text_height(graphics, weather1, TEXT_WIDTH, scale=3) + PADDING
# Update the display
graphics.update()
# Try to free some resources (does this even work?)
del graphics
gc.collect()