Skip to content

Commit 4b29f87

Browse files
committed
Add Milwaukee weather screensaver
1 parent 45e890b commit 4b29f87

2 files changed

Lines changed: 107 additions & 3 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ The small board-support components in `components/` come from M5Stack's Apache-2
5656
- [x] SPIFFS/microSD file browser
5757
- [x] Notes, counter, and system apps
5858
- [x] Internet-synced RTC clock with persistent daily alarms and snooze
59-
- [x] Global weather with location search, current conditions, hourly and 7-day forecasts
59+
- [x] Milwaukee-default global weather plus an idle weather/time/date screensaver
6060
- [x] GPIO control and eight-channel ADC oscilloscope
6161
- [x] Wi-Fi settings
6262
- [x] AI chat client through an authenticated HTTPS relay

‎main/main.c‎

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#define ALARM_COUNT 3
7070
#define WEATHER_HOURS 12
7171
#define WEATHER_DAYS 7
72+
#define SCREENSAVER_IDLE_MS (2 * 60 * 1000)
7273
#define TIME_ZONE "CST6CDT,M3.2.0,M11.1.0"
7374

7475
typedef struct __attribute__((packed)) {
@@ -377,10 +378,16 @@ static volatile bool weather_done;
377378
static bool weather_ok;
378379
static bool weather_keyboard_visible;
379380
static bool weather_has_data;
380-
static char weather_location[64] = "Chicago";
381+
static char weather_location[64] = "Milwaukee, Wisconsin";
381382
static char weather_pending_location[64];
382383
static char weather_error[96];
383384
static weather_data_t weather_data;
385+
static time_t weather_fetched_at;
386+
static lv_obj_t *screensaver;
387+
static lv_obj_t *screensaver_panel;
388+
static lv_obj_t *screensaver_time;
389+
static lv_obj_t *screensaver_date;
390+
static lv_obj_t *screensaver_weather;
384391

385392
static void show_launcher(void);
386393
static void show_files(const char *path);
@@ -392,6 +399,7 @@ static void show_clock(void);
392399
static void show_gpio(void);
393400
static void show_scope(void);
394401
static void show_weather(void);
402+
static void weather_start(const char *location);
395403
static void clear_content(void);
396404
static void browser_link_clicked(lv_event_t *event);
397405
static lv_obj_t *button(lv_obj_t *parent, const char *text, lv_event_cb_t callback);
@@ -1387,9 +1395,17 @@ static bool weather_parse_forecast(const char *json, weather_data_t *data)
13871395
static void load_weather_location(void)
13881396
{
13891397
nvs_handle_t handle;
1390-
if (nvs_open("tab5", NVS_READONLY, &handle) != ESP_OK) return;
1398+
if (nvs_open("tab5", NVS_READWRITE, &handle) != ESP_OK) return;
13911399
size_t size = sizeof(weather_location);
13921400
nvs_get_str(handle, "weather_loc", weather_location, &size);
1401+
uint8_t migrated = 0;
1402+
if (nvs_get_u8(handle, "weather_mke", &migrated) != ESP_OK) {
1403+
if (strcmp(weather_location, "Chicago") == 0)
1404+
snprintf(weather_location, sizeof(weather_location), "Milwaukee, Wisconsin");
1405+
nvs_set_str(handle, "weather_loc", weather_location);
1406+
nvs_set_u8(handle, "weather_mke", 1);
1407+
nvs_commit(handle);
1408+
}
13931409
nvs_close(handle);
13941410
}
13951411

@@ -1451,6 +1467,7 @@ static void weather_task(void *argument)
14511467
}
14521468
weather_data = next;
14531469
weather_has_data = true;
1470+
weather_fetched_at = time(NULL);
14541471
weather_ok = true;
14551472
snprintf(weather_location, sizeof(weather_location), "%s", weather_pending_location);
14561473
save_weather_location();
@@ -3596,6 +3613,92 @@ static void weather_clicked(lv_event_t *event)
35963613
show_weather();
35973614
}
35983615

