From 924633f27203692b393941007f05139a6fcb6908 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Mon, 24 Aug 2020 23:44:49 +0200
Subject: [PATCH 1/8] fix: all the bugs with the new database and commanding

---
 .gitignore                               |  5 +-
 CMakeLists.txt                           |  2 +-
 include/models/junction_relay_schedule.h |  3 +
 include/models/schedule.h                |  2 +-
 include/sql/migration_0.h                | 96 ------------------------
 sql/migration_0.sql                      |  4 +-
 src/handlers/command.c                   | 24 +++++-
 src/main.c                               |  9 ++-
 src/models/controller.c                  |  6 +-
 src/models/junction_relay_schedule.c     | 14 +++-
 src/models/relay.c                       | 64 ++++++++--------
 src/models/schedule.c                    | 19 ++---
 12 files changed, 99 insertions(+), 149 deletions(-)
 delete mode 100644 include/sql/migration_0.h

diff --git a/.gitignore b/.gitignore
index ec5515d..b944f3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
-.idea/
-
 docs/
 build/
-cmake-build-debug/
+
+include/sql/*.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c1f96a6..0eee6a6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.0
+        VERSION 0.3.1
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/include/models/junction_relay_schedule.h b/include/models/junction_relay_schedule.h
index 3a1eccb..ebc0755 100644
--- a/include/models/junction_relay_schedule.h
+++ b/include/models/junction_relay_schedule.h
@@ -10,4 +10,7 @@ junction_relay_schedule_remove_for_relay(int relay_id);
 int
 junction_relay_schedule_insert_weekdays(int relay_id, int *schedule_ids);
 
+int*
+junction_relay_schedule_get_relay_ids_with_schedule(int schedule_id);
+
 #endif /* CONTROLLER_MODELS_JUNCTION_RELAY_SCHEDULE_H */
diff --git a/include/models/schedule.h b/include/models/schedule.h
index 3455e4c..212cd81 100644
--- a/include/models/schedule.h
+++ b/include/models/schedule.h
@@ -12,7 +12,7 @@ typedef struct
     int id;
     uuid_t uid;
     uint8_t weekday;
-    uint16_t length;
+    uint16_t periods_count;
     period_t *periods;
 } schedule_t;
 
