295 lines
6.9 KiB
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);
|
|
}
|