#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); }