diff --git a/include/sql/migration_0.h b/include/sql/migration_0.h
deleted file mode 100644
index fc2ea85..0000000
--- a/include/sql/migration_0.h
+++ /dev/null
@@ -1,96 +0,0 @@
-unsigned char sql_migration_0_sql[] = {
-  0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65,
-  0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73,
-  0x0a, 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x64, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x0a, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50,
-  0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x0a, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41,
-  0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54,
-  0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x69, 0x64, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e,
-  0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x2c, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x56, 0x41, 0x52, 0x43,
-  0x48, 0x41, 0x52, 0x28, 0x31, 0x32, 0x38, 0x29, 0x2c, 0x0a, 0x20, 0x20,
-  0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x70, 0x6f,
-  0x72, 0x74, 0x20, 0x20, 0x20, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45,
-  0x52, 0x0a, 0x29, 0x3b, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
-  0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x79,
-  0x73, 0x0a, 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x75, 0x6d, 0x62,
-  0x65, 0x72, 0x20, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x2c, 0x0a, 0x20, 0x20,
-  0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20, 0x56, 0x41,
-  0x52, 0x43, 0x48, 0x41, 0x52, 0x28, 0x31, 0x32, 0x38, 0x29, 0x0a, 0x29,
-  0x3b, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x61,
-  0x62, 0x6c, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-  0x73, 0x0a, 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x64, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x20, 0x4b, 0x45, 0x59, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x41, 0x55, 0x54, 0x4f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e,
-  0x54, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x69, 0x64, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x4f, 0x54, 0x20,
-  0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x2c,
-  0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20,
-  0x20, 0x56, 0x41, 0x52, 0x43, 0x48, 0x41, 0x52, 0x28, 0x31, 0x32, 0x38,
-  0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f,
-  0x64, 0x73, 0x20, 0x42, 0x4c, 0x4f, 0x42, 0x0a, 0x29, 0x3b, 0x0a, 0x0a,
-  0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65,
-  0x20, 0x6a, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65,
-  0x6c, 0x61, 0x79, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-  0x0a, 0x28, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x65, 0x65, 0x6b, 0x64,
-  0x61, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
-  0x4d, 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x54, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4e, 0x55, 0x4c, 0x4c,
-  0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f,
-  0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x4e,
-  0x54, 0x45, 0x47, 0x45, 0x52, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, 0x4e, 0x43, 0x45, 0x53,
-  0x20, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x73, 0x20, 0x28, 0x69, 0x64, 0x29,
-  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4f, 0x4e, 0x20,
-  0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x20, 0x43, 0x41, 0x53, 0x43, 0x41,
-  0x44, 0x45, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x68, 0x65,
-  0x64, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x0a, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x20,
-  0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x45,
-  0x46, 0x45, 0x52, 0x45, 0x4e, 0x43, 0x45, 0x53, 0x20, 0x73, 0x63, 0x68,
-  0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x28, 0x69, 0x64, 0x29, 0x0a,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4f, 0x4e, 0x20, 0x44,
-  0x45, 0x4c, 0x45, 0x54, 0x45, 0x20, 0x53, 0x45, 0x54, 0x20, 0x44, 0x45,
-  0x46, 0x41, 0x55, 0x4c, 0x54, 0x0a, 0x29, 0x3b, 0x0a, 0x0a, 0x49, 0x4e,
-  0x53, 0x45, 0x52, 0x54, 0x20, 0x49, 0x4e, 0x54, 0x4f, 0x20, 0x73, 0x63,
-  0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x28, 0x75, 0x69, 0x64,
-  0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x70, 0x65, 0x72, 0x69,
-  0x6f, 0x64, 0x73, 0x29, 0x20, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x53, 0x20,
-  0x28, 0x78, 0x27, 0x36, 0x66, 0x36, 0x36, 0x36, 0x36, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x27,
-  0x2c, 0x20, 0x27, 0x6f, 0x66, 0x66, 0x27, 0x2c, 0x20, 0x78, 0x27, 0x30,
-  0x30, 0x27, 0x29, 0x3b, 0x0a, 0x49, 0x4e, 0x53, 0x45, 0x52, 0x54, 0x20,
-  0x49, 0x4e, 0x54, 0x4f, 0x20, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
-  0x65, 0x73, 0x20, 0x28, 0x75, 0x69, 0x64, 0x2c, 0x20, 0x6e, 0x61, 0x6d,
-  0x65, 0x2c, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x73, 0x29, 0x20,
-  0x56, 0x41, 0x4c, 0x55, 0x45, 0x53, 0x20, 0x28, 0x78, 0x27, 0x36, 0x66,
-  0x36, 0x65, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x27, 0x2c, 0x20, 0x20, 0x27, 0x6f,
-  0x6e, 0x27, 0x2c, 0x20, 0x78, 0x27, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x30, 0x39, 0x46, 0x30, 0x35, 0x27, 0x29, 0x3b, 0x0a, 0x00
-};
-unsigned int sql_migration_0_sql_len = 1114;
diff --git a/sql/migration_0.sql b/sql/migration_0.sql
index 922c002..e9dc18a 100644
--- a/sql/migration_0.sql
+++ b/sql/migration_0.sql
@@ -12,8 +12,10 @@ create table controllers
 
 create table relays
 (
-    number  INTEGER
+    id      INTEGER
             PRIMARY KEY
+            AUTOINCREMENT,
+    number  INTEGER
             NOT NULL,
     name    VARCHAR(128)
 );
diff --git a/src/handlers/command.c b/src/handlers/command.c
index ae15e86..b511e02 100644
--- a/src/handlers/command.c
+++ b/src/handlers/command.c
@@ -114,9 +114,26 @@ handler_command_schedule_update(mpack_node_t map)
     if(schedule)
     {
         new_schedule->id = schedule->id;
+        schedule_free(schedule);
     }
