PicoWeatherDisplay/weather_display.py

228 lines
8.9 KiB
Python

import time
class WeatherDisplay:
def __init__(self, display):
self.display = display
self.text_padding = 4
self.last_displayed_data = None
self.time_update_running = False
self.time_thread = None
def weathercode_to_text(self, weathercode):
if weathercode == 0:
return 'Clear Sky'
elif weathercode == 1:
return 'Mainly Clear'
elif weathercode == 2:
return 'Partly Cloudy'
elif weathercode == 3:
return 'Overcast'
elif weathercode in [45, 48]:
return 'Foggy'
elif weathercode in [51, 53, 55]:
return 'Light Rain'
elif weathercode in [56, 57]:
return 'Freezing Rain'
elif weathercode in [61, 63, 65]:
return 'Moderate Rain'
elif weathercode in [66, 67]:
return 'Heavy Rain'
elif weathercode in [71, 73, 75]:
return 'Snow Fall'
elif weathercode == 77:
return 'Snow Grains'
elif weathercode in [80, 81, 82]:
return 'Rain Showers'
elif weathercode in [85, 86]:
return 'Snow Showers'
elif weathercode == 95:
return 'Thunderstorm'
elif weathercode in [96, 99]:
return 'Thunderstorm with Hail'
else:
return 'Unknown Weather'
if force_full_update:
self.display.clear()
else:
# Create a clean buffer but don't send to display yet
self.display.fill(self.display.black)
text_x = self.text_padding
text_y = 8
update_regions = []
temp_text = f"Temp: {weather_data.get('max_temp', 0):.0f}/{weather_data.get('min_temp', 0):.0f}C"
if force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('max_temp') != weather_data.get('max_temp') or \
self.last_displayed_data.get('miget_wen_temp') != weather_data.get('min_temp'):
self.display.text(temp_text, text_x, text_y)
update_regions.append((0, text_y, 16, text_y + 8))
weathercode = weather_data.get('weathercode', 0)
weather_text = self.weathercode_to_text(weathercode)
if force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('weathercode') != weathercode:
self.display.text(f"{weather_text}", text_x, text_y + 12)
update_regions.append((0, text_y + 12, 16, text_y + 20))
precip_text = f"Precip: {weather_data.get('precip_mm', 0):.1f}mm"
if force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('precip_mm') != weather_data.get('precip_mm'):
self.display.text(precip_text, text_x, text_y + 24)
update_regions.append((0, text_y + 24, 16, text_y + 32))
date_text = weather_data.get('date', '')
if date_text and len(date_text) >= 10:
year = date_text[0:4]
month = date_text[5:7]
day = date_text[8:10]
date_text = f"{day}-{month}-{year}"
if force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('date') != weather_data.get('date'):
self.display.text(f"Date: {date_text}", text_x, text_y + 36)
update_regions.append((0, text_y + 36, 16, text_y + 44))
self.last_displayed_data = dict(weather_data)
self.last_displayed_data['view_type'] = 'detailed'
if force_full_update:
self.display.show()
else:
if update_regions:
min_y = min(region[1] for region in update_regions)
max_y = max(region[3] for region in update_regions)
self.display.show(0, min_y, 16, max_y)
else:
pass
def display_weather(self, weather_data):
"""Detailed view with max/min temps, description, precip, date."""
if 'daily' in weather_data:
d = weather_data['daily']
weather_data = {
'max_temp': d['temperature_2m_max'][0],
'min_temp': d['temperature_2m_min'][0],
'weathercode':d['weathercode'][0],
'precip_mm': d['precipitation_sum'][0],
'date': d['time'][0],
}
force_full_update = (
self.last_displayed_data is None or
self.last_displayed_data.get('view_type') != 'detailed'
)
if force_full_update:
self.display.clear()
else:
self.display.fill(self.display.black)
text_x = self.text_padding
text_y = 8
update_regions = []
temp_text = f"Temp: {weather_data.get('max_temp', 0):.0f}/" \
f"{weather_data.get('min_temp', 0):.0f}C"
if (force_full_update
or self.last_displayed_data.get('max_temp') != weather_data.get('max_temp')
or self.last_displayed_data.get('min_temp') != weather_data.get('min_temp')
):
self.display.text(temp_text, text_x, text_y)
update_regions.append((text_y, text_y + 8))
code = weather_data.get('weathercode', 0)
desc = self.weathercode_to_text(code)
if (force_full_update
or self.last_displayed_data.get('weathercode') != code
):
self.display.text(desc, text_x, text_y + 12)
update_regions.append((text_y + 12, text_y + 20))
precip = f"Precip: {weather_data.get('precip_mm', 0):.1f}mm"
if (force_full_update
or self.last_displayed_data.get('precip_mm') != weather_data.get('precip_mm')
):
self.display.text(precip, text_x, text_y + 24)
update_regions.append((text_y + 24, text_y + 32))
raw_date = weather_data.get('date', '')
if raw_date and len(raw_date) >= 10:
dd = raw_date[8:10]; mm = raw_date[5:7]; yyyy = raw_date[0:4]
formatted = f"Date: {dd}-{mm}-{yyyy}"
if (force_full_update
or self.last_displayed_data.get('date') != raw_date
):
self.display.text(formatted, text_x, text_y + 36)
update_regions.append((text_y + 36, text_y + 44))
self.last_displayed_data = dict(weather_data)
self.last_displayed_data['view_type'] = 'detailed'
if force_full_update:
self.display.show()
return
if update_regions:
min_y = min(r[0] for r in update_regions)
max_y = max(r[1] for r in update_regions)
page_count = self.display.height // 8
self.display.show(1, min_y, page_count, max_y)
def display_simple_weather(self, weather_data):
force_full_update = self.last_displayed_data is None or self.last_displayed_data.get('view_type') != 'simple'
if force_full_update:
self.display.clear()
else:
self.display.fill(self.display.black)
text_x = self.text_padding
center_y = self.display.height // 2
update_regions = []
temp_text = f"{weather_data.get('current_temp', 0):.0f}C"
if force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('current_temp') != weather_data.get('current_temp'):
self.display.text(temp_text, text_x, center_y - 8, scale=2)
update_regions.append((0, center_y - 8, 16, center_y + 8)) # Scaled text is 16px high
weather_desc = self.weathercode_to_text(weather_data.get('weathercode', 0))
if force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('weathercode') != weather_data.get('weathercode'):
self.display.text(weather_desc, text_x, center_y + 12)
update_regions.append((0, center_y + 12, 16, center_y + 20))
current_time_tuple = time.localtime(time.time())
current_time = f"{current_time_tuple[3]:02d}:{current_time_tuple[4]:02d}:{current_time_tuple[5]:02d}"
if current_time and (force_full_update or not self.last_displayed_data or \
self.last_displayed_data.get('current_time') != current_time):
self.display.text(current_time, text_x, center_y + 24)
update_regions.append((0, center_y + 24, 16, center_y + 32))
self.last_displayed_data = dict(weather_data)
self.last_displayed_data['view_type'] = 'simple'
if force_full_update:
self.display.show()
else:
if update_regions:
min_y = min(region[1] for region in update_regions)
max_y = max(region[3] for region in update_regions)
self.display.show(0, min_y, 16, max_y)
else:
pass
def reset_display(self):
"""Clear display and reset last displayed data."""
self.display.clear()
self.display.show()
self.last_displayed_data = None