rpi4b-temp-humidity/src/ui/datapoints.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;
}