+
     schedule_save(new_schedule);
-    schedule_free(schedule);
+    schedule_debug(new_schedule);
+
+    int *relay_ids = junction_relay_schedule_get_relay_ids_with_schedule(new_schedule->id);
+
+    for(int i = 0; i < global_config.relay_count; ++i)
+    {
+        for(int j = 0; relay_ids[j] != 0; ++j)
+        {
+            if(global_controller->relays[i]->id == relay_ids[j])
+            {
+                relay_reload_schedules(global_controller->relays[i]);
+            }
+        }
+    }
+
+    free(relay_ids);
     schedule_free(new_schedule);
 }
 
@@ -151,6 +168,7 @@ handler_command_relay_schedules_set(mpack_node_t map)
 
         schedule_t *schedule = schedule_get_by_uid(schedule_uid);
 
+        relay_debug(target_relay);
         junction_relay_schedule_insert(i, target_relay->id, schedule->id);
     }
 
@@ -182,7 +200,7 @@ handler_command(struct mg_connection *c, int ev, void *ev_data)
     mpack_tree_parse(&tree);
     mpack_node_t root = mpack_tree_root(&tree);
 
-    uint16_t command_code = mpack_node_u8(mpack_node_map_uint(root, COMMAND_MAPPING_CODE));
+    uint16_t command_code = mpack_node_u16(mpack_node_map_uint(root, COMMAND_MAPPING_CODE));
 
     LOGGER_DEBUG("received command %d\n", command_code);
 
@@ -221,4 +239,6 @@ handler_command(struct mg_connection *c, int ev, void *ev_data)
     {
         LOGGER_WARNING("error when destroying mpack tree\n");
     }
+    LOGGER_DEBUG("done with command %d - closing connection\n", command_code);
+    c->flags |= MG_F_SEND_AND_CLOSE;
 }
diff --git a/src/main.c b/src/main.c
index cd998b6..17149e2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -122,7 +122,6 @@ main(int argc, const char** argv)
     if(!global_controller)
     {
         global_controller = controller_create();
-
         controller_save();
     }
 
@@ -130,9 +129,13 @@ main(int argc, const char** argv)
     connection_mqtt_connect(&mgr);
     struct mg_connection *c_command = connection_command_bind(&mgr);
 
-    global_controller->command_port = helper_get_port(c_command->sock);
+    if(global_controller->command_port == 0)
+    {
+        global_controller->command_port = helper_get_port(c_command->sock);
+        controller_save();
+    }
 
-    controller_save();
+    controller_debug(global_controller);
 
     helper_drop_privileges();
 
diff --git a/src/models/controller.c b/src/models/controller.c
index 58c1554..729404b 100644
--- a/src/models/controller.c
+++ b/src/models/controller.c
@@ -60,10 +60,11 @@ controller_db_select_mapper(sqlite3_stmt *stmt)
     uint8_t i;
     for(i = 0; i < global_config.relay_count; ++i)
     {
-        new_controller->relays[i] = relay_load(new_controller->id);
+        new_controller->relays[i] = relay_load(i);
         if(!new_controller->relays[i])
         {
             new_controller->relays[i] = relay_create(i);
+            relay_save(new_controller->relays[i]);
         }
     }
     return new_controller;
@@ -206,10 +207,11 @@ controller_create(void)
     uint8_t i;
     for(i = 0; i < global_config.relay_count; ++i)
     {
-        new_controller->relays[i] = relay_load(new_controller->id);
+        new_controller->relays[i] = relay_load(i);
         if(!new_controller->relays[i])
         {
             new_controller->relays[i] = relay_create(i);
+            relay_save(new_controller->relays[i]);
         }
     }
 
diff --git a/src/models/junction_relay_schedule.c b/src/models/junction_relay_schedule.c
index fca0ffd..8d623c0 100644
--- a/src/models/junction_relay_schedule.c
+++ b/src/models/junction_relay_schedule.c
@@ -23,7 +23,7 @@ junction_relay_schedule_insert(uint8_t weekday, int relay_id, int schedule_id)
     rc = sqlite3_step(stmt);
     if (rc != SQLITE_DONE)
     {
-        LOGGER_ERR("error inserting data: %s", sqlite3_errmsg(global_database));
+        LOGGER_ERR("error inserting data: %s\n", sqlite3_errmsg(global_database));
         return false;
     }
 
