/* * datapoints.c - Screen for viewing individual data points * Copyright (C) 2024 Alexander Rosenberg * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. See the LICENSE file for more information. */ #include "datapoints.h" #include #include #include static bool data_points_select_date(DataPointsScreen *screen, SensorState *state) { if (state->up_down || state->down_down || state->sel_down || state->back_down) { screen->need_redraw = true; } if (screen->need_redraw) { screen->need_redraw = false; DateSelectionState dss = date_sel_dispatch(&screen->ds, state, "Date:"); switch (dss) { case DATE_SEL_CONTINUE: break; // ignore case DATE_SEL_DONE: ++screen->stage; screen->need_redraw = true; break; case DATE_SEL_BACK: case DATE_SEL_ERROR: screen->need_redraw = true; date_sel_reset(&screen->ds); time_sel_reset(&screen->ts); return true; } } return false; } static void data_points_calculate_initial_time(DataPointsScreen *screen) { struct tm broken_time = { .tm_sec = 0, .tm_min = screen->ts.minute, .tm_hour = screen->ts.hour, .tm_mday = screen->ds.day, .tm_mon = screen->ds.month - 1, .tm_year = screen->ds.year - 1900, .tm_isdst = -1, }; time_t it = mktime(&broken_time); if (it == -1) { warnx("could not convert selected date and time"); screen->cur_point = 0; } else { screen->cur_point = it; } } static void data_points_select_time(DataPointsScreen *screen, SensorState *state) { if (state->up_down || state->down_down || state->sel_down || state->back_down) { screen->need_redraw = true; } if (screen->need_redraw) { screen->need_redraw = false; TimeSelState tss = time_sel_dispatch(&screen->ts, state, "Time:"); switch (tss) { case TIME_SEL_CONTINUE: break; // ignore case TIME_SEL_DONE: ++screen->stage; screen->need_redraw = true; data_points_calculate_initial_time(screen); break; case TIME_SEL_BACK: case TIME_SEL_ERROR: screen->need_redraw = true; --screen->stage; } } } static void data_points_show(DataPointsScreen *screen, SensorState *state) { if (state->back_down) { screen->stage = DP_STAGE_DATE; screen->ds.stage = DATE_SEL_YEAR; screen->ts.stage = TS_STAGE_HOUR; screen->need_redraw = true; return; } if (state->up_down || state->down_down) { screen->need_redraw = true; } if (screen->need_redraw) { screen->need_redraw = false; UtilDataPointInfo info; if (!get_data_point_info(state->db, screen->cur_point, &info)) { warnx("could not get info for data point: %" PRIi64 "", screen->cur_point); screen->stage = DP_STAGE_DATE; screen->need_redraw = true; return; } screen->cur_point = info.time; int temp = info.temp; int humid = info.humid; if (state->up_down && info.has_next) { screen->cur_point = info.next_time; temp = info.next_temp; humid = info.next_humid; } else if (state->down_down && info.has_prev) { screen->cur_point = info.prev_time; temp = info.prev_temp; humid = info.prev_humid; } struct tm broken_time; localtime_r(&screen->cur_point, &broken_time); char str_time[17]; if (!strftime(str_time, 17, "%y/%m/%d %H:%M", &broken_time)) { warnx("could not format time: %" PRIi64 "", screen->cur_point); screen->stage = DP_STAGE_DATE; screen->need_redraw = true; return; } lcd_clear(state->lcd); lcd_move_to(state->lcd, 0, 0); lcd_write_string(state->lcd, str_time); char data_line[17]; snprintf(data_line, 17, "%02ds %.1f%c %d%%", broken_time.tm_sec, convert_temperature(temp), GLOBAL_OPTS.temp_unit, humid); lcd_move_to(state->lcd, 1, 0); lcd_write_string(state->lcd, data_line); } } static bool data_points_screen_dispatch(DataPointsScreen *screen, SensorState *state) { if (state->force_draw) { screen->need_redraw = true; } switch (screen->stage) { case DP_STAGE_DATE: return data_points_select_date(screen, state); case DP_STAGE_TIME: data_points_select_time(screen, state); return false; case DP_STAGE_SHOW: data_points_show(screen, state); return false; default: warnx("Attempt to show bad data points screen stage"); return true; } } DataPointsScreen *data_points_screen_new() { DataPointsScreen *s = malloc_checked(sizeof(DataPointsScreen)); screen_init(&s->parent, "Data points", (ScreenDispatchFunc) data_points_screen_dispatch, (ScreenCleanupFunc) free); s->need_redraw = true; s->stage = DP_STAGE_DATE; date_sel_init(&s->ds, PERIOD_DAY); time_sel_init(&s->ts, &s->ds, false); return s; }