// Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de) - MIT License #include "home_screen.h" #include #include "../../include/theme.h" #include "../../include/text_utils.h" #include "../../include/date_utils.h" #include "../icons/icons.h" #include "../api/weather_api.h" #include "../api/calendar_api.h" namespace { WeatherData lastWeather; CalendarData lastCalendar; bool weatherOk = false; bool calendarOk = false; unsigned long lastFetchMs = 0; const unsigned long REFRESH_INTERVAL_MS = 10UL * 60UL * 1000UL; void doFetch() { WeatherData w = fetchWeather(); weatherOk = w.valid; if (w.valid) lastWeather = w; CalendarData c = fetchCalendar(); calendarOk = c.valid; if (c.valid) lastCalendar = c; lastFetchMs = millis(); } void drawErrorState(int x, int y, const char *label) { Icons::drawRetryIcon(x, y, 10); M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setCursor(x + 20, y - 5); M5.Lcd.print(label); } } void updateHomeScreen() { if (lastFetchMs == 0 || millis() - lastFetchMs >= REFRESH_INTERVAL_MS) doFetch(); } void renderHomeScreen(bool forceRefresh) { if (forceRefresh || lastFetchMs == 0) doFetch(); M5.Lcd.fillScreen(Theme::BG); if (weatherOk) { Icons::drawWeatherIcon(lastWeather.current.symbol, lastWeather.current.description, 45, 55, 24); M5.Lcd.setTextColor(Theme::TEXT, Theme::BG); M5.Lcd.setTextSize(4); M5.Lcd.setCursor(90, 30); M5.Lcd.printf("%d", lastWeather.current.temperature); M5.Lcd.setTextSize(2); M5.Lcd.print(" C"); M5.Lcd.setTextSize(2); M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setCursor(90, 65); M5.Lcd.print(sanitizeGermanText(lastWeather.current.description)); if (lastWeather.willRainSoon) { Icons::drawRainWarning(280, 30); M5.Lcd.setTextColor(Theme::ACCENT_RAIN, Theme::BG); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(220, 45); M5.Lcd.print("Regen moeglich"); } } else { drawErrorState(20, 40, "Wetter n.a."); } M5.Lcd.drawFastHLine(10, 95, Theme::SCREEN_W - 20, Theme::BG_CARD); Icons::drawCalendarIcon(20, 112, 16); M5.Lcd.setTextColor(Theme::TEXT, Theme::BG); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(38, 104); M5.Lcd.print("Termine"); if (calendarOk) { int y = 135; int shown = 0; for (const auto &ev : lastCalendar.events) { if (shown >= 2) break; M5.Lcd.setTextColor(Theme::TEXT, Theme::BG); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(10, y); M5.Lcd.print(sanitizeGermanText(ev.summary.substring(0, 20))); M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(10, y + 20); M5.Lcd.print(DateUtils::formatShortDE(ev.startAt, ev.allDay)); y += 42; shown++; } } else { drawErrorState(20, 150, "Kalender n.a."); } M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(10, 225); M5.Lcd.print("A:Wetter/Kalender B:Home C:MVG"); }