@@ -88,3 +88,15 @@ junction_relay_schedule_remove_for_relay(int relay_id)
 
     return rc == SQLITE_DONE;
 }
+
+
+int*
+junction_relay_schedule_get_relay_ids_with_schedule(int schedule_id)
+{
+    sqlite3_stmt *stmt;
+
+    sqlite3_prepare_v2(global_database, "SELECT DISTINCT relay_id FROM junction_relay_schedule WHERE schedule_id=?1;", -1, &stmt, NULL);
+    sqlite3_bind_int(stmt, 1, schedule_id);
+
+    return database_helper_get_ids(stmt);
+}
diff --git a/src/models/relay.c b/src/models/relay.c
index 317f575..903e1bf 100644
--- a/src/models/relay.c
+++ b/src/models/relay.c
@@ -55,20 +55,14 @@ relay_db_select_mapper(sqlite3_stmt *stmt)
                 break;
         }
     }
+    
+    memset(new_relay->schedules, 0, sizeof(schedule_t*) * 7);
+    relay_reload_schedules(new_relay);
 
-    schedule_t **schedules = schedule_get_relay_weekdays(new_relay->id);
-    for(int i = 0; i < 7; ++i)
-    {
-        if(schedules[i] == NULL)
-        {
-            LOGGER_ERR("got only %d/7 schedules for relay_id %d\n", i, new_relay->id);
-            relay_free(new_relay);
-            free(schedules);
-            return NULL;
-        }
-        new_relay->schedules[i] = schedules[i];
-    }
-    free(schedules); // don't free list, because contents are kept in relay->schedules
+    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;
 }
@@ -119,11 +113,11 @@ relay_save(relay_t *relay)
     sqlite3_stmt *stmt;
     if(relay->id)
     {
-        sqlite3_prepare_v2(global_database, "UPDATE relays set number = ?2, name = ?3, controller_id = ?4 WHERE id = ?1;", -1, &stmt, NULL);
+        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, controller_id) values (?2, ?3, ?4);", -1, &stmt, NULL);
+        sqlite3_prepare_v2(global_database, "INSERT INTO relays(number, name) values (?2, ?3);", -1, &stmt, NULL);
     }
 
     int result = db_update_insert(relay, stmt);
@@ -149,6 +143,7 @@ relay_save(relay_t *relay)
         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");
@@ -177,6 +172,7 @@ 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';
 
@@ -217,23 +213,31 @@ 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)
+        if(schedules[i] == NULL || fill_with_off)
         {
-            LOGGER_ERR("got only %d/7 schedules for relay_id %d\n", i, relay->id);
-            relay_free(relay);
-            schedule_free_list(schedules);
-            return;
+            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];
         }
     }
 
-
-    for(int i = 0; i < 7; ++i)
-    {
-        schedule_free(relay->schedules[i]);
-        relay->schedules[i] = schedules[i];
-    }
     free(schedules); // don't free list, because contents are kept in relay->schedules
 }
 
