Python RGB Matrix games and animations https://www.xythobuz.de/ledmatrix_v2.html
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

weather.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #!/usr/bin/env python3
  2. # ----------------------------------------------------------------------------
  3. # "THE BEER-WARE LICENSE" (Revision 42):
  4. # <xythobuz@xythobuz.de> wrote this file. As long as you retain this notice
  5. # you can do whatever you want with this stuff. If we meet some day, and you
  6. # think this stuff is worth it, you can buy me a beer in return. Thomas Buck
  7. # ----------------------------------------------------------------------------
  8. import util
  9. import time
  10. from datetime import datetime, timezone, timedelta
  11. from wetterdienst import Settings
  12. from wetterdienst.provider.dwd.mosmix import (
  13. DwdForecastDate,
  14. DwdMosmixRequest,
  15. DwdMosmixType,
  16. )
  17. import polars
  18. class WeatherScreen:
  19. def __init__(self, g, i, latlon, timestep = 5.0, refresh = (60.0 * 60.0)):
  20. self.gui = g
  21. self.input = i
  22. self.latlon = latlon
  23. self.timestep = timestep
  24. DrawText = util.getTextDrawer()
  25. self.t_head = DrawText(self.gui, (255, 255, 255), (0, 0, 0))
  26. self.t_sub = DrawText(self.gui, (0, 255, 255), (0, 0, 0))
  27. self.t_val = DrawText(self.gui, (255, 0, 255), (0, 0, 0))
  28. self.t_aux = DrawText(self.gui, (255, 255, 0), (0, 0, 0))
  29. self.params = [
  30. "weather_significant",
  31. "temperature_air_mean_200",
  32. "cloud_cover_effective",
  33. ]
  34. self.num_state = len(self.params) + 1
  35. self.find_station()
  36. self.restart()
  37. def restart(self):
  38. self.state = 0
  39. self.old_keys = {
  40. "left": False,
  41. "right": False,
  42. "up": False,
  43. "down": False,
  44. "a": False,
  45. "b": False,
  46. "x": False,
  47. "y": False,
  48. "l": False,
  49. "r": False,
  50. "start": False,
  51. "select": False,
  52. }
  53. self.last = time.time()
  54. def find_station(self):
  55. settings = Settings(ts_shape=True, ts_humanize=True)
  56. request = DwdMosmixRequest(
  57. parameter=self.params,
  58. start_issue=DwdForecastDate.LATEST,
  59. mosmix_type=DwdMosmixType.LARGE,
  60. settings=settings,
  61. )
  62. stations = request.filter_by_distance(latlon=self.latlon, distance=30)
  63. self.station = stations.df[0]
  64. print("Found station '{}' ({}) in {:.2f} km distance".format(
  65. self.station["name"][0],
  66. self.station["station_id"][0],
  67. self.station["distance"][0]
  68. ))
  69. self.forecast = request.filter_by_station_id(station_id=[
  70. self.station["station_id"][0],
  71. ])
  72. self.parse_forecast()
  73. def get_forecast(self):
  74. settings = Settings(ts_shape=True, ts_humanize=True)
  75. request = DwdMosmixRequest(
  76. parameter=self.params,
  77. start_issue=DwdForecastDate.LATEST,
  78. mosmix_type=DwdMosmixType.LARGE,
  79. settings=settings,
  80. )
  81. self.forecast = request.filter_by_station_id(station_id=[self.station["station_id"][0]])
  82. self.parse_forecast()
  83. def parse_forecast(self):
  84. self.last_forecast = time.time()
  85. response = next(self.forecast.values.query())
  86. response_subset = response.df.select(["date", "parameter", "value"])
  87. # only datapoints from -1h to +12h from now
  88. start_time = datetime.now(timezone.utc) - timedelta(hours=1)
  89. end_time = datetime.now(timezone.utc) + timedelta(hours=12)
  90. self.data = response_subset.filter((polars.col("date") >= start_time) & (polars.col("date") <= end_time))
  91. #print(self.data)
  92. #for p in self.params:
  93. # print(self.data.filter(polars.col("parameter") == p)[0])
  94. #for i in range(0, len(self.data)):
  95. # print(self.data[i])
  96. def buttons(self):
  97. keys = self.input.get()
  98. if keys["up"] and (not self.old_keys["up"]) and (not self.old_keys["select"]):
  99. self.state = (self.state + 1) % self.num_state
  100. self.last = time.time()
  101. elif keys["down"] and (not self.old_keys["select"]):
  102. self.state = (self.state - 1) % self.num_state
  103. self.last = time.time()
  104. self.old_keys = keys.copy()
  105. def finished(self):
  106. return False # TODO
  107. def draw_station_info(self):
  108. # heading
  109. self.t_head.setText("Weather:", "lemon")
  110. self.t_head.draw(3, -self.gui.height / 2 + 7)
  111. # station info (2 lines)
  112. self.t_sub.setText(self.station["name"][0], "tom-thumb")
  113. self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 2)
  114. self.t_sub.draw(self.gui.width, -self.gui.height / 2 + 5 + 6 * 3)
  115. # distance
  116. self.t_val.setText("Distance:", "tom-thumb")
  117. self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 5)
  118. self.t_val.setText("{:.2f} km".format(self.station["distance"][0]), "tom-thumb")
  119. self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 6)
  120. # lat lon
  121. self.t_aux.setText("Lat: {:.2f}".format(self.station["latitude"][0]), "tom-thumb")
  122. self.t_aux.draw(0, -self.gui.height / 2 + 5 + 6 * 8)
  123. self.t_aux.setText("Lon: {:.2f}".format(self.station["longitude"][0]), "tom-thumb")
  124. self.t_aux.draw(0, -self.gui.height / 2 + 5 + 6 * 9)
  125. def draw_weather(self):
  126. # heading
  127. self.t_head.setText("Weather:", "lemon")
  128. self.t_head.draw(3, -self.gui.height / 2 + 7)
  129. val = self.data.filter(polars.col("parameter") == self.params[0])[0]["value"][0]
  130. self.t_val.setText("{:.0f}".format(val), "tom-thumb")
  131. self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 5)
  132. def draw_temperature(self):
  133. # heading
  134. self.t_head.setText("Temps:", "lemon")
  135. self.t_head.draw(3, -self.gui.height / 2 + 7)
  136. # current temperature
  137. self.t_sub.setText("Current:", "tom-thumb")
  138. self.t_sub.draw(0, -self.gui.height / 2 + 5 + 6 * 2)
  139. val = self.data.filter(polars.col("parameter") == self.params[1])[0]["value"][0]
  140. val = val - 273.15 # kelvin to celsius
  141. self.t_val.setText("{:.1f} °C".format(val), "tom-thumb")
  142. self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 3)
  143. def draw_cloud_cover(self):
  144. # heading
  145. self.t_head.setText("Clouds:", "lemon")
  146. self.t_head.draw(3, -self.gui.height / 2 + 7)
  147. val = self.data.filter(polars.col("parameter") == self.params[2])[0]["value"][0]
  148. self.t_val.setText("{:.1f} %".format(val), "tom-thumb")
  149. self.t_val.draw(0, -self.gui.height / 2 + 5 + 6 * 5)
  150. def draw(self):
  151. # handle button input
  152. if self.input != None:
  153. self.buttons()
  154. # draw screen contents
  155. if self.state == 0:
  156. self.draw_station_info()
  157. elif self.state == 1:
  158. self.draw_weather()
  159. elif self.state == 2:
  160. self.draw_temperature()
  161. elif self.state == 3:
  162. self.draw_cloud_cover()
  163. # advance to next screen after time has passed
  164. if (time.time() - self.last) >= self.timestep:
  165. self.state = (self.state + 1) % self.num_state
  166. self.last = time.time()
  167. # draw progress bar on bottom most row
  168. elapsed = (time.time() - self.last)
  169. ratio = elapsed / self.timestep
  170. for i in range(0, int(ratio * self.gui.width)):
  171. self.gui.set_pixel(i, self.gui.height - 1, (255, 0, 0))
  172. if __name__ == "__main__":
  173. from config import Config
  174. i = util.getInput()
  175. t = util.getTarget(i)
  176. s = WeatherScreen(t, i, Config.weather_latlon, 2.0, 60.0 * 10.0)
  177. util.loop(t, s.draw)