Initial commit

This commit is contained in:
2026-08-01 23:38:09 +02:00
parent 0d9cca3668
commit a99b986544
28 changed files with 1476 additions and 1 deletions
+128
View File
@@ -0,0 +1,128 @@
#include "home_screen.h"
#include <M5Stack.h>
#include "../../include/theme.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; // 10 minutes
String formatEventTime(const CalendarEvent &ev) {
// Times are shown exactly as provided by the API, no timezone math.
if (ev.allDay) {
// start_at looks like "2026-08-03T00:00:00" -> show date part only
int tIdx = ev.startAt.indexOf('T');
return tIdx > 0 ? ev.startAt.substring(0, tIdx) : ev.startAt;
} else {
int tIdx = ev.startAt.indexOf('T');
if (tIdx > 0 && ev.startAt.length() >= tIdx + 6) {
return ev.startAt.substring(tIdx + 1, tIdx + 6); // HH:MM
}
return ev.startAt;
}
}
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);
// --- Weather block (top) ---
if (weatherOk) {
Icons::drawWeatherIcon(lastWeather.current.symbol, 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(lastWeather.current.description);
if (willRainSoon(lastWeather, 8)) {
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);
// --- Calendar block (next 2 events) ---
M5.Lcd.setTextColor(Theme::TEXT, Theme::BG);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(10, 105);
Icons::drawCalendarIcon(20, 115, 14);
M5.Lcd.setCursor(35, 108);
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(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(formatEventTime(ev));
y += 40;
shown++;
}
} else {
drawErrorState(20, 150, "Kalender n.a.");
}
// --- Footer hint ---
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");
}