@@ -248,12 +252,12 @@ int
 relay_is_on_schedule(relay_t *relay, struct tm *time_struct)
 {
     schedule_t *schedule = relay->schedules[helper_get_weekday(time_struct)];
-    if(schedule->length == 0)
+    if(schedule->periods_count == 0)
     {
         return 0;
     }
 
-    for(uint16_t i = 0; i < schedule->length; ++i)
+    for(uint16_t i = 0; i < schedule->periods_count; ++i)
     {
         if(period_includes_time(schedule->periods[i], time_struct))
         {
@@ -271,8 +275,8 @@ relay_debug(relay_t *relay)
         LOGGER_DEBUG("relay is NULL\n");
         return;
     }
-    LOGGER_DEBUG("(1/3) %d @ %p\n", relay->number, (void*)relay);
-    LOGGER_DEBUG("(2/3) name: %s\n", relay->name);
+    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)
     {
diff --git a/src/models/schedule.c b/src/models/schedule.c
index 188358e..d895637 100644
--- a/src/models/schedule.c
+++ b/src/models/schedule.c
@@ -44,6 +44,7 @@ schedule_db_select_mapper(sqlite3_stmt *stmt)
                 break;
             case 'p': // periods
                 periods_blob = sqlite3_column_blob(stmt, i);
+                new_schedule->periods_count = periods_blob[0];
                 new_schedule->periods = malloc(sizeof(period_t) * periods_blob[0]);
 
                 for(int i = 0; i < periods_blob[0]; ++i)
@@ -186,9 +187,10 @@ schedule_create(uuid_t uid, uint16_t length, uint16_t *periods_blob)
 {
     schedule_t *new_schedule = malloc(sizeof(schedule_t));
 
+    new_schedule->id = 0;
     memmove(new_schedule->uid, uid, sizeof(uuid_t));
 
-    new_schedule->length = length;
+    new_schedule->periods_count = length;
     new_schedule->periods = NULL;
 
     if(length)
@@ -208,10 +210,10 @@ schedule_create(uuid_t uid, uint16_t length, uint16_t *periods_blob)
 uint16_t*
 schedule_periods_to_blob(schedule_t *schedule)
 {
-    uint16_t *periods_blob = malloc(sizeof(uint16_t) * ((2 * schedule->length) + 1));
-    periods_blob[0] = schedule->length;
+    uint16_t *periods_blob = malloc(sizeof(uint16_t) * ((2 * schedule->periods_count) + 1));
+    periods_blob[0] = schedule->periods_count;
 
-    for(uint16_t i = 0; i < schedule->length; ++i)
+    for(uint16_t i = 0; i < schedule->periods_count; ++i)
     {
 
         periods_blob[1 + (i * 2)] = schedule->periods[i].start;
@@ -296,14 +298,13 @@ schedule_debug(schedule_t *schedule)
     char uuid_str[UUID_STR_LEN];
     uuid_unparse(schedule->uid, uuid_str);
     LOGGER_DEBUG("(1/3) %s @ %p\n", uuid_str, (void*)schedule);
-    LOGGER_DEBUG("(2/4) period count: %3d\n", schedule->length);
-    LOGGER_DEBUG("(3/4) weekday: %3d\n", schedule->weekday);
+    LOGGER_DEBUG("(2/3) id: %3d; period count: %3d\n", schedule->id, schedule->periods_count);
 
     // one block: "HH:MM-HH:MM, " --> size: 13 (14 with '\0')
-    char *periods_debug_str = malloc(sizeof(char) * ((schedule->length * 13) + 1));
+    char *periods_debug_str = malloc(sizeof(char) * ((schedule->periods_count * 13) + 1));
     periods_debug_str[0] = '\0';
 
-    for(uint16_t i = 0; i < schedule->length; ++i)
+    for(uint16_t i = 0; i < schedule->periods_count; ++i)
     {
         sprintf(
             periods_debug_str + (13 * i),
@@ -315,7 +316,7 @@ schedule_debug(schedule_t *schedule)
         );
     }
 
-    LOGGER_DEBUG("(4/4) periods: %s\n", periods_debug_str);
+    LOGGER_DEBUG("(3/3) periods: %s\n", periods_debug_str);
 
     free(periods_debug_str);
 }

From f91e0bffb1134d1474a18ce5b584eae5db1d071c Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Tue, 25 Aug 2020 00:49:39 +0200
Subject: [PATCH 2/8] fix: reloading relay schedules during different command
 caused bad behaviour

---
 CMakeLists.txt         |  2 +-
 src/handlers/command.c | 18 +++++++++++++++---
 src/models/schedule.c  |  2 +-
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0eee6a6..3bc8b68 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.1
+        VERSION 0.3.2
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/src/handlers/command.c b/src/handlers/command.c
index b511e02..e746478 100644
--- a/src/handlers/command.c
+++ b/src/handlers/command.c
@@ -161,15 +161,27 @@ handler_command_relay_schedules_set(mpack_node_t map)
     {
         mpack_node_t schedule_map = mpack_node_array_at(schedules_array, i);
 
-        handler_command_schedule_update(schedule_map);
-
         uuid_t schedule_uid;
         memcpy(schedule_uid, mpack_node_data(mpack_node_map_uint(schedule_map, COMMAND_MAPPING_SCHEDULE_ID)), sizeof(uuid_t));
 
+        uint16_t periods_count = mpack_node_u16(mpack_node_map_uint(schedule_map, COMMAND_MAPPING_PERIODS_COUNT));
+        uint16_t *periods = (uint16_t*)mpack_node_bin_data(mpack_node_map_uint(schedule_map, COMMAND_MAPPING_PERIODS_BLOB));
+
         schedule_t *schedule = schedule_get_by_uid(schedule_uid);
 
+        schedule_t *new_schedule = schedule_create(schedule_uid, periods_count, periods);
+
+        if(schedule)
+        {
+            new_schedule->id = schedule->id;
+            schedule_free(schedule);
+        }
+
+        schedule_save(new_schedule);
+        schedule_debug(new_schedule);
+
         relay_debug(target_relay);
-        junction_relay_schedule_insert(i, target_relay->id, schedule->id);
+        junction_relay_schedule_insert(i, target_relay->id, new_schedule->id);
     }
 
     relay_reload_schedules(target_relay);
diff --git a/src/models/schedule.c b/src/models/schedule.c
index d895637..4c279c9 100644
--- a/src/models/schedule.c
+++ b/src/models/schedule.c
@@ -296,7 +296,7 @@ schedule_debug(schedule_t *schedule)
         return;
     }
     char uuid_str[UUID_STR_LEN];
-    uuid_unparse(schedule->uid, uuid_str);
+    schedule_uid_unparse(schedule->uid, uuid_str);
     LOGGER_DEBUG("(1/3) %s @ %p\n", uuid_str, (void*)schedule);
     LOGGER_DEBUG("(2/3) id: %3d; period count: %3d\n", schedule->id, schedule->periods_count);
 

From ce674a746ac8e9bf42d7cb463a210e3ac45cc499 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Tue, 25 Aug 2020 10:50:31 +0200
Subject: [PATCH 3/8] remove: too many debug calls

---
 CMakeLists.txt         | 2 +-
 src/handlers/command.c | 5 -----
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3bc8b68..b738d89 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.2
+        VERSION 0.3.3
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/src/handlers/command.c b/src/handlers/command.c
index e746478..d2c04c9 100644
--- a/src/handlers/command.c
+++ b/src/handlers/command.c
@@ -93,7 +93,6 @@ handler_command_relay_name_set(mpack_node_t map)
         return;
     }
     relay_set_name(global_controller->relays[relay_num], relay_name);
-    relay_debug(global_controller->relays[relay_num]);
     LOGGER_DEBUG("setting new name %s for relay %d\n", relay_name, relay_num);
     relay_save(global_controller->relays[relay_num]);
 }
@@ -118,7 +117,6 @@ handler_command_schedule_update(mpack_node_t map)
     }
 
     schedule_save(new_schedule);
