This repository has been archived by the owner on Jun 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
eink_images.py
236 lines (205 loc) · 7.96 KB
/
eink_images.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
from PIL import Image, ImageDraw, ImageFont, ImageOps
from datetime import datetime
from io import BytesIO
from matplotlib import pyplot as plt
from math import floor, ceil
temperature_font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf', 34)
text_font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf', 20)
small_font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf', 14)
def drawImage_forecast(forecast):
"""Build image for default display.
The top left corner shows location.
The top two-thirds of the display shows the current temperature and weather icon.
The bottom third of the display switches between weather summary, and time and date.
INPUTS
--------
forecast: forecast object
returned from forecastio.load_forecast()
show_datetime: bool
determine whether to display datetime (True) or summary (False)
RETURNS
--------
image: PIL.Image
image to be displayed on the eink screen
"""
# Prep data
current_forecast = forecast.currently()
summary = current_forecast.d['summary']
icon = current_forecast.d['icon']
temperature = current_forecast.d['apparentTemperature']
now = datetime.today()
# Set up image
image = Image.new('1', (200, 96), 1)
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, image.width, image.height), fill=1, outline=1)
# Draw temperature
draw.text( (16, 20), "{temp}'C".format(temp=round(temperature, 1)), font=temperature_font)
# Draw icon
icon = Image.open('./icons/{}.bmp'.format(icon))
draw.bitmap((image.width - icon.width, 4), icon, fill=0)
# Draw either summary or date and time
time_date = '{h:02d}:{m:02d} {date}'.format(h=now.hour, m=now.minute, date=now.strftime('%d %b'))
x_pix = (200 - draw.textsize(time_date, font=text_font)[0])/2
draw.text((x_pix, 72), time_date, fill=0, font=text_font)
# Draw symbol is weather alert
if forecast.alerts() == []:
# Draw location
draw.text( (0,0), "Cowes", font=small_font)
else:
# Draw location
draw.text( (23,0), "Cowes", font=small_font)
alert = Image.open('./icons/Alert.bmp')
draw.bitmap( (0,0), alert, fill=0)
return image
def drawImage_sunInfo(forecast):
"""Build image for secondary display: sunrise and sunset information.
Dispays the sunrise and sunset time of the current day
INPUTS
--------
forecast: forecast object
returned from forecastio.load_forecast()
RETURNS
--------
image: PIL.Image
image to be displayed on the eink screen
"""
# Prep data
today = forecast.daily().data[0]
sunrise = today.sunriseTime
sunset = today.sunsetTime
# Set up image
image = Image.new('1', (200, 96), 1)
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, image.width, image.height), fill=1, outline=1)
# Draw data
sunrise_icon = Image.open('./icons/sunrise.bmp')
sunset_icon = Image.open('./icons/sunset.bmp')
draw.bitmap((40,5), sunrise_icon, fill=0)
draw.bitmap((40,54), sunset_icon, fill=0)
draw.text( (100, 10), "{h:02d}:{m:02d}".format(h=sunrise.hour, m=sunrise.minute), font=text_font)
draw.text( (100, 58), "{h:02d}:{m:02d}".format(h=sunset.hour, m=sunset.minute), font=text_font)
return image
def drawImage_next2Days(forecast):
"""Build image for secondary display: weather forecast for next 2 days.
Displays the weather forecast (icon, max temperature and min temperature) for the next 2 days.
INPUTS
--------
forecast: forecast object
returned from forecastio.load_forecast()
RETURNS
--------
image: PIL.Image
image to be displayed on the eink screen
"""
days = forecast.daily()
# Set up image
image = Image.new('1', (200, 96), 1)
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, image.width, image.height), fill=1, outline=1)
draw.line((100,0)+(100,96), fill=0)
# Prep data for next day
tomorrow = days.data[1]
tmrw_icon = Image.open('./icons/{}.bmp'.format(tomorrow.d['icon']))
tmrw_max_temp = str(round(tomorrow.d['apparentTemperatureMax'], 1)) + "'C"
tmrw_min_temp = str(round(tomorrow.d['apparentTemperatureMin'], 1)) + "'C"
# Draw data
draw.bitmap((18,0), tmrw_icon, fill=0)
x = int((100 - draw.textsize(tmrw_max_temp, font=small_font)[0])/2)
draw.text( (x,55), tmrw_max_temp, font=small_font)
x = int((100 - draw.textsize(tmrw_min_temp, font=small_font)[0])/2)
draw.text( (x,66), tmrw_min_temp, font=small_font)
x = int((100 - draw.textsize("Tomorrow", font=small_font)[0])/2)
draw.text( (x,82), "Tomorrow", font=small_font)
# Prep data for next day + 1
day_2 = days.data[2]
day_2_name = datetime.fromtimestamp(day_2.d['time']).strftime('%A')
day_2_icon = Image.open('./icons/{}.bmp'.format(day_2.d['icon']))
day_2_max_temp = str(round(day_2.d['apparentTemperatureMax'], 1)) + "'C"
day_2_min_temp = str(round(day_2.d['apparentTemperatureMin'], 1)) + "'C"
# Draw data
draw.bitmap((118,0), tmrw_icon, fill=0)
x = int((100 - draw.textsize(day_2_max_temp, font=small_font)[0])/2)
draw.text( (100+x,55), day_2_max_temp, font=small_font)
x = int((100 - draw.textsize(day_2_min_temp, font=small_font)[0])/2)
draw.text( (100+x,66), day_2_min_temp, font=small_font)
x = int((100 - draw.textsize(day_2_name, font=small_font)[0])/2)
draw.text( (100+x,82), day_2_name, font=small_font)
return image
def drawImage_tempGraph(forecast):
"""Build image for secondary display: graph showing temperature change for next 24 hours.
INPUTS
--------
forecast: forecast object
returned from forecastio.load_forecast()
RETURNS
--------
image: PIL.Image
image to be displayed on the eink screen
"""
hourly = forecast.hourly()
tempData = []
for hour in hourly.data[:24]:
tempData.append(hour.d['apparentTemperature'])
fig,ax = plt.subplots(figsize=(2.3, 1), dpi=100)
ax.plot(tempData, lw=2, color='k')
ax.plot([0,24], [0,0], 'k--')
ax.set_ylim([floor(min(tempData)), ceil(max(tempData))])
ax.set_yticks([floor(min(tempData)), ceil(max(tempData))])
ax.set_yticklabels([])
ax.set_xticks([0,6,12,18,24])
ax.set_xticklabels([])
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_linewidth(1.25)
ax.spines['left'].set_linewidth(1.25)
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')
# Save graph to open with PIL
buffer_ = BytesIO()
fig.savefig(buffer_, format='png')
buffer_.seek(0)
# Set up image
image = Image.new('1', (200, 96), 1)
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, image.width, image.height), fill=1, outline=1)
# Draw graph
graph = ImageOps.invert(Image.open(buffer_).convert('L'))
draw.bitmap((-8,2), graph, fill=0)
x = draw.textsize(str(int(ceil(max(tempData)))), font=small_font)[0]
draw.text((17-x,5), str(int(ceil(max(tempData)))), font=small_font)
x = draw.textsize(str(int(floor(min(tempData)))), font=small_font)[0]
draw.text((17-x,80), str(int(floor(min(tempData)))), font=small_font)
draw.text((36,0), "Temp ('C) 24 hrs", font=small_font)
return image
def drawImage_weatherAlert(forecast):
"""Build image for secondary display: Information about weather alerts.
INPUTS
--------
forecast: forecast object
returned from forecastio.load_forecast()
RETURNS
--------
image: PIL.Image
image to be displayed on the eink screen
"""
alert = forecast.alerts()
# Set up image
image = Image.new('1', (200, 96), 1)
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, image.width, image.height), fill=1, outline=1)
if alert == []:
# No weather alert
draw.text((50, 5), "Alert", font=temperature_font)
# No alerts
draw.text((34, 50), "No warnings", font=text_font)
else:
# Weather alert
draw.text((50, 5), "Alert", font=temperature_font)
# Alert title
x = int((200 - draw.textsize(alert[0].json['title'].split(" for ")[0], font=text_font)[0])/2)
draw.text((x, 50), alert[0].json['title'].split(" for ")[0], font=text_font)
# Alert expiry
expiry_date = datetime.fromtimestamp(alert[0].json['expires']).strftime('%A %H:%m')
x = int((200 - draw.textsize("Expires: {}".format(expiry_date), font=small_font)[0])/2)
draw.text((x, 77), "Expires: {}".format(expiry_date), font=small_font)
return image