-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathweather_server.py
111 lines (94 loc) · 3.76 KB
/
weather_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
from datetime import datetime
from datetime import timedelta
import json
import os
import urllib
from eink.image import Palette
from eink.server import Server
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
class WeatherServer(Server):
"""Displays a five-day weather forecast, using the OpenWeatherMap API.
To use the OpenWeatherMap API, you must obtain an API key by signing
up for an account. If this is for personal use, the free plan should
offer more than enough API requests per month.
"""
def __init__(
self, latitude, longitude, api_key, imperial=False,
width=800, height=600, palette=Palette.THREE_BIT_GRAYSCALE):
"""Initialize a new ``WeatherServer``.
Arguments:
latitude (float): The latitude of the location to show the
weather for.
longitude (float): The longitude of the location to show the
weather for.
api_key (str): The OpenWeatherMap API key to use.
imperial (bool): Whether to display the results using
imperial units, as opposed to metric units.
width (int): The width of the display, after rotation.
height (int): The height of the display, after rotation.
palette (Palette): The palette to use. This must be a
palette that the e-ink device supports.
"""
self._latitude = latitude
self._longitude = longitude
self._api_key = api_key
self._imperial = imperial
self._width = width
self._height = height
self._palette = palette
def update_time(self):
return timedelta(minutes=30)
def screensaver_time(self):
return timedelta(hours=3)
def palette(self):
return self._palette
def render(self):
# Load the font
dir_ = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
font_filename = os.path.join(
dir_, 'src', 'eink', 'assets', 'server_skeleton',
'GentiumPlus-R.ttf')
font = ImageFont.truetype(font_filename, 50)
# Fetch the weather forecast
weather = self._fetch_weather()
image = Image.new('L', (self._width, self._height), 255)
draw = ImageDraw.Draw(image)
x = (self._width // 2) - 250
y = (self._height // 2) - 185
# Render the weather forecast
five_day_forecast = weather['daily'][:5]
for index, day_forecast in enumerate(five_day_forecast):
if index == 0:
day_str = 'Today'
elif index == 1:
day_str = 'Tomorrow'
else:
# Compute the day of the week
time = (
datetime.utcfromtimestamp(0) +
timedelta(seconds=day_forecast['dt']))
day_str = time.strftime('%A')
high = round(day_forecast['temp']['max'])
low = round(day_forecast['temp']['min'])
text = f'{day_str}: {high}\u00b0 / {low}\u00b0'
draw.text((x, y), text, fill=0, font=font)
y += 70
return image
def _fetch_weather(self):
"""Fetch the weather forecast from the OpenWeatherMap One Call API.
Return the JSON value for the response.
"""
if self._imperial:
units = 'imperial'
else:
units = 'metric'
url = (
'https://api.openweathermap.org/data/3.0/onecall?'
f'exclude=current,minutely,hourly,alerts&units={units}&'
f'appid={self._api_key}&lat={self._latitude}&'
f'lon={self._longitude}')
with urllib.request.urlopen(url) as response:
return json.loads(response.read().decode())