-    schedule_debug(new_schedule);
 
     int *relay_ids = junction_relay_schedule_get_relay_ids_with_schedule(new_schedule->id);
 
@@ -178,14 +176,11 @@ handler_command_relay_schedules_set(mpack_node_t map)
         }
 
         schedule_save(new_schedule);
-        schedule_debug(new_schedule);
 
-        relay_debug(target_relay);
         junction_relay_schedule_insert(i, target_relay->id, new_schedule->id);
     }
 
     relay_reload_schedules(target_relay);
-    relay_debug(target_relay);
 
     database_transaction_commit();
 }

From db7eb6305c5224fc7d18932217f52c6f46fb48df Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Tue, 25 Aug 2020 11:42:05 +0200
Subject: [PATCH 4/8] add: random status sending to broker

---
 CMakeLists.txt      | 2 +-
 src/handlers/loop.c | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b738d89..d27cf5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.3
+        VERSION 0.3.4
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/src/handlers/loop.c b/src/handlers/loop.c
index 76a5999..f2c6671 100644
--- a/src/handlers/loop.c
+++ b/src/handlers/loop.c
@@ -60,9 +60,13 @@ handler_loop(struct mg_connection *c_mqtt)
             sprintf(topic_buf, "controller/%s/relay/%u", controller_uid, i);
             sprintf(payload_buf, "%u", is_on);
             mg_mqtt_publish(c_mqtt, topic_buf, 0, MG_MQTT_QOS(0), payload_buf, strlen(payload_buf));
