controller-legacy/src/models/relay.c

295 lines
6.9 KiB
C

#include <stdlib.h>
#include <string.h>
#include <uuid/uuid.h>
#include <logger.h>
#include <helpers.h>
#include <database.h>
#include <models/relay.h>
#include <models/junction_relay_schedule.h>
static int
db_update_insert(relay_t *relay, sqlite3_stmt *stmt)
{
LOGGER_DEBUG("saving relay '%s' into database (id: %d)\n", relay->name, relay->id);
int rc;
sqlite3_bind_int(stmt, 1, relay->id);
sqlite3_bind_int(stmt, 2, relay->number);
sqlite3_bind_text(stmt, 3, relay->name, -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return rc != SQLITE_DONE;
}
static relay_t*
relay_db_select_mapper(sqlite3_stmt *stmt)
{
relay_t *new_relay = malloc(sizeof(relay_t));
new_relay->is_on = 0;
for(int i = 0; i < sqlite3_column_count(stmt); i++)
{
const char *name = sqlite3_column_name(stmt, i);
switch(name[0])
{
case 'i':
new_relay->id = sqlite3_column_int(stmt, i);
break;
case 'n':
switch(name[1])
{
case 'a': // name
strncpy(new_relay->name, (const char*)sqlite3_column_text(stmt, i), 127);
break;
case 'u': // number
new_relay->number = sqlite3_column_int(stmt, i);
break;
default:
break;
}
break;
default: // ignore columns not implemented
break;
}
}
memset(new_relay->schedules, 0, sizeof(schedule_t*) * 7);
relay_reload_schedules(new_relay);
new_relay->is_on = -1;
new_relay->is_on_schedule = -1;
new_relay->pulse_timer = 0;
new_relay->sent_to_broker = 0;
return new_relay;
}
static relay_t**
relay_db_select(sqlite3_stmt *stmt)
{
relay_t **all_relays = malloc(sizeof(relay_t*));
int row = 0;
while(true)
{
int s;
s = sqlite3_step(stmt);
if (s == SQLITE_ROW)
{
relay_t *new_relay = relay_db_select_mapper(stmt);
row++;
all_relays = (relay_t**)realloc(all_relays, sizeof(relay_t*) * (row + 1));
all_relays[row - 1] = new_relay;
}
else
{
if(s == SQLITE_DONE)
{
break;
}
else
{
LOGGER_ERR("error selecting relays from database: %s\n", sqlite3_errstr(s));
break;
}
}
}
sqlite3_finalize(stmt);
all_relays[row] = NULL;
return all_relays;
}
int
relay_save(relay_t *relay)
{
int opened_transaction = database_transaction_begin();
sqlite3_stmt *stmt;
if(relay->id)
{
sqlite3_prepare_v2(global_database, "UPDATE relays set number = ?2, name = ?3 WHERE id = ?1;", -1, &stmt, NULL);
}
else
{
sqlite3_prepare_v2(global_database, "INSERT INTO relays(number, name) values (?2, ?3);", -1, &stmt, NULL);
}
int result = db_update_insert(relay, stmt);
if(result)
{
if(relay->id)
{
LOGGER_ERR("error inserting data: %s\n", sqlite3_errmsg(global_database));
}
else
{
LOGGER_ERR("error updating data: %s\n", sqlite3_errmsg(global_database));
}
if(opened_transaction)
{
database_transaction_rollback();
}
}
else
{
if(relay->id == 0)
{
relay->id = sqlite3_last_insert_rowid(global_database);
LOGGER_DEBUG("new relay - new id: %d\n", relay->id);
}
LOGGER_DEBUG("cleaning relay_schedule junction\n");
junction_relay_schedule_remove_for_relay(relay->id);
LOGGER_DEBUG("rebuilding relay_schedule junction\n");
int schedule_ids[7];
for(int i = 0; i < 7; ++i)
{
schedule_ids[i] = relay->schedules[i]->id;
}
junction_relay_schedule_insert_weekdays(relay->id, schedule_ids);
if(opened_transaction)
{
database_transaction_commit();
}
}
return result;
}
relay_t*
relay_create(uint8_t number)
{
relay_t *new_relay = malloc(sizeof(relay_t));
new_relay->id = 0;
new_relay->number = number;
new_relay->name[0] = '\0';
new_relay->is_on = -1;
new_relay->is_on_schedule = -1;
new_relay->pulse_timer = 0;
new_relay->sent_to_broker = 0;
uuid_t off_id;
memset(off_id, 0, sizeof(uuid_t));
memcpy(off_id, "off", 3);
for(int i = 0; i < 7; ++i)
{
new_relay->schedules[i] = schedule_get_by_uid(off_id);
}
return new_relay;
}
relay_t*
relay_load(uint8_t number)
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2(global_database, "SELECT * FROM relays WHERE number = ?1;", -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, number);
relay_t **sql_result = relay_db_select(stmt);
relay_t *result = sql_result[0];
free(sql_result);
return result;
}
void
relay_reload_schedules(relay_t *relay)
{
schedule_t **schedules = schedule_get_relay_weekdays(relay->id);
uuid_t off_id;
memset(off_id, 0, sizeof(uuid_t));
memcpy(off_id, "off", 3);
int fill_with_off = 0;
for(int i = 0; i < 7; ++i)
{
if(schedules[i] == NULL || fill_with_off)
{
LOGGER_WARNING("got only %d/7 schedules for relay_id %d\n", i, relay->id);
relay->schedules[i] = schedule_get_by_uid(off_id);
fill_with_off = 1;
}
else
{
if(relay->schedules[i])
{
schedule_free(relay->schedules[i]);
}
relay->schedules[i] = schedules[i];
}
}
free(schedules); // don't free list, because contents are kept in relay->schedules
}
void
relay_set_name(relay_t *relay, const char *name)
{
strncpy(relay->name, name, MAX_NAME_LENGTH);
relay->name[MAX_NAME_LENGTH] = '\0';
}
int
relay_is_on_schedule(relay_t *relay, struct tm *time_struct)
{
schedule_t *schedule = relay->schedules[helper_get_weekday(time_struct)];
if(schedule->periods_count == 0)
{
return 0;
}
for(uint16_t i = 0; i < schedule->periods_count; ++i)
{
if(period_includes_time(schedule->periods[i], time_struct))
{
return 1;
}
}
return 0;
}
void
relay_debug(relay_t *relay)
{
if(relay == NULL)
{
LOGGER_DEBUG("relay is NULL\n");
return;
}
LOGGER_DEBUG("(1/3) %3d @ %p\n", relay->number, (void*)relay);
LOGGER_DEBUG("(2/3) id: %3d; name: %s\n", relay->id, relay->name);
LOGGER_DEBUG("(3/3) schedules @ %p:\n", (void*)relay->schedules);
for(int i = 0; i < 7; ++i)
{
schedule_debug(relay->schedules[i]);
}
}
void
relay_free(relay_t *relay)
{
for(int i = 0; i < 7; ++i)
{
schedule_free(relay->schedules[i]);
}
free(relay);
}