Added EInk Bonnet Weather Station Code
This commit is contained in:
parent
6899f09f2b
commit
9dd2e3be78
3 changed files with 217 additions and 0 deletions
BIN
EInk_Bonnet_Weather_Station/meteocons.ttf
Normal file
BIN
EInk_Bonnet_Weather_Station/meteocons.ttf
Normal file
Binary file not shown.
60
EInk_Bonnet_Weather_Station/weather.py
Normal file
60
EInk_Bonnet_Weather_Station/weather.py
Normal file
|
|
@ -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
|
||||
157
EInk_Bonnet_Weather_Station/weather_graphics.py
Normal file
157
EInk_Bonnet_Weather_Station/weather_graphics.py
Normal file
|
|
@ -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()
|
||||
Loading…
Reference in a new issue