-            relay->sent_to_broker = 1;
+            relay->sent_to_broker = (rand() % 45) + 15;
             LOGGER_DEBUG("sent relay %d status (%d) to mqtt broker\n", i, is_on);
         }
+        if(relay->sent_to_broker)
+        {
+            --relay->sent_to_broker;
+        }
         relay->is_on = is_on;
         relay->is_on_schedule = is_on_schedule;
 

From 14f93e44ce409350a92bb98904dd0c2a16099a32 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Thu, 27 Aug 2020 10:46:52 +0200
Subject: [PATCH 5/8] add: only allow pulse when on schedule

---
 CMakeLists.txt         |  2 +-
 include/models/relay.h |  1 -
 src/handlers/loop.c    | 27 +++++++++++++++------------
 src/models/relay.c     |  2 --
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d27cf5e..ec9f33a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.4
+        VERSION 0.3.5
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/include/models/relay.h b/include/models/relay.h
index 6ffb258..bbac159 100644
--- a/include/models/relay.h
+++ b/include/models/relay.h
@@ -13,7 +13,6 @@ typedef struct
     int id;
     uint8_t number;
     int is_on;
-    int is_on_schedule;
     int pulse_timer;
     int sent_to_broker;
     char name[MAX_NAME_LENGTH + 1];
diff --git a/src/handlers/loop.c b/src/handlers/loop.c
index f2c6671..035e462 100644
--- a/src/handlers/loop.c
+++ b/src/handlers/loop.c
@@ -34,21 +34,25 @@ handler_loop(struct mg_connection *c_mqtt)
         int is_on = 0;
         
         int is_on_schedule = relay_is_on_schedule(relay, &time_now);
+        int pulse_relay = global_config.relay_configs[i].pulse_duration;
 
-        if(relay->is_on_schedule != is_on_schedule && relay->is_on_schedule != -1)
+        if(is_on_schedule)
         {
-            relay->pulse_timer = global_config.relay_configs[i].pulse_duration;
+            if(pulse_relay)
+            {
+                is_on = 1;
+                --relay->pulse_timer;
+                LOGGER_DEBUG("relay %d is pulsing for %d more seconds\n", i, relay->pulse_timer);
+            }
+            else
+            {
+                is_on = 1;
+                LOGGER_DEBUG("relay %d is active\n", i);
+            }
         }
-        if(is_on_schedule && !global_config.relay_configs[i].pulse_duration)
+        else
         {
-            is_on = 1;
-            LOGGER_DEBUG("relay %d is active\n", i);
-        }
-        if(relay->pulse_timer > 0)
-        {
-            is_on = 1;
-            --relay->pulse_timer;
-            LOGGER_DEBUG("relay %d is pulsing for %d more seconds\n", i, relay->pulse_timer);
+            relay->pulse_timer = 0;
         }
 
         if(relay->is_on != is_on)
@@ -68,7 +72,6 @@ handler_loop(struct mg_connection *c_mqtt)
             --relay->sent_to_broker;
         }
         relay->is_on = is_on;
