|
@@ -8,6 +8,8 @@
|
8
|
8
|
# ----------------------------------------------------------------------------
|
9
|
9
|
|
10
|
10
|
import util
|
|
11
|
+from image import ImageScreen
|
|
12
|
+
|
11
|
13
|
import time
|
12
|
14
|
from datetime import datetime, timezone, timedelta
|
13
|
15
|
|
|
@@ -19,6 +21,13 @@ from wetterdienst.provider.dwd.mosmix import (
|
19
|
21
|
)
|
20
|
22
|
import polars
|
21
|
23
|
|
|
24
|
+def get_first_capitalized_word(s):
|
|
25
|
+ words = s.split()
|
|
26
|
+ for w in words:
|
|
27
|
+ if w[0].isupper():
|
|
28
|
+ return w
|
|
29
|
+ return None
|
|
30
|
+
|
22
|
31
|
class WeatherScreen:
|
23
|
32
|
def __init__(self, g, i, latlon, timestep = 5.0, refresh = (60.0 * 60.0)):
|
24
|
33
|
self.gui = g
|
|
@@ -37,7 +46,39 @@ class WeatherScreen:
|
37
|
46
|
"temperature_air_mean_200",
|
38
|
47
|
"cloud_cover_effective",
|
39
|
48
|
]
|
40
|
|
- self.num_state = len(self.params) + 1
|
|
49
|
+ self.num_state = 4
|
|
50
|
+
|
|
51
|
+ self.descriptions = [
|
|
52
|
+ (95, 'leichtes oder mäßiges Gewitter mit Regen oder Schnee', 'weather_icon_95.png'),
|
|
53
|
+ (57, 'mäßiger oder starker gefrierender Sprühregen', 'weather_icon_57.png'),
|
|
54
|
+ (56, 'leichter gefrierender Sprühregen', 'weather_icon_56.png'),
|
|
55
|
+ (67, 'mäßiger bis starker gefrierender Regen', 'weather_icon_67.png'),
|
|
56
|
+ (66, 'leichter gefrierender Regen', 'weather_icon_66.png'),
|
|
57
|
+ (86, 'mäßiger bis starker Schneeschauer', 'weather_icon_86.png'),
|
|
58
|
+ (85, 'leichter Schneeschauer', 'weather_icon_85.png'),
|
|
59
|
+ (84, 'mäßiger oder starker Schneeregenschauer', 'weather_icon_84.png'),
|
|
60
|
+ (83, 'leichter Schneeregenschauer', 'weather_icon_83.png'),
|
|
61
|
+ (82, 'äußerst heftiger Regenschauer', 'weather_icon_82.png'),
|
|
62
|
+ (81, 'mäßiger oder starker Regenschauer', 'weather_icon_81.png'),
|
|
63
|
+ (80, 'leichter Regenschauer', 'weather_icon_80.png'),
|
|
64
|
+ (75, 'durchgehend starker Schneefall', 'weather_icon_75.png'),
|
|
65
|
+ (73, 'durchgehend mäßiger Schneefall', 'weather_icon_73.png'),
|
|
66
|
+ (71, 'durchgehend leichter Schneefall', 'weather_icon_71.png'),
|
|
67
|
+ (69, 'mäßger oder starker Schneeregen', 'weather_icon_69.png'),
|
|
68
|
+ (68, 'leichter Schneeregen', 'weather_icon_68.png'),
|
|
69
|
+ (55, 'durchgehend starker Sprühregen', 'weather_icon_55.png'),
|
|
70
|
+ (53, 'durchgehend mäßiger Sprühregen', 'weather_icon_53.png'),
|
|
71
|
+ (51, 'durchgehend leichter Sprühregen', 'weather_icon_51.png'),
|
|
72
|
+ (65, 'durchgehend starker Regen', 'weather_icon_65.png'),
|
|
73
|
+ (63, 'durchgehend mäßiger Regen', 'weather_icon_63.png'),
|
|
74
|
+ (61, 'durchgehend leichter Regen', 'weather_icon_61.png'),
|
|
75
|
+ (49, 'Nebel mit Reifansatz, Himmel nicht erkennbar, unverändert', 'weather_icon_49.png'),
|
|
76
|
+ (45, 'Nebel, Himmel nicht erkennbar', 'weather_icon_45.png'),
|
|
77
|
+ (3, 'Bewölkung zunehmend', None),
|
|
78
|
+ (2, 'Bewölkung unverändert', None),
|
|
79
|
+ (1, 'Bewölkung abnehmend', None),
|
|
80
|
+ (0, 'keine Bewölkungsentwicklung', None),
|
|
81
|
+ ]
|
41
|
82
|
|
42
|
83
|
self.find_station()
|
43
|
84
|
self.restart()
|
|
@@ -58,10 +99,20 @@ class WeatherScreen:
|
58
|
99
|
"start": False,
|
59
|
100
|
"select": False,
|
60
|
101
|
}
|
|
102
|
+ self.done = False
|
61
|
103
|
self.last = time.time()
|
62
|
104
|
|
63
|
105
|
def find_station(self):
|
64
|
|
- settings = Settings(ts_shape=True, ts_humanize=True)
|
|
106
|
+ self.gui.loop_start()
|
|
107
|
+ self.t_head.setText("Weather:", "lemon")
|
|
108
|
+ self.t_head.draw(3, -self.gui.height / 2 + 7)
|
|
109
|
+ self.t_sub.setText("Loading...", "tom-thumb")
|
|
110
|
+ self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 4)
|
|
111
|
+ self.t_val.setText("Station...", "tom-thumb")
|
|
112
|
+ self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 6)
|
|
113
|
+ self.gui.loop_end()
|
|
114
|
+
|
|
115
|
+ settings = Settings(ts_shape=True, ts_humanize=True, cache_disable=False)
|
65
|
116
|
request = DwdMosmixRequest(
|
66
|
117
|
parameter=self.params,
|
67
|
118
|
start_issue=DwdForecastDate.LATEST,
|
|
@@ -83,7 +134,16 @@ class WeatherScreen:
|
83
|
134
|
self.parse_forecast()
|
84
|
135
|
|
85
|
136
|
def get_forecast(self):
|
86
|
|
- settings = Settings(ts_shape=True, ts_humanize=True)
|
|
137
|
+ self.gui.loop_start()
|
|
138
|
+ self.t_head.setText("Weather:", "lemon")
|
|
139
|
+ self.t_head.draw(3, -self.gui.height / 2 + 7)
|
|
140
|
+ self.t_sub.setText("Loading...", "tom-thumb")
|
|
141
|
+ self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 4)
|
|
142
|
+ self.t_val.setText("Refresh...", "tom-thumb")
|
|
143
|
+ self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 6)
|
|
144
|
+ self.gui.loop_end()
|
|
145
|
+
|
|
146
|
+ settings = Settings(ts_shape=True, ts_humanize=True, cache_disable=False)
|
87
|
147
|
request = DwdMosmixRequest(
|
88
|
148
|
parameter=self.params,
|
89
|
149
|
start_issue=DwdForecastDate.LATEST,
|
|
@@ -94,6 +154,15 @@ class WeatherScreen:
|
94
|
154
|
self.parse_forecast()
|
95
|
155
|
|
96
|
156
|
def parse_forecast(self):
|
|
157
|
+ self.gui.loop_start()
|
|
158
|
+ self.t_head.setText("Weather:", "lemon")
|
|
159
|
+ self.t_head.draw(3, -self.gui.height / 2 + 7)
|
|
160
|
+ self.t_sub.setText("Parsing", "tom-thumb")
|
|
161
|
+ self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 4)
|
|
162
|
+ self.t_val.setText("Forecast", "tom-thumb")
|
|
163
|
+ self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 6)
|
|
164
|
+ self.gui.loop_end()
|
|
165
|
+
|
97
|
166
|
self.last_forecast = time.time()
|
98
|
167
|
|
99
|
168
|
response = next(self.forecast.values.query())
|
|
@@ -116,14 +185,14 @@ class WeatherScreen:
|
116
|
185
|
if keys["up"] and (not self.old_keys["up"]) and (not self.old_keys["select"]):
|
117
|
186
|
self.state = (self.state + 1) % self.num_state
|
118
|
187
|
self.last = time.time()
|
119
|
|
- elif keys["down"] and (not self.old_keys["select"]):
|
|
188
|
+ elif keys["down"] and (not self.old_keys["down"]) and (not self.old_keys["select"]):
|
120
|
189
|
self.state = (self.state - 1) % self.num_state
|
121
|
190
|
self.last = time.time()
|
122
|
191
|
|
123
|
192
|
self.old_keys = keys.copy()
|
124
|
193
|
|
125
|
194
|
def finished(self):
|
126
|
|
- return False # TODO
|
|
195
|
+ return self.done
|
127
|
196
|
|
128
|
197
|
def draw_station_info(self):
|
129
|
198
|
# heading
|
|
@@ -152,9 +221,41 @@ class WeatherScreen:
|
152
|
221
|
self.t_head.setText("Weather:", "lemon")
|
153
|
222
|
self.t_head.draw(3, -self.gui.height / 2 + 7)
|
154
|
223
|
|
|
224
|
+ # convert weather id
|
155
|
225
|
val = self.data.filter(polars.col("parameter") == self.params[0])[0]["value"][0]
|
156
|
|
- self.t_val.setText("{:.0f}".format(val), "tom-thumb")
|
157
|
|
- self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 5)
|
|
226
|
+ name = "ID {} Unknown".format(val)
|
|
227
|
+ img = None
|
|
228
|
+ for i, d in enumerate(self.descriptions):
|
|
229
|
+ if d[0] != val:
|
|
230
|
+ continue
|
|
231
|
+
|
|
232
|
+ if isinstance(d[2], str):
|
|
233
|
+ w = 50
|
|
234
|
+ target_size = (w, w)
|
|
235
|
+ iscr = ImageScreen(self.gui, d[2], 0.2, 1, 5.0, None, target_size, False)
|
|
236
|
+ self.descriptions[i] = (d[0], d[1], iscr)
|
|
237
|
+ iscr.xOff = (self.gui.width - w) / 2
|
|
238
|
+ iscr.yOff = self.gui.height - w + 5
|
|
239
|
+ img = iscr
|
|
240
|
+ else:
|
|
241
|
+ img = d[2]
|
|
242
|
+
|
|
243
|
+ name = get_first_capitalized_word(d[1])
|
|
244
|
+
|
|
245
|
+ # print weather description text
|
|
246
|
+ self.t_sub.setText(name, "tom-thumb")
|
|
247
|
+ self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 1 + 2)
|
|
248
|
+ #self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 2)
|
|
249
|
+ #self.t_sub.draw(self.gui.width, -self.gui.height / 2 + 5 + 6 * 3)
|
|
250
|
+ #self.t_sub.draw(self.gui.width * 2, -self.gui.height / 2 + 5 + 6 * 4)
|
|
251
|
+
|
|
252
|
+ # show image if it exists
|
|
253
|
+ if img != None:
|
|
254
|
+ img.draw()
|
|
255
|
+
|
|
256
|
+ # id of weather / image
|
|
257
|
+ self.t_aux.setText("{}".format(int(val)), "tom-thumb")
|
|
258
|
+ self.t_aux.draw(0, -self.gui.height / 2 + 5 + 6 * 9 + 3)
|
158
|
259
|
|
159
|
260
|
def draw_temperature(self):
|
160
|
261
|
# heading
|
|
@@ -171,8 +272,10 @@ class WeatherScreen:
|
171
|
272
|
|
172
|
273
|
def draw_cloud_cover(self):
|
173
|
274
|
# heading
|
174
|
|
- self.t_head.setText("Clouds:", "lemon")
|
|
275
|
+ self.t_head.setText("Cloud", "lemon")
|
175
|
276
|
self.t_head.draw(3, -self.gui.height / 2 + 7)
|
|
277
|
+ self.t_sub.setText("Coverage:", "lemon")
|
|
278
|
+ self.t_sub.draw(3, -self.gui.height / 2 + 20)
|
176
|
279
|
|
177
|
280
|
val = self.data.filter(polars.col("parameter") == self.params[2])[0]["value"][0]
|
178
|
281
|
self.t_val.setText("{:.1f} %".format(val), "tom-thumb")
|
|
@@ -196,13 +299,15 @@ class WeatherScreen:
|
196
|
299
|
# advance to next screen after time has passed
|
197
|
300
|
if (time.time() - self.last) >= self.timestep:
|
198
|
301
|
self.state = (self.state + 1) % self.num_state
|
|
302
|
+ if self.state == 0:
|
|
303
|
+ self.done = True
|
199
|
304
|
self.last = time.time()
|
200
|
305
|
|
201
|
306
|
# draw progress bar on bottom most row
|
202
|
307
|
elapsed = (time.time() - self.last)
|
203
|
308
|
ratio = elapsed / self.timestep
|
204
|
|
- for i in range(0, int(ratio * self.gui.width)):
|
205
|
|
- self.gui.set_pixel(i, self.gui.height - 1, (255, 0, 0))
|
|
309
|
+ for i in range(0, int(ratio * self.gui.width) + 1):
|
|
310
|
+ self.gui.set_pixel(i, self.gui.height - 1, (0, 255, 0))
|
206
|
311
|
|
207
|
312
|
if __name__ == "__main__":
|
208
|
313
|
from config import Config
|
|
@@ -210,5 +315,5 @@ if __name__ == "__main__":
|
210
|
315
|
i = util.getInput()
|
211
|
316
|
t = util.getTarget(i)
|
212
|
317
|
|
213
|
|
- s = WeatherScreen(t, i, Config.weather_latlon, 2.0, 60.0 * 10.0)
|
|
318
|
+ s = WeatherScreen(t, i, Config.weather_latlon, 5.0, 60.0 * 10.0)
|
214
|
319
|
util.loop(t, s.draw)
|