167 lines
5.5 KiB
C
167 lines
5.5 KiB
C
/*
|
|
* 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 <inttypes.h>
|
|
#include <time.h>
|
|
#include <err.h>
|
|
|
|
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;
|
|
}
|