-        relay->is_on_schedule = is_on_schedule;
 
         if(global_config.relay_configs[i].inverted)
         {
diff --git a/src/models/relay.c b/src/models/relay.c
index 903e1bf..38c3aa0 100644
--- a/src/models/relay.c
+++ b/src/models/relay.c
@@ -60,7 +60,6 @@ relay_db_select_mapper(sqlite3_stmt *stmt)
     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;
 
@@ -177,7 +176,6 @@ relay_create(uint8_t 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;
 

From d82a6219f0682eef1e4b88adb8679eb66124c221 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Thu, 27 Aug 2020 12:01:49 +0200
Subject: [PATCH 6/8] fix: forgot pulse condition

---
 CMakeLists.txt      | 2 +-
 src/handlers/loop.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ec9f33a..9d07b24 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.5
+        VERSION 0.3.6
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/src/handlers/loop.c b/src/handlers/loop.c
index 035e462..f121bcd 100644
--- a/src/handlers/loop.c
+++ b/src/handlers/loop.c
@@ -38,7 +38,7 @@ handler_loop(struct mg_connection *c_mqtt)
 
         if(is_on_schedule)
         {
-            if(pulse_relay)
+            if(pulse_relay && relay->pulse_timer)
             {
                 is_on = 1;
                 --relay->pulse_timer;

From 25eab5d38ec867cb3834cd31acb6f75029a9cb5e Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Thu, 27 Aug 2020 13:22:10 +0200
Subject: [PATCH 7/8] fix: see last commit (I need tests)

---
 CMakeLists.txt      |  2 +-
 src/handlers/loop.c | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9d07b24..3223e1c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.3.6
+        VERSION 0.3.7
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/src/handlers/loop.c b/src/handlers/loop.c
index f121bcd..2076952 100644
--- a/src/handlers/loop.c
+++ b/src/handlers/loop.c
@@ -38,17 +38,17 @@ handler_loop(struct mg_connection *c_mqtt)
 
         if(is_on_schedule)
         {
+            if(!pulse_relay)
+            {
+                is_on = 1;
+                LOGGER_DEBUG("relay %d is active\n", i);
+            }
             if(pulse_relay && relay->pulse_timer)
             {
                 is_on = 1;
                 --relay->pulse_timer;
                 LOGGER_DEBUG("relay %d is pulsing for %d more seconds\n", i, relay->pulse_timer);
             }
-            else
-            {
-                is_on = 1;
-                LOGGER_DEBUG("relay %d is active\n", i);
-            }
         }
         else
         {

From 5afff53301cb8bb8af13e5a681591961aa76a4c3 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Sat, 27 May 2023 00:37:28 +0200
Subject: [PATCH 8/8] Remove unused lmdb.h

---
 include/models/controller.h | 1 -
 include/models/relay.h      | 1 -
 include/models/schedule.h   | 1 -
 src/main.c                  | 1 -
 4 files changed, 4 deletions(-)

diff --git a/include/models/controller.h b/include/models/controller.h
index 1cf4fad..10d5827 100644
--- a/include/models/controller.h
+++ b/include/models/controller.h
@@ -3,7 +3,6 @@
 
 #include <uuid/uuid.h>
 #include <stdint.h>
-#include <lmdb.h>
 
 #include <config.h>
 #include <models/relay.h>
diff --git a/include/models/relay.h b/include/models/relay.h
index bbac159..498ea30 100644
--- a/include/models/relay.h
+++ b/include/models/relay.h
@@ -3,7 +3,6 @@
 
 #include <stdint.h>
 #include <time.h>
-#include <lmdb.h>
 
 #include <constants.h>
 #include <models/schedule.h>
diff --git a/include/models/schedule.h b/include/models/schedule.h
index 212cd81..ae91e14 100644
--- a/include/models/schedule.h
+++ b/include/models/schedule.h
@@ -3,7 +3,6 @@
 
 #include <stdint.h>
 #include <uuid/uuid.h>
-#include <lmdb.h>
 
 #include <models/period.h>
 
diff --git a/src/main.c b/src/main.c
index 17149e2..a13c75e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,7 +2,6 @@
 #include <string.h>
 #include <stdio.h>
 #include <time.h>
-#include <lmdb.h>
 #include <signal.h>
 #include <syslog.h>