Add config files and service file

This commit is contained in:
2024-04-05 01:31:05 -07:00
parent 338d9360a6
commit 7ad8ea25a6
9 changed files with 233 additions and 46 deletions

View File

@ -221,7 +221,7 @@ void parse_config_file(const char *path) {
.directive = "gpio_file",
.type = FIGPAR_TYPE_STR,
.action = parse_str_callback,
.value = {.str = strdup_default_opt(DEFAULT_GPIO_DEVICE)},
.value = {.str = strdup_default_opt(STRINGIFY(DEFAULT_GPIO_DEVICE))},
},
{
.directive = "rs_pin",
@ -247,19 +247,19 @@ void parse_config_file(const char *path) {
.directive = "temp_key",
.type = FIGPAR_TYPE_STR,
.action = parse_str_callback,
.value = {.str = strdup_default_opt(DEFAULT_TEMP_KEY)},
.value = {.str = strdup_default_opt(STRINGIFY(DEFAULT_TEMP_KEY))},
},
{
.directive = "humid_key",
.type = FIGPAR_TYPE_STR,
.action = parse_str_callback,
.value = {.str = strdup_default_opt(DEFAULT_HUMID_KEY)},
.value = {.str = strdup_default_opt(STRINGIFY(DEFAULT_HUMID_KEY))},
},
{
.directive = "fail_key",
.type = FIGPAR_TYPE_STR,
.action = parse_str_callback,
.value = {.str = strdup_default_opt(DEFAULT_FAIL_KEY)},
.value = {.str = strdup_default_opt(STRINGIFY(DEFAULT_FAIL_KEY))},
},
{
.directive = "fail_limit",
@ -271,7 +271,7 @@ void parse_config_file(const char *path) {
.directive = "database_location",
.type = FIGPAR_TYPE_STR,
.action = parse_str_callback,
.value = {.str = strdup_default_opt(DEFAULT_DATABASE_LOCATION)},
.value = {.str = strdup_default_opt(STRINGIFY(DEFAULT_DATABASE_LOCATION))},
},
{
.directive = "refresh_time",
@ -303,7 +303,7 @@ void parse_config_file(const char *path) {
.directive = "temp_unit",
.type = FIGPAR_TYPE_INT,
.action = parse_temp_unit_callback,
.value = {.num = DEFAULT_TEMP_UNIT},
.value = {.num = STRINGIFY(DEFAULT_TEMP_UNIT)[0]},
},
{
.directive = "bl_pin",
@ -315,7 +315,7 @@ void parse_config_file(const char *path) {
.directive = "export_file_name",
.type = FIGPAR_TYPE_STR,
.action = parse_str_callback,
.value = {.str = strdup_default_opt(DEFAULT_EXPORT_FILE_NAME)},
.value = {.str = strdup_default_opt(STRINGIFY(DEFAULT_EXPORT_FILE_NAME))},
},
{ .directive = NULL },
};

View File

@ -35,6 +35,7 @@
#include <stdatomic.h>
#include <signal.h>
#include <sqlite3.h>
#include <libgen.h>
/*
* Print help message to standard output.
@ -49,9 +50,13 @@ void parse_arguments(int argc, char *const *argv);
*/
void setup_signals(void);
/*
* Open an sqlite3 database connection.
* Open the sqlite3 database connection.
*/
void open_database(void);
/*
* Create the env_data table in DATABASE
*/
void create_db_table(void);
/*
* Read the temp. and humid., store it in the configured database, and output it
* to the given uint32_t pointers.
@ -93,6 +98,7 @@ int main(int argc, char *const *argv) {
GLOBAL_OPTS.data_pins[7], GLOBAL_OPTS.bl_pin);
setup_signals();
open_database();
create_db_table();
initialize_util_queries(DATABASE);
pthread_t bg_update;
start_update_thread(&bg_update);
@ -167,7 +173,7 @@ void parse_arguments(int argc, char *const *argv) {
}
}
if (!GLOBAL_OPTS.config_path) {
GLOBAL_OPTS.config_path = strdup_checked(DEFAULT_CONFIG_PATH);
GLOBAL_OPTS.config_path = strdup_checked(STRINGIFY(DEFAULT_CONFIG_PATH));
LOG_VERBOSE("Config file path set: \"%s\"\n", GLOBAL_OPTS.config_path);
}
}
@ -190,18 +196,43 @@ void setup_signals() {
SIGNAL_SETUP_CHECKED(SIGUSR1, SIG_IGN); // used to kill export operations
}
static const char *CREATE_DB_TABLE_QUERY =
"CREATE TABLE IF NOT EXISTS env_data("
"time INTEGER PRIMARY KEY,"
"temp INTEGER,"
"humid INTEGER"
");";
void create_db_table() {
char *errmsg;
int status = sqlite3_exec(DATABASE, CREATE_DB_TABLE_QUERY, NULL, NULL,
&errmsg);
if (status != SQLITE_OK) {
errx(1, "could not create table. sqlite3 error follows:\n%s",
errmsg ? errmsg : "No message generated");
}
LOG_VERBOSE("Ensured env_data table existance\n");
}
void open_database() {
int status = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
if (status != SQLITE_OK) {
errx(1, "failed to enable multi-thread mode for sqlite: %s",
sqlite3_errstr(status));
}
char *to_free = strdup_checked(GLOBAL_OPTS.database_location);
char *db_dir = dirname(to_free);
if (!mkdirs(db_dir, 0755)) {
errx(1, "failed to create database directory: %s", db_dir);
}
free(to_free);
status = sqlite3_open(GLOBAL_OPTS.database_location, &DATABASE);
if (status != SQLITE_OK) {
sqlite3_close(DATABASE);
errx(1, "failed to open database: %s",
sqlite3_errstr(status));
}
LOG_VERBOSE("Successfully opened database at \"%s\"\n",
GLOBAL_OPTS.database_location);
}
void update_stats(THS *ths, sqlite3_stmt *insert_statement) {
@ -229,28 +260,10 @@ void update_stats(THS *ths, sqlite3_stmt *insert_statement) {
}
}
static const char *CREATE_DB_TABLE_QUERY =
"CREATE TABLE IF NOT EXISTS env_data("
"time INTEGER PRIMARY KEY,"
"temp INTEGER,"
"humid INTEGER"
");";
static void create_db_table() {
char *errmsg;
int status = sqlite3_exec(DATABASE, CREATE_DB_TABLE_QUERY, NULL, NULL,
&errmsg);
if (status != SQLITE_OK) {
errx(1, "could not create table. sqlite3 error follows:\n%s",
errmsg ? errmsg : "No message generated");
}
LOG_VERBOSE("Ensured env_data table existance\n");
}
static const char *UPDATE_STATS_QUERY =
"INSERT INTO env_data (time, temp, humid) "
"VALUES(?, ?, ?);";
static void *update_thread_action(void *_ignored) {
create_db_table();
sqlite3_stmt *insert_statement = NULL;
int status = sqlite3_prepare_v2(DATABASE, UPDATE_STATS_QUERY, -1,
&insert_statement, NULL);

View File

@ -18,6 +18,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
const char *PERIOD_LABELS[] = {
"HOUR",
@ -164,7 +165,7 @@ static const char *AVG_FOR_PERIOD_QUERY_STR =
"min(humid) AS minhumid\n"
"FROM env_data\n"
"WHERE time >= stime\n"
"AND time <= etime);\n";
"AND time <= etime);";
static sqlite3_stmt *AVG_FOR_PERIOD_QUERY;
static const char *DATA_POINT_QUERY_STR =
"SELECT max(time) IS NULL, max(time), temp, humid FROM env_data WHERE time < ?1\n"
@ -528,3 +529,39 @@ bool export_database_as_csv(sqlite3 *db, const char *dest) {
pthread_cleanup_pop(true); // close file
return status;
}
static bool ensure_dir_exists(const char *path, mode_t mode) {
struct stat statbuf;
errno = 0;
if (mkdir(path, mode) < 0) {
if (errno != EEXIST) {
warn("mkdir failed: %s", path);
return false;
}
if (stat(path, &statbuf) < 0) {
warn("mkdir and stat failed: %s", path);
return false;
} else if (!S_ISDIR(statbuf.st_mode)) {
warn("not a directory: %s", path);
return false;
}
}
return true;
}
bool mkdirs(const char *path, mode_t mode) {
LOG_VERBOSE("Creating directory: \"%s\"\n", path)
char *copy = strdup_checked(path);
char *work_str = copy, *token;
while ((token = strsep(&work_str, "/"))) {
if (token != copy) {
token[-1] = '/';
}
if (*copy && *token && !ensure_dir_exists(copy, mode)) {
free(copy);
return false;
}
}
free(copy);
return true;
}

View File

@ -19,6 +19,9 @@
#include <libgpio.h>
#include <sqlite3.h>
#define _STRINGIFY_LIT(s) (#s)
#define STRINGIFY(v) _STRINGIFY_LIT(v)
typedef enum {
TEMP_UNIT_F = 'F',
TEMP_UNIT_C = 'C'
@ -239,4 +242,10 @@ bool export_database(sqlite3 *db, const char *dest);
*/
bool export_database_as_csv(sqlite3 *db, const char *dest);
/*
* Create all the missing directories along path.
* Return: true on success, false otherwise
*/
bool mkdirs(const char *path, mode_t mode);
#endif