diff --git a/EInk_Bonnet_Weather_Station/meteocons.ttf b/EInk_Bonnet_Weather_Station/meteocons.ttf new file mode 100644 index 000000000..809da1827 Binary files /dev/null and b/EInk_Bonnet_Weather_Station/meteocons.ttf differ diff --git a/EInk_Bonnet_Weather_Station/weather.py b/EInk_Bonnet_Weather_Station/weather.py new file mode 100644 index 000000000..c972ec5f5 --- /dev/null +++ b/EInk_Bonnet_Weather_Station/weather.py @@ -0,0 +1,60 @@ +""" +This example queries the Open Weather Maps site API to find out the current +weather for your location... and display it on a eInk Bonnet! +""" + +import time +import urllib.request +import urllib.parse +import digitalio +import busio +import board +from adafruit_epd.epd import Adafruit_EPD +from adafruit_epd.ssd1675 import Adafruit_SSD1675 +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.D22) +rst = digitalio.DigitalInOut(board.D27) +busy = digitalio.DigitalInOut(board.D17) + +# You'll need to get a token from openweathermap.org, looks like: +# 'b6907d289e10d714a6e88b30761fae22' +OPEN_WEATHER_TOKEN = "" +LOCATION = "Manhattan, US" +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_SSD1675( + 122, 250, spi, cs_pin=ecs, dc_pin=dc, sramcs_pin=None, rst_pin=rst, busy_pin=busy, +) + +display.rotation = 3 + +gfx = Weather_Graphics(display, am_pm=True, celsius=False) +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 diff --git a/EInk_Bonnet_Weather_Station/weather_graphics.py b/EInk_Bonnet_Weather_Station/weather_graphics.py new file mode 100644 index 000000000..6826b44d4 --- /dev/null +++ b/EInk_Bonnet_Weather_Station/weather_graphics.py @@ -0,0 +1,157 @@ +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) + + # 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()