3616+
static void screensaver_close(void)
3617+
{
3618+
if (!screensaver) return;
3619+
lv_obj_delete_async(screensaver);
3620+
screensaver = screensaver_panel = screensaver_time = screensaver_date = screensaver_weather = NULL;
3621+
}
3622+
3623+
static void screensaver_touched(lv_event_t *event)
3624+
{
3625+
(void)event;
3626+
screensaver_close();
3627+
}
3628+
3629+
static void screensaver_update(void)
3630+
{
3631+
if (!screensaver) return;
3632+
time_t now = time(NULL);
3633+
struct tm local;
3634+
localtime_r(&now, &local);
3635+
char text[48];
3636+
strftime(text, sizeof(text), "%I:%M %p", &local);
3637+
if (text[0] == '0') memmove(text, text + 1, strlen(text));
3638+
lv_label_set_text(screensaver_time, text);
3639+
strftime(text, sizeof(text), "%A, %B %d, %Y", &local);
3640+
lv_label_set_text(screensaver_date, text);
3641+
if (weather_has_data) {
3642+
lv_label_set_text_fmt(screensaver_weather, "%d F\n%s\n%s\n\nBAT %d%%",
3643+
weather_round(weather_data.temperature), weather_condition(weather_data.code),
3644+
weather_data.place, battery_percent);
3645+
} else {
3646+
lv_label_set_text(screensaver_weather, wifi_connected ? "Loading Milwaukee weather..." :
3647+
"Milwaukee weather needs Wi-Fi");
3648+
}
3649+
static const int16_t offsets[][2] = {{-45, -70}, {45, -35}, {-30, 15}, {35, 60}};
3650+
size_t position = local.tm_min % (sizeof(offsets) / sizeof(offsets[0]));
3651+
lv_obj_align(screensaver_panel, LV_ALIGN_CENTER, offsets[position][0], offsets[position][1]);
3652+
}
3653+
3654+
static void screensaver_show(void)
3655+
{
3656+
if (screensaver) return;
3657+
screensaver = lv_obj_create(lv_layer_top());
3658+
lv_obj_set_size(screensaver, SCREEN_WIDTH, SCREEN_HEIGHT);
3659+
lv_obj_align(screensaver, LV_ALIGN_CENTER, 0, 0);
3660+
lv_obj_clear_flag(screensaver, LV_OBJ_FLAG_SCROLLABLE);
3661+
lv_obj_add_flag(screensaver, LV_OBJ_FLAG_CLICKABLE);
3662+
lv_obj_set_style_bg_color(screensaver, lv_color_hex(0x080b12), 0);
3663+
lv_obj_set_style_bg_opa(screensaver, LV_OPA_COVER, 0);
3664+
lv_obj_set_style_border_width(screensaver, 0, 0);
3665+
lv_obj_set_style_radius(screensaver, 0, 0);
3666+
lv_obj_set_style_text_color(screensaver, lv_color_white(), 0);
3667+
lv_obj_add_event_cb(screensaver, screensaver_touched, LV_EVENT_PRESSED, NULL);
3668+
3669+
screensaver_panel = lv_obj_create(screensaver);
3670+
lv_obj_remove_style_all(screensaver_panel);
3671+
lv_obj_set_size(screensaver_panel, 620, 650);
3672+
lv_obj_set_flex_flow(screensaver_panel, LV_FLEX_FLOW_COLUMN);
3673+
lv_obj_set_flex_align(screensaver_panel, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
3674+
lv_obj_set_style_pad_row(screensaver_panel, 28, 0);
3675+
screensaver_time = lv_label_create(screensaver_panel);
3676+
lv_obj_set_style_text_font(screensaver_time, &lv_font_montserrat_48, 0);
3677+
screensaver_date = lv_label_create(screensaver_panel);
3678+
lv_obj_set_style_text_font(screensaver_date, &lv_font_montserrat_28, 0);
3679+
screensaver_weather = lv_label_create(screensaver_panel);
3680+
lv_obj_set_width(screensaver_weather, 600);
3681+
lv_obj_set_style_text_font(screensaver_weather, &lv_font_montserrat_28, 0);
3682+
lv_obj_set_style_text_align(screensaver_weather, LV_TEXT_ALIGN_CENTER, 0);
3683+
lv_obj_t *source = lv_label_create(screensaver_panel);
3684+
lv_label_set_text(source, "Weather data: Open-Meteo | Touch to wake");
3685+
screensaver_update();
3686+
if (wifi_connected && (!weather_has_data || time(NULL) - weather_fetched_at > 15 * 60))
3687+
weather_start(weather_location);
3688+
}
3689+
3690+
static void screensaver_tick(lv_timer_t *timer)
3691+
{
3692+
(void)timer;
3693+
uint32_t inactive = lv_display_get_inactive_time(NULL);
3694+
if (screensaver) {
3695+
if (inactive < 1000 || alarm_active) screensaver_close();
3696+
else screensaver_update();
3697+
} else if (!alarm_active && inactive >= SCREENSAVER_IDLE_MS) {
3698+
screensaver_show();
3699+
}
3700+
}
3701+
35993702
static void show_launcher(void)
36003703
{
36013704
static int32_t columns[] = {
@@ -3684,6 +3787,7 @@ void app_main(void)
36843787
lv_timer_create(battery_tick, 5000, NULL);
36853788
clock_tick(NULL);
36863789
lv_timer_create(clock_tick, 1000, NULL);
3790+
lv_timer_create(screensaver_tick, 1000, NULL);
36873791

36883792
content = lv_obj_create(screen);
36893793
lv_obj_set_size(content, 720, 1180);

0 commit comments

Comments
 (0)