Work on date selection
This commit is contained in:
parent
da83874d11
commit
c0e51c13ed
@ -48,6 +48,8 @@ static void lcd_pulse_enable(LCD *lcd) {
|
|||||||
LCD *lcd_open(gpio_handle_t handle, gpio_pin_t rs, gpio_pin_t rw, gpio_pin_t en,
|
LCD *lcd_open(gpio_handle_t handle, gpio_pin_t rs, gpio_pin_t rw, gpio_pin_t en,
|
||||||
gpio_pin_t d0, gpio_pin_t d1, gpio_pin_t d2, gpio_pin_t d3,
|
gpio_pin_t d0, gpio_pin_t d1, gpio_pin_t d2, gpio_pin_t d3,
|
||||||
gpio_pin_t d4, gpio_pin_t d5, gpio_pin_t d6, gpio_pin_t d7) {
|
gpio_pin_t d4, gpio_pin_t d5, gpio_pin_t d6, gpio_pin_t d7) {
|
||||||
|
LOG_VERBOSE("Initializing LCD: rs=%d, rw=%d, en=%d, d={%d, %d, %d, %d, %d, "
|
||||||
|
"%d, %d, %d}\n", rs, rw, en, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||||
LCD *lcd = malloc_checked(sizeof(LCD));
|
LCD *lcd = malloc_checked(sizeof(LCD));
|
||||||
lcd->handle = handle;
|
lcd->handle = handle;
|
||||||
lcd->rs = rs;
|
lcd->rs = rs;
|
||||||
@ -68,8 +70,7 @@ LCD *lcd_open(gpio_handle_t handle, gpio_pin_t rs, gpio_pin_t rw, gpio_pin_t en,
|
|||||||
lcd_call(lcd, 0, 0, 0, 0, 1, 1, 1, 0, 0); // 5x8 font, 2 lines, 8bit
|
lcd_call(lcd, 0, 0, 0, 0, 1, 1, 1, 0, 0); // 5x8 font, 2 lines, 8bit
|
||||||
lcd_entry_mode(lcd, LCD_INCREMENT, LCD_CURSOR_MOVE);
|
lcd_entry_mode(lcd, LCD_INCREMENT, LCD_CURSOR_MOVE);
|
||||||
lcd_display_control(lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF, LCD_DISPLAY_ON);
|
lcd_display_control(lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF, LCD_DISPLAY_ON);
|
||||||
LOG_VERBOSE("Initializing LCD: rs=%d, rw=%d, en=%d, d={%d, %d, %d, %d, %d, "
|
LOG_VERBOSE("LCD Initialization done\n");
|
||||||
"%d, %d, %d}\n", rs, rw, en, d0, d1, d2, d3, d4, d5, d6, d7);
|
|
||||||
return lcd;
|
return lcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
109
src/screen.c
109
src/screen.c
@ -171,15 +171,6 @@ StatsScreen *stats_screen_new() {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *PERIOD_LABELS[] = {
|
|
||||||
"HOUR",
|
|
||||||
"DAY",
|
|
||||||
"WEEK",
|
|
||||||
"MONTH",
|
|
||||||
"YEAR",
|
|
||||||
};
|
|
||||||
static const size_t NPERIOD = sizeof(PERIOD_LABELS) / sizeof(char *);
|
|
||||||
|
|
||||||
static void stats_by_select_period(StatsByScreen *screen, SensorState *state) {
|
static void stats_by_select_period(StatsByScreen *screen, SensorState *state) {
|
||||||
if (state->up_down) {
|
if (state->up_down) {
|
||||||
screen->period = (screen->period + 1) % NPERIOD;
|
screen->period = (screen->period + 1) % NPERIOD;
|
||||||
@ -206,15 +197,15 @@ static void stats_by_select_period(StatsByScreen *screen, SensorState *state) {
|
|||||||
if (state->sel_down) {
|
if (state->sel_down) {
|
||||||
++screen->stage;
|
++screen->stage;
|
||||||
switch (screen->period) {
|
switch (screen->period) {
|
||||||
case 0:
|
case PERIOD_HOUR:
|
||||||
case 1:
|
case PERIOD_DAY:
|
||||||
case 2:
|
case PERIOD_WEEK:
|
||||||
screen->ds.max_stage = DATE_SEL_DAY;
|
screen->ds.max_stage = DATE_SEL_DAY;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case PERIOD_MONTH:
|
||||||
screen->ds.max_stage = DATE_SEL_MONTH;
|
screen->ds.max_stage = DATE_SEL_MONTH;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case PERIOD_YEAR:
|
||||||
screen->ds.max_stage = DATE_SEL_YEAR;
|
screen->ds.max_stage = DATE_SEL_YEAR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -244,11 +235,14 @@ static void date_sel_clamp_time(DateSelection *ds) {
|
|||||||
if (ds->year == ds->end_time.local_year &&
|
if (ds->year == ds->end_time.local_year &&
|
||||||
ds->month > ds->end_time.local_month) {
|
ds->month > ds->end_time.local_month) {
|
||||||
ds->month = ds->end_time.local_month;
|
ds->month = ds->end_time.local_month;
|
||||||
|
if (ds->stage == DATE_SEL_DAY) {
|
||||||
|
// last days of previous month
|
||||||
|
ds->day = days_in_month(ds->month, ds->year);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ds->month == ds->end_time.local_year &&
|
if (ds->year == ds->end_time.local_year &&
|
||||||
ds->month == ds->end_time.local_month &&
|
ds->month == ds->end_time.local_month &&
|
||||||
ds->day > ds->end_time.local_day) {
|
ds->day > ds->end_time.local_day) {
|
||||||
printf("Clamp Day High!\n");
|
|
||||||
ds->day = ds->end_time.local_day;
|
ds->day = ds->end_time.local_day;
|
||||||
}
|
}
|
||||||
if (ds->year < ds->start_time.local_year) {
|
if (ds->year < ds->start_time.local_year) {
|
||||||
@ -257,16 +251,15 @@ static void date_sel_clamp_time(DateSelection *ds) {
|
|||||||
if (ds->year == ds->start_time.local_year &&
|
if (ds->year == ds->start_time.local_year &&
|
||||||
ds->month < ds->start_time.local_month) {
|
ds->month < ds->start_time.local_month) {
|
||||||
ds->month = ds->start_time.local_month;
|
ds->month = ds->start_time.local_month;
|
||||||
|
if (ds->stage == DATE_SEL_DAY) {
|
||||||
|
ds->day = 1; // first day of the next month
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ds->year == ds->start_time.local_year &&
|
if (ds->year == ds->start_time.local_year &&
|
||||||
ds->month == ds->start_time.local_month &&
|
ds->month == ds->start_time.local_month &&
|
||||||
ds->day < ds->start_time.local_day) {
|
ds->day < ds->start_time.local_day) {
|
||||||
printf("Clamp Day Low!\n");
|
|
||||||
ds->day = ds->start_time.local_day;
|
ds->day = ds->start_time.local_day;
|
||||||
}
|
}
|
||||||
printf("Max: %d %d %d\n", ds->end_time.local_year, ds->end_time.local_month, ds->end_time.local_day);
|
|
||||||
printf("Min: %d %d %d\n", ds->start_time.local_year, ds->start_time.local_month, ds->start_time.local_day);
|
|
||||||
printf("Cur: %d %d %d\n", ds->year, ds->month, ds->day);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void date_sel_cleanup(DateSelection *ds) {
|
static void date_sel_cleanup(DateSelection *ds) {
|
||||||
@ -404,12 +397,77 @@ static void stats_by_select_start(StatsByScreen *screen, SensorState *state) {
|
|||||||
break; // ignore
|
break; // ignore
|
||||||
case DATE_SEL_DONE:
|
case DATE_SEL_DONE:
|
||||||
++screen->stage;
|
++screen->stage;
|
||||||
|
screen->offset_scale = 0;
|
||||||
screen->need_redraw = true;
|
screen->need_redraw = true;
|
||||||
|
screen->ulimit_reached = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void stats_by_show_stats(StatsByScreen *screen, SensorState *state) {
|
||||||
|
if (state->back_down) {
|
||||||
|
screen->stage = STATS_BY_SELECT_PERIOD;
|
||||||
|
screen->need_redraw = true;
|
||||||
|
screen->ds.stage = DATE_SEL_YEAR;
|
||||||
|
} else if (screen->need_redraw) {
|
||||||
|
screen->need_redraw = false;
|
||||||
|
lcd_display_control(state->lcd, LCD_CURSOR_NO_BLINK, LCD_CURSOR_OFF,
|
||||||
|
LCD_DISPLAY_ON);
|
||||||
|
lcd_clear(state->lcd);
|
||||||
|
lcd_move_to(state->lcd, 0, 0);
|
||||||
|
UtilAverageRange data;
|
||||||
|
if (!get_average_for_range(state->db, screen->ds.year, screen->ds.month,
|
||||||
|
screen->ds.day, screen->offset_scale,
|
||||||
|
screen->period, &data)) {
|
||||||
|
lcd_write_string(state->lcd, "Query failed!");
|
||||||
|
warnx("failed to query average temperature and humidity");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
screen->ulimit_reached = data.upper_bound;
|
||||||
|
screen->blimit_reached = data.lower_bound;
|
||||||
|
char period_string[17];
|
||||||
|
switch (screen->period) {
|
||||||
|
case PERIOD_YEAR:
|
||||||
|
snprintf(period_string, 17, "Year>%d", data.year);
|
||||||
|
break;
|
||||||
|
case PERIOD_MONTH:
|
||||||
|
snprintf(period_string, 17, "Month>%d-%d", data.year,
|
||||||
|
data.month);
|
||||||
|
break;
|
||||||
|
case PERIOD_WEEK:
|
||||||
|
snprintf(period_string, 17, "Week>%d-%d-%d", data.year,
|
||||||
|
data.month, data.day);
|
||||||
|
break;
|
||||||
|
case PERIOD_DAY:
|
||||||
|
snprintf(period_string, 17, "Day>%d-%d-%d", data.year,
|
||||||
|
data.month, data.day);
|
||||||
|
break;
|
||||||
|
case PERIOD_HOUR:
|
||||||
|
snprintf(period_string, 17, "Hour>%d-%d %d:00", data.month,
|
||||||
|
data.day, data.hour);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lcd_write_string(state->lcd, period_string);
|
||||||
|
lcd_move_to(state->lcd, 1, 0);
|
||||||
|
if (data.npoints) {
|
||||||
|
char data_string[17];
|
||||||
|
snprintf(data_string, 17, "T:%.1fF H:%d%%", DK_TO_F(data.temp), data.humid);
|
||||||
|
lcd_write_string(state->lcd, data_string);
|
||||||
|
} else {
|
||||||
|
lcd_write_string(state->lcd, "No data!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!screen->ulimit_reached && state->up_down) {
|
||||||
|
++screen->offset_scale;
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
if (!screen->blimit_reached && state->down_down) {
|
||||||
|
--screen->offset_scale;
|
||||||
|
screen->need_redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool stats_by_screen_dispatch(StatsByScreen *screen,
|
static bool stats_by_screen_dispatch(StatsByScreen *screen,
|
||||||
SensorState *state) {
|
SensorState *state) {
|
||||||
if (state->force_draw) {
|
if (state->force_draw) {
|
||||||
@ -432,16 +490,7 @@ static bool stats_by_screen_dispatch(StatsByScreen *screen,
|
|||||||
stats_by_select_start(screen, state);
|
stats_by_select_start(screen, state);
|
||||||
break;
|
break;
|
||||||
case STATS_BY_SHOWING:
|
case STATS_BY_SHOWING:
|
||||||
if (state->back_down) {
|
stats_by_show_stats(screen, state);
|
||||||
screen->stage = STATS_BY_SELECT_PERIOD;
|
|
||||||
screen->need_redraw = true;
|
|
||||||
screen->ds.stage = DATE_SEL_YEAR;
|
|
||||||
} else if (screen->need_redraw) {
|
|
||||||
lcd_clear(state->lcd);
|
|
||||||
lcd_move_to(state->lcd, 0, 0);
|
|
||||||
lcd_write_string(state->lcd, "Some data!");
|
|
||||||
screen->need_redraw = false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_VERBOSE("Attempt to show bad stats by screen\n");
|
LOG_VERBOSE("Attempt to show bad stats by screen\n");
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
* the terms of the GNU General Public License as published by the Free Software
|
* 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
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
* version. See the LICENSE file for more information.
|
* version. See the LICENSE file for more information.
|
||||||
*/
|
*/ #ifndef INCLUDED_SCREEN_H
|
||||||
#ifndef INCLUDED_SCREEN_H
|
|
||||||
#define INCLUDED_SCREEN_H
|
#define INCLUDED_SCREEN_H
|
||||||
|
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
@ -161,8 +160,11 @@ typedef struct {
|
|||||||
STATS_BY_SHOWING,
|
STATS_BY_SHOWING,
|
||||||
} stage;
|
} stage;
|
||||||
bool need_redraw;
|
bool need_redraw;
|
||||||
int period;
|
UtilPeriod period;
|
||||||
DateSelection ds;
|
DateSelection ds;
|
||||||
|
int offset_scale;
|
||||||
|
bool ulimit_reached;
|
||||||
|
bool blimit_reached;
|
||||||
} StatsByScreen;
|
} StatsByScreen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
75
src/util.c
75
src/util.c
@ -12,6 +12,15 @@
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
const char *PERIOD_LABELS[] = {
|
||||||
|
"HOUR",
|
||||||
|
"DAY",
|
||||||
|
"WEEK",
|
||||||
|
"MONTH",
|
||||||
|
"YEAR",
|
||||||
|
};
|
||||||
|
const size_t NPERIOD = sizeof(PERIOD_LABELS) / sizeof(char *);
|
||||||
|
|
||||||
Options GLOBAL_OPTS;
|
Options GLOBAL_OPTS;
|
||||||
|
|
||||||
void cleanup_options(Options *opts) {
|
void cleanup_options(Options *opts) {
|
||||||
@ -96,25 +105,53 @@ static const char *DB_LIMITS_QUERY_STR =
|
|||||||
"unixepoch(max(time), 'unixepoch', 'localtime', '+1 ' || ?1, 'start of ' || ?1, '-1 second') as MaxLocal\n"
|
"unixepoch(max(time), 'unixepoch', 'localtime', '+1 ' || ?1, 'start of ' || ?1, '-1 second') as MaxLocal\n"
|
||||||
"FROM env_data);";
|
"FROM env_data);";
|
||||||
static sqlite3_stmt *DB_LIMITS_QUERY;
|
static sqlite3_stmt *DB_LIMITS_QUERY;
|
||||||
|
const char *AVG_FOR_RANGE_QUERY_STR =
|
||||||
|
"SELECT\n"
|
||||||
|
"strftime('%Y', stime, 'unixepoch', 'localtime') as y,\n"
|
||||||
|
"strftime('%m', stime, 'unixepoch', 'localtime') as m,\n"
|
||||||
|
"strftime('%e', stime, 'unixepoch', 'localtime') as d,\n"
|
||||||
|
"strftime('%H', stime, 'unixepoch', 'localtime') as h,\n"
|
||||||
|
"ndata,\n"
|
||||||
|
"etime >= (select max(time) from env_data) as ulimit,\n"
|
||||||
|
"stime <= (select min(time) from env_data) as blimit,\n"
|
||||||
|
"atemp,\n"
|
||||||
|
"ahumid\n"
|
||||||
|
"FROM (SELECT\n"
|
||||||
|
"unixepoch(printf('%04d-%02d-%02d', ?1, ?2, ?3), 'utc', printf('%d %s', ?4 * ?6, ?5)) as stime,\n"
|
||||||
|
"unixepoch(printf('%04d-%02d-%02d', ?1, ?2, ?3), 'utc', printf('%d %s', (?4 + 1) * ?6, ?5)) as etime,\n"
|
||||||
|
"count(time) AS ndata,\n"
|
||||||
|
"round(avg(temp)) AS atemp,\n"
|
||||||
|
"round(avg(humid)) AS ahumid\n"
|
||||||
|
"FROM env_data\n"
|
||||||
|
"WHERE time > stime\n"
|
||||||
|
"AND time < etime);\n";
|
||||||
|
static sqlite3_stmt *AVG_FOR_RANGE_QUERY;
|
||||||
void initialize_util_queries(sqlite3 *db) {
|
void initialize_util_queries(sqlite3 *db) {
|
||||||
int status = sqlite3_prepare_v2(db, DB_LIMITS_QUERY_STR, -1,
|
int status = sqlite3_prepare_v2(db, DB_LIMITS_QUERY_STR, -1,
|
||||||
&DB_LIMITS_QUERY, NULL);
|
&DB_LIMITS_QUERY, NULL);
|
||||||
if (status != SQLITE_OK) {
|
if (status != SQLITE_OK) {
|
||||||
errx(1, "failed to compile limits query: %s", sqlite3_errstr(status));
|
errx(1, "failed to compile limits query: %s", sqlite3_errstr(status));
|
||||||
}
|
}
|
||||||
|
status = sqlite3_prepare_v2(db, AVG_FOR_RANGE_QUERY_STR, -1,
|
||||||
|
&AVG_FOR_RANGE_QUERY, NULL);
|
||||||
|
if (status != SQLITE_OK) {
|
||||||
|
errx(1, "failed to compile range average query: %s", sqlite3_errstr(status));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_util_queries() {
|
void cleanup_util_queries() {
|
||||||
sqlite3_finalize(DB_LIMITS_QUERY);
|
sqlite3_finalize(DB_LIMITS_QUERY);
|
||||||
|
sqlite3_finalize(AVG_FOR_RANGE_QUERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool get_database_limits(sqlite3 *db, const char *period, UtilDate *start,
|
bool get_database_limits(sqlite3 *db, const char *period, UtilDate *start,
|
||||||
UtilDate *end) {
|
UtilDate *end) {
|
||||||
if (strcasecmp(period, "week") == 0 || strcasecmp(period, "hour") == 0) {
|
if (strcasecmp(period, "week") == 0 || strcasecmp(period, "hour") == 0) {
|
||||||
period = "day";
|
period = "day";
|
||||||
}
|
}
|
||||||
bool success = true;
|
bool success = true;
|
||||||
sqlite3_bind_text(DB_LIMITS_QUERY, 1, period, -1, SQLITE_TRANSIENT);
|
sqlite3_bind_text(DB_LIMITS_QUERY, 1, period, -1, SQLITE_STATIC);
|
||||||
int status = sqlite3_step(DB_LIMITS_QUERY);
|
int status = sqlite3_step(DB_LIMITS_QUERY);
|
||||||
if (status == SQLITE_ROW) {
|
if (status == SQLITE_ROW) {
|
||||||
if (start) {
|
if (start) {
|
||||||
@ -145,3 +182,39 @@ bool get_database_limits(sqlite3 *db, const char *period, UtilDate *start,
|
|||||||
sqlite3_reset(DB_LIMITS_QUERY);
|
sqlite3_reset(DB_LIMITS_QUERY);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get_average_for_range(sqlite3 *db, int year, int month, int day,
|
||||||
|
int64_t count, UtilPeriod period,
|
||||||
|
UtilAverageRange *data) {
|
||||||
|
bool success = true;
|
||||||
|
sqlite3_bind_int(AVG_FOR_RANGE_QUERY, 1, year);
|
||||||
|
sqlite3_bind_int(AVG_FOR_RANGE_QUERY, 2, month);
|
||||||
|
sqlite3_bind_int(AVG_FOR_RANGE_QUERY, 3, day);
|
||||||
|
sqlite3_bind_int64(AVG_FOR_RANGE_QUERY, 4, count);
|
||||||
|
if (period == PERIOD_WEEK) {
|
||||||
|
sqlite3_bind_text(AVG_FOR_RANGE_QUERY, 5, "days", -1, SQLITE_STATIC);
|
||||||
|
sqlite3_bind_int(AVG_FOR_RANGE_QUERY, 6, 7);
|
||||||
|
} else {
|
||||||
|
sqlite3_bind_text(AVG_FOR_RANGE_QUERY, 5, PERIOD_LABELS[period], -1,
|
||||||
|
SQLITE_STATIC);
|
||||||
|
sqlite3_bind_int(AVG_FOR_RANGE_QUERY, 6, 1);
|
||||||
|
}
|
||||||
|
int status = sqlite3_step(AVG_FOR_RANGE_QUERY);
|
||||||
|
if (status == SQLITE_ROW) {
|
||||||
|
if (data) {
|
||||||
|
data->year = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 0);
|
||||||
|
data->month = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 1);
|
||||||
|
data->day = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 2);
|
||||||
|
data->hour = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 3);
|
||||||
|
data->npoints = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 4);
|
||||||
|
data->upper_bound = sqlite3_column_int64(AVG_FOR_RANGE_QUERY, 5);
|
||||||
|
data->lower_bound = sqlite3_column_int64(AVG_FOR_RANGE_QUERY, 6);
|
||||||
|
data->temp = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 7);
|
||||||
|
data->humid = sqlite3_column_int(AVG_FOR_RANGE_QUERY, 8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
sqlite3_reset(AVG_FOR_RANGE_QUERY);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
31
src/util.h
31
src/util.h
@ -103,6 +103,16 @@ typedef struct {
|
|||||||
int local_day;
|
int local_day;
|
||||||
} UtilDate;
|
} UtilDate;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PERIOD_HOUR = 0,
|
||||||
|
PERIOD_DAY,
|
||||||
|
PERIOD_WEEK,
|
||||||
|
PERIOD_MONTH,
|
||||||
|
PERIOD_YEAR,
|
||||||
|
} UtilPeriod;
|
||||||
|
extern const char *PERIOD_LABELS[];
|
||||||
|
extern const size_t NPERIOD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the START of the first and END of the last PERIOD (ex. week) of DB.
|
* Return the START of the first and END of the last PERIOD (ex. week) of DB.
|
||||||
* Return: false if an error occurred, true otherwise.
|
* Return: false if an error occurred, true otherwise.
|
||||||
@ -110,4 +120,25 @@ typedef struct {
|
|||||||
bool get_database_limits(sqlite3 *db, const char *period, UtilDate *start,
|
bool get_database_limits(sqlite3 *db, const char *period, UtilDate *start,
|
||||||
UtilDate *end);
|
UtilDate *end);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int npoints;
|
||||||
|
int temp;
|
||||||
|
int humid;
|
||||||
|
int year;
|
||||||
|
int month;
|
||||||
|
int day;
|
||||||
|
int hour;
|
||||||
|
bool lower_bound;
|
||||||
|
bool upper_bound;
|
||||||
|
} UtilAverageRange;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the average temp. and humid. between YEAR-MONTH-DAY + COUNT * PERIOD and
|
||||||
|
* YEAR-MONTH-DAY + (COUNT + 1) * PERIOD.
|
||||||
|
* Return: false if an error occurred, true otherwise.
|
||||||
|
*/
|
||||||
|
bool get_average_for_range(sqlite3 *db, int year, int month, int day,
|
||||||
|
int64_t count, UtilPeriod period,
|
||||||
|
UtilAverageRange *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user