From d1cb50cf98038b66f5a5a4ed4f025065dcb411132dee0ac591dffc372a54ecc9 Mon Sep 17 00:00:00 2001
From: localhorst <localhorst@mosad.xyz>
Date: Mon, 16 Dec 2024 22:12:29 +0100
Subject: [PATCH 1/5] some idea

---
 main/main.c    | 56 +++++++++++++++++++++++++++++++++++++++++++++-----
 main/metrics.c |  2 ++
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/main/main.c b/main/main.c
index 1ee85ff..a1f6628 100644
--- a/main/main.c
+++ b/main/main.c
@@ -11,6 +11,9 @@
 #include <freertos/task.h>
 #include "freertos/timers.h"
 #include "nvs_flash.h"
+#include <time.h>
+#include <sys/time.h>
+#include <esp_sntp.h>
 
 #include "safety.h"
 #include "metrics.h"
@@ -23,6 +26,39 @@
 
 static const char *TAG = "smart-oil-heater-control-system";
 
+// Function to wait for time synchronization
+void obtain_time()
+{
+    time_t now = 0;
+    struct tm timeinfo = {0};
+
+    // Wait for the time to be set
+  //  while (timeinfo.tm_year < (2020 - 1900))
+    {
+        ESP_LOGI(TAG, "Waiting for system time to be set...");
+        vTaskDelay(2000 / portTICK_PERIOD_MS);
+        time(&now);
+        localtime_r(&now, &timeinfo);
+    }
+
+    ESP_LOGI(TAG, "System time is set.");
+}
+
+// Function to print the current time
+void print_current_time()
+{
+    time_t now;
+    struct tm timeinfo;
+
+    time(&now);
+    localtime_r(&now, &timeinfo);
+
+    char strftime_buf[64];
+    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
+
+    ESP_LOGI(TAG, "Current time: %s", strftime_buf);
+}
+
 void app_main(void)
 {
     ESP_LOGI(TAG, "starting ...");
@@ -37,14 +73,24 @@ void app_main(void)
     ESP_ERROR_CHECK(ret);
 
     // TODO: Error handling!
-    initOutputs();
-    initInputs();
-    initSafety();
-    initControl();
+    //initOutputs();
+    //initInputs();
+    //initSafety();
+    //initControl();
     initMetrics();
 
+    esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
+    esp_sntp_setservername(0, "10.1.0.1"); // Set NTP server
+    esp_sntp_init();
+
     while (1)
     {
-        vTaskDelay(pdMS_TO_TICKS(2048));
+        vTaskDelay(pdMS_TO_TICKS(10000U));
+
+        // Obtain the current time
+        obtain_time();
+
+        // Print the current time
+        print_current_time();
     }
 }
\ No newline at end of file
diff --git a/main/metrics.c b/main/metrics.c
index c7cce67..2823dbb 100644
--- a/main/metrics.c
+++ b/main/metrics.c
@@ -38,6 +38,8 @@ esp_err_t get_metrics_handler(httpd_req_t *req);
 void initMetrics(void)
 {
     connect_wifi();
+    return;
+    
     setup_server();
 
     BaseType_t taskCreated = xTaskCreate(

From 15b74c91f46607e68c9141f99794ecfbc2d3ffbdb34ebee64735eda090a10e65 Mon Sep 17 00:00:00 2001
From: localhorst <localhorst@mosad.xyz>
Date: Tue, 17 Dec 2024 22:26:04 +0100
Subject: [PATCH 2/5] set server and cleanup

---
 .vscode/c_cpp_properties.json | 27 +++++++++++++++++++++
 main/main.c                   | 45 +++++++++++++----------------------
 2 files changed, 44 insertions(+), 28 deletions(-)
 create mode 100644 .vscode/c_cpp_properties.json

diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..0546715
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,27 @@
+{
+    "configurations": [
+      {
+        "name": "ESP-IDF",
+        "compilerPath": "${default}",
+        "compileCommands": "${workspaceFolder}/build/compile_commands.json",
+        "includePath": [
+          "${config:idf.espIdfPath}/components/**",
+          "${config:idf.espIdfPathWin}/components/**",
+          "${config:idf.espAdfPath}/components/**",
+          "${config:idf.espAdfPathWin}/components/**",
+          "${workspaceFolder}/**"
+        ],
+        "browse": {
+          "path": [
+            "${config:idf.espIdfPath}/components",
+            "${config:idf.espIdfPathWin}/components",
+            "${config:idf.espAdfPath}/components/**",
+            "${config:idf.espAdfPathWin}/components/**",
+            "${workspaceFolder}"
+          ],
+          "limitSymbolsToIncludedHeaders": false
+        }
+      }
+    ],
+    "version": 4
+  }
\ No newline at end of file
diff --git a/main/main.c b/main/main.c
index a1f6628..8751ec7 100644
--- a/main/main.c
+++ b/main/main.c
@@ -26,24 +26,6 @@
 
 static const char *TAG = "smart-oil-heater-control-system";
 
-// Function to wait for time synchronization
-void obtain_time()
-{
-    time_t now = 0;
-    struct tm timeinfo = {0};
-
-    // Wait for the time to be set
-  //  while (timeinfo.tm_year < (2020 - 1900))
-    {
-        ESP_LOGI(TAG, "Waiting for system time to be set...");
-        vTaskDelay(2000 / portTICK_PERIOD_MS);
-        time(&now);
-        localtime_r(&now, &timeinfo);
-    }
-
-    ESP_LOGI(TAG, "System time is set.");
-}
-
 // Function to print the current time
 void print_current_time()
 {
@@ -59,6 +41,13 @@ void print_current_time()
     ESP_LOGI(TAG, "Current time: %s", strftime_buf);
 }
 
+// SNTP Callback function
+void time_sync_notification_cb(struct timeval *tv)
+{
+    ESP_LOGI(TAG, "SNTP synchronization completed! Unix Time: %lld", tv->tv_sec);
+    ESP_LOGI(TAG, "Time synchronization callback called.");
+}
+
 void app_main(void)
 {
     ESP_LOGI(TAG, "starting ...");
@@ -73,24 +62,24 @@ void app_main(void)
     ESP_ERROR_CHECK(ret);
 
     // TODO: Error handling!
-    //initOutputs();
-    //initInputs();
-    //initSafety();
-    //initControl();
+    // initOutputs();
+    // initInputs();
+    // initSafety();
+    // initControl();
     initMetrics();
 
     esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
-    esp_sntp_setservername(0, "10.1.0.1"); // Set NTP server
+    esp_sntp_setservername(0, "10.1.0.1");       // Set first NTP server local router
+
+    sntp_set_time_sync_notification_cb(time_sync_notification_cb); // Register the SNTP time sync callback
     esp_sntp_init();
 
     while (1)
     {
-        vTaskDelay(pdMS_TO_TICKS(10000U));
-
-        // Obtain the current time
-        obtain_time();
-
+        vTaskDelay(pdMS_TO_TICKS(1000));
         // Print the current time
         print_current_time();
+
+        ESP_LOGI(TAG, "SNTP Server 0 reachability: %i", esp_sntp_getreachability(0));
     }
 }
\ No newline at end of file

From 0b9f5e2997506ba70b30d4775b23176ff6281cf4b02b4602da8d2d1a634a8787 Mon Sep 17 00:00:00 2001
From: localhorst <localhorst@mosad.xyz>
Date: Thu, 19 Dec 2024 18:58:05 +0100
Subject: [PATCH 3/5] own wifi module

---
 .vscode/settings.json |   5 +-
 README.md             |  10 ++++
 main/CMakeLists.txt   |   4 +-
 main/main.c           |  16 ++++---
 main/metrics.c        | 104 ----------------------------------------
 main/metrics.h        |   2 -
 main/sntp.c           |   0
 main/sntp.h           |   0
 main/wifi.c           | 108 ++++++++++++++++++++++++++++++++++++++++++
 main/wifi.h           |   3 ++
 10 files changed, 137 insertions(+), 115 deletions(-)
 create mode 100644 main/sntp.c
 create mode 100644 main/sntp.h
 create mode 100644 main/wifi.c
 create mode 100644 main/wifi.h

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 884c37d..34ff52a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -17,7 +17,10 @@
         "type_traits": "c",
         "cmath": "c",
         "*.tcc": "c",
-        "*.inc": "c"
+        "*.inc": "c",
+        "safety.h": "c",
+        "event_groups.h": "c",
+        "string.h": "c"
     },
     "idf.openOcdConfigs": [
         "board/esp32-wrover-kit-3.3v.cfg"
diff --git a/README.md b/README.md
index 9b900e1..f0dbad7 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,16 @@ Safety <|-- HTTP_Metrics
         +getSafetyState()
     }
 
+
+    class Wifi{
+        +initWifi()
+    }
+
+    class SNTP{
+        +initSntp()
+        +getSntpState()
+    }
+
     class Metrics{
         +initMetrics()
         -taskMetrics()
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index fda1709..cef8b5e 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -1,7 +1,9 @@
-idf_component_register(SRCS "main.c"
+idf_component_register(SRCS "sntp.c" "wifi.c" "main.c"
                             "metrics.c"
                             "inputs.c"
                             "outputs.c"
                             "control.c"
                             "safety.c"
+                            "wifi.c"
+                            "sntp.c"
                     INCLUDE_DIRS ".")
diff --git a/main/main.c b/main/main.c
index 8751ec7..a34a9bc 100644
--- a/main/main.c
+++ b/main/main.c
@@ -20,6 +20,7 @@
 #include "outputs.h"
 #include "inputs.h"
 #include "control.h"
+#include "wifi.h"
 
 #define I2C_MASTER_SCL 19
 #define I2C_MASTER_SDA 18
@@ -65,21 +66,22 @@ void app_main(void)
     // initOutputs();
     // initInputs();
     // initSafety();
+    initWifi();
     // initControl();
-    initMetrics();
+    // initMetrics();
 
-    esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
-    esp_sntp_setservername(0, "10.1.0.1");       // Set first NTP server local router
+    // esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
+    // esp_sntp_setservername(0, "10.1.0.1");       // Set first NTP server local router
 
-    sntp_set_time_sync_notification_cb(time_sync_notification_cb); // Register the SNTP time sync callback
-    esp_sntp_init();
+    // sntp_set_time_sync_notification_cb(time_sync_notification_cb); // Register the SNTP time sync callback
+    // esp_sntp_init();
 
     while (1)
     {
         vTaskDelay(pdMS_TO_TICKS(1000));
         // Print the current time
-        print_current_time();
+        // print_current_time();
 
-        ESP_LOGI(TAG, "SNTP Server 0 reachability: %i", esp_sntp_getreachability(0));
+        // ESP_LOGI(TAG, "SNTP Server 0 reachability: %i", esp_sntp_getreachability(0));
     }
 }
\ No newline at end of file
diff --git a/main/metrics.c b/main/metrics.c
index 2823dbb..1a3886d 100644
--- a/main/metrics.c
+++ b/main/metrics.c
@@ -1,28 +1,15 @@
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include "esp_timer.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
-#include "esp_system.h"
-#include "spi_flash_mmap.h"
 #include "esp_wifi.h"
-#include "esp_event.h"
-#include "freertos/event_groups.h"
 #include "esp_log.h"
-#include "esp_netif.h"
-#include <lwip/sockets.h>
-#include <lwip/sys.h>
-#include <lwip/api.h>
-#include <lwip/netdb.h>
 
 #include "metrics.h"
 #include "outputs.h"
 #include "inputs.h"
 #include "safety.h"
 
-static EventGroupHandle_t s_wifi_event_group;
-
 static const char *TAG = "smart-oil-heater-control-system-metrics";
 
 char caHtmlResponse[HTML_RESPONSE_SIZE];
@@ -31,15 +18,11 @@ static sMetric aMetrics[METRIC_MAX_COUNT];
 static uint16_t u16MetricCounter = 0U;
 
 void taskMetrics(void *pvParameters);
-void connect_wifi(void);
 httpd_handle_t setup_server(void);
 esp_err_t get_metrics_handler(httpd_req_t *req);
 
 void initMetrics(void)
 {
-    connect_wifi();
-    return;
-    
     setup_server();
 
     BaseType_t taskCreated = xTaskCreate(
@@ -227,93 +210,6 @@ void vSetMetrics(sMetric *paMetrics, uint16_t u16Size)
     }
 }
 
-static void event_handler(void *arg, esp_event_base_t event_base,
-                          int32_t event_id, void *event_data)
-{
-    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
-    {
-        esp_wifi_connect();
-    }
-    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
-    {
-        esp_wifi_connect();
-        ESP_LOGI(TAG, "Retry to connect to the AP");
-    }
-    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
-    {
-        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
-        ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip));
-        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
-    }
-}
-
-void connect_wifi(void)
-{
-    s_wifi_event_group = xEventGroupCreate();
-    ESP_ERROR_CHECK(esp_netif_init());
-    ESP_ERROR_CHECK(esp_event_loop_create_default());
-
-    esp_netif_t *my_sta = esp_netif_create_default_wifi_sta();
-    esp_netif_dhcpc_stop(my_sta);
-    esp_netif_ip_info_t ip_info;
-    ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDR);
-    ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GATEWAY_IP_ADDR);
-    ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_IP_NETMASK);
-    esp_netif_set_ip_info(my_sta, &ip_info);
-
-    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
-    esp_event_handler_instance_t instance_any_id;
-    esp_event_handler_instance_t instance_got_ip;
-    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
-                                                        ESP_EVENT_ANY_ID,
-                                                        &event_handler,
-                                                        NULL,
-                                                        &instance_any_id));
-    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
-                                                        IP_EVENT_STA_GOT_IP,
-                                                        &event_handler,
-                                                        NULL,
-                                                        &instance_got_ip));
-
-    wifi_config_t wifi_config = {
-        .sta = {
-            .ssid = CONFIG_SSID,
-            .password = CONFIG_WIFI_PASSWORD,
-            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
-        },
-    };
-    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
-    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
-
-    ESP_ERROR_CHECK(esp_wifi_start());
-
-    ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(78));      // Set max power to 19.5 dBm (78 in units of 0.25 dBm)
-    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MIN_MODEM)); // Use power-saving mode
-
-    ESP_LOGI(TAG, "wifi_init_sta finished.");
-
-    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
-                                           WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
-                                           pdFALSE,
-                                           pdFALSE,
-                                           portMAX_DELAY);
-
-    if (bits & WIFI_CONNECTED_BIT)
-    {
-        ESP_LOGI(TAG, "Connected to ap SSID:%s", CONFIG_SSID);
-    }
-    else if (bits & WIFI_FAIL_BIT)
-    {
-        ESP_LOGI(TAG, "Failed to connect to SSID:%s", CONFIG_SSID);
-    }
-    else
-    {
-        ESP_LOGE(TAG, "Unexpected event");
-    }
-    vEventGroupDelete(s_wifi_event_group);
-}
-
 esp_err_t get_metrics_handler(httpd_req_t *req)
 {
     if (xSemaphoreTakeRecursive(xMutexAccessMetricResponse, pdMS_TO_TICKS(5000)) == pdTRUE)
diff --git a/main/metrics.h b/main/metrics.h
index 7e8a161..ad7dd23 100644
--- a/main/metrics.h
+++ b/main/metrics.h
@@ -2,8 +2,6 @@
 
 #include <esp_http_server.h>
 
-#define WIFI_CONNECTED_BIT BIT0
-#define WIFI_FAIL_BIT BIT1
 #define HTML_RESPONSE_SIZE 1024U
 #define METRIC_NAME_MAX_SIZE 256U
 #define METRIC_MAX_COUNT 64U
diff --git a/main/sntp.c b/main/sntp.c
new file mode 100644
index 0000000..473a0f4
diff --git a/main/sntp.h b/main/sntp.h
new file mode 100644
index 0000000..473a0f4
diff --git a/main/wifi.c b/main/wifi.c
new file mode 100644
index 0000000..d1fd0c1
--- /dev/null
+++ b/main/wifi.c
@@ -0,0 +1,108 @@
+#include <string.h>
+#include "esp_timer.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "freertos/event_groups.h"
+#include "esp_log.h"
+#include "esp_netif.h"
+#include <lwip/sockets.h>
+
+#include "wifi.h"
+
+#define WIFI_CONNECTED_BIT BIT0
+#define WIFI_FAIL_BIT BIT1
+
+static const char *TAG = "smart-oil-heater-control-system-wifi";
+
+static EventGroupHandle_t s_wifi_event_group;
+static void event_handler(void *arg, esp_event_base_t event_base,
+                          int32_t event_id, void *event_data);
+
+void initWifi(void)
+{
+    s_wifi_event_group = xEventGroupCreate();
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    esp_netif_t *my_sta = esp_netif_create_default_wifi_sta();
+    esp_netif_dhcpc_stop(my_sta);
+    esp_netif_ip_info_t ip_info;
+    ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDR);
+    ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GATEWAY_IP_ADDR);
+    ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_IP_NETMASK);
+    esp_netif_set_ip_info(my_sta, &ip_info);
+
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+    esp_event_handler_instance_t instance_any_id;
+    esp_event_handler_instance_t instance_got_ip;
+    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
+                                                        ESP_EVENT_ANY_ID,
+                                                        &event_handler,
+                                                        NULL,
+                                                        &instance_any_id));
+    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
+                                                        IP_EVENT_STA_GOT_IP,
+                                                        &event_handler,
+                                                        NULL,
+                                                        &instance_got_ip));
+
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = CONFIG_SSID,
+            .password = CONFIG_WIFI_PASSWORD,
+            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
+        },
+    };
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
+
+    ESP_ERROR_CHECK(esp_wifi_start());
+
+    ESP_ERROR_CHECK(esp_wifi_set_max_tx_power(78));      // Set max power to 19.5 dBm (78 in units of 0.25 dBm)
+    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MIN_MODEM)); // Use power-saving mode
+
+    ESP_LOGI(TAG, "wifi_init_sta finished.");
+
+    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
+                                           WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
+                                           pdFALSE,
+                                           pdFALSE,
+                                           portMAX_DELAY);
+
+    if (bits & WIFI_CONNECTED_BIT)
+    {
+        ESP_LOGI(TAG, "Connected to ap SSID:%s", CONFIG_SSID);
+    }
+    else if (bits & WIFI_FAIL_BIT)
+    {
+        ESP_LOGI(TAG, "Failed to connect to SSID:%s", CONFIG_SSID);
+    }
+    else
+    {
+        ESP_LOGE(TAG, "Unexpected event");
+    }
+    vEventGroupDelete(s_wifi_event_group);
+}
+
+static void event_handler(void *arg, esp_event_base_t event_base,
+                          int32_t event_id, void *event_data)
+{
+    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
+    {
+        esp_wifi_connect();
+    }
+    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
+    {
+        esp_wifi_connect();
+        ESP_LOGI(TAG, "Retry to connect to the AP");
+    }
+    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
+    {
+        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
+        ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip));
+        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
+    }
+}
\ No newline at end of file
diff --git a/main/wifi.h b/main/wifi.h
new file mode 100644
index 0000000..380c625
--- /dev/null
+++ b/main/wifi.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void initWifi(void);
\ No newline at end of file

From e5bb620a37860eb37a96eafe35154eb2a629c44b363bba41859bd2030981c1be Mon Sep 17 00:00:00 2001
From: localhorst <localhorst@mosad.xyz>
Date: Thu, 19 Dec 2024 20:33:51 +0100
Subject: [PATCH 4/5] sntp module

---
 .vscode/settings.json  |  5 +++-
 README.md              | 12 +++++----
 main/Kconfig.projbuild |  3 +++
 main/control.c         | 21 +++++++++------
 main/main.c            | 61 ++++++------------------------------------
 main/metrics.c         | 18 +++++++++++++
 main/sntp.c            | 30 +++++++++++++++++++++
 main/sntp.h            | 11 ++++++++
 8 files changed, 94 insertions(+), 67 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 34ff52a..b007ac5 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -20,7 +20,10 @@
         "*.inc": "c",
         "safety.h": "c",
         "event_groups.h": "c",
-        "string.h": "c"
+        "string.h": "c",
+        "time.h": "c",
+        "timers.h": "c",
+        "nvs_flash.h": "c"
     },
     "idf.openOcdConfigs": [
         "board/esp32-wrover-kit-3.3v.cfg"
diff --git a/README.md b/README.md
index f0dbad7..bdafc6b 100644
--- a/README.md
+++ b/README.md
@@ -7,13 +7,15 @@
 classDiagram
 Inputs <|-- Control
 Outputs <|-- Control
+Sntp <|-- Control
 Inputs <|-- Safety
 Outputs <|--|> Safety
 
-Inputs <|-- HTTP_Metrics
-Outputs <|-- HTTP_Metrics
-Control <|-- HTTP_Metrics
-Safety <|-- HTTP_Metrics
+Inputs <|-- Metrics
+Outputs <|-- Metrics
+Control <|-- Metrics
+Safety <|-- Metrics
+Sntp <|-- Metrics
 
     class Inputs{
         +initInputs()
@@ -52,7 +54,7 @@ Safety <|-- HTTP_Metrics
         +initWifi()
     }
 
-    class SNTP{
+    class Sntp{
         +initSntp()
         +getSntpState()
     }
diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild
index 990fa8e..c855f47 100644
--- a/main/Kconfig.projbuild
+++ b/main/Kconfig.projbuild
@@ -15,5 +15,8 @@ menu "Smart Oil Heating Control System"
     config STATIC_GATEWAY_IP_ADDR
         string "Static IPv4 gateway address"
         default "192.168.0.1"
+    config SNTP_SERVER_IP_ADDR
+        string "SNTP IPv4 server address"
+        default "192.168.0.1"
 
 endmenu
diff --git a/main/control.c b/main/control.c
index 0b64e78..42f89f8 100644
--- a/main/control.c
+++ b/main/control.c
@@ -5,6 +5,7 @@
 #include "outputs.h"
 #include "inputs.h"
 #include "safety.h"
+#include "sntp.h"
 
 #define PERIODIC_INTERVAL 1U // run safety checks every 1sec
 
@@ -40,16 +41,20 @@ void taskControl(void *pvParameters)
     {
         vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS);
 
-        if (getSafetyState() == SAFETY_NO_ERROR)
-        {
-            // TODO: control the burner based on timetable
-
-            setCirculationPumpState(DISABLED);
-            setBurnerState(ENABLED);
-        }
-        else
+        if (getSafetyState() != SAFETY_NO_ERROR)
         {
             ESP_LOGW(TAG, "Control not possible due to safety fault!");
+            continue;
         }
+
+        if (getSntpState() != SYNC_SUCCESSFUL)
+        {
+            ESP_LOGW(TAG, "Control not possible due to sntp fault!");
+            continue;
+        }
+
+        // TODO: control the burner based on timetable
+        setCirculationPumpState(DISABLED);
+        setBurnerState(ENABLED);
     }
 }
\ No newline at end of file
diff --git a/main/main.c b/main/main.c
index a34a9bc..82c2d63 100644
--- a/main/main.c
+++ b/main/main.c
@@ -1,19 +1,6 @@
-#include <stdio.h>
 #include "esp_log.h"
-#include "driver/i2c.h"
 #include <esp_system.h>
-#include <bmp280.h>
-#include <dht.h>
-#include <aht.h>
-#include <veml7700.h>
-#include <string.h>
-#include <freertos/FreeRTOS.h>
-#include <freertos/task.h>
-#include "freertos/timers.h"
 #include "nvs_flash.h"
-#include <time.h>
-#include <sys/time.h>
-#include <esp_sntp.h>
 
 #include "safety.h"
 #include "metrics.h"
@@ -21,34 +8,10 @@
 #include "inputs.h"
 #include "control.h"
 #include "wifi.h"
-
-#define I2C_MASTER_SCL 19
-#define I2C_MASTER_SDA 18
+#include "sntp.h"
 
 static const char *TAG = "smart-oil-heater-control-system";
 
-// Function to print the current time
-void print_current_time()
-{
-    time_t now;
-    struct tm timeinfo;
-
-    time(&now);
-    localtime_r(&now, &timeinfo);
-
-    char strftime_buf[64];
-    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
-
-    ESP_LOGI(TAG, "Current time: %s", strftime_buf);
-}
-
-// SNTP Callback function
-void time_sync_notification_cb(struct timeval *tv)
-{
-    ESP_LOGI(TAG, "SNTP synchronization completed! Unix Time: %lld", tv->tv_sec);
-    ESP_LOGI(TAG, "Time synchronization callback called.");
-}
-
 void app_main(void)
 {
     ESP_LOGI(TAG, "starting ...");
@@ -63,25 +26,17 @@ void app_main(void)
     ESP_ERROR_CHECK(ret);
 
     // TODO: Error handling!
-    // initOutputs();
-    // initInputs();
-    // initSafety();
+    initOutputs();
+    initInputs();
+    initSafety();
     initWifi();
-    // initControl();
-    // initMetrics();
-
-    // esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
-    // esp_sntp_setservername(0, "10.1.0.1");       // Set first NTP server local router
-
-    // sntp_set_time_sync_notification_cb(time_sync_notification_cb); // Register the SNTP time sync callback
-    // esp_sntp_init();
+    initSntp();
+    initControl();
+    initMetrics();
 
     while (1)
     {
         vTaskDelay(pdMS_TO_TICKS(1000));
-        // Print the current time
-        // print_current_time();
-
-        // ESP_LOGI(TAG, "SNTP Server 0 reachability: %i", esp_sntp_getreachability(0));
+        // Do nothing ;-)
     }
 }
\ No newline at end of file
diff --git a/main/metrics.c b/main/metrics.c
index 1a3886d..dcb90cf 100644
--- a/main/metrics.c
+++ b/main/metrics.c
@@ -4,11 +4,14 @@
 #include "freertos/task.h"
 #include "esp_wifi.h"
 #include "esp_log.h"
+#include <time.h>
+#include <sys/time.h>
 
 #include "metrics.h"
 #include "outputs.h"
 #include "inputs.h"
 #include "safety.h"
+#include "sntp.h"
 
 static const char *TAG = "smart-oil-heater-control-system-metrics";
 
@@ -57,6 +60,21 @@ void taskMetrics(void *pvParameters)
         aMetrics[u16MetricCounter].fMetricValue = (esp_timer_get_time() / 1000000U);
         u16MetricCounter++;
 
+        /*SNTP Status*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "sntp_status");
+        aMetrics[u16MetricCounter].fMetricValue = getSntpState();
+        u16MetricCounter++;
+
+        /*System time
+        time_t now;
+        struct tm timeinfo;
+        time(&now);
+        localtime_r(&now, &timeinfo);
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "system_unixtime");
+        aMetrics[u16MetricCounter].fMetricValue = (float) now;
+        u16MetricCounter++;
+        */
+
         /*Wifi RSSI*/
         wifi_ap_record_t ap;
         esp_wifi_sta_get_ap_info(&ap);
diff --git a/main/sntp.c b/main/sntp.c
index 473a0f4..638bfa4 100644
--- a/main/sntp.c
+++ b/main/sntp.c
@@ -0,0 +1,30 @@
+#include <time.h>
+#include <sys/time.h>
+#include <esp_sntp.h>
+#include "esp_log.h"
+
+#include "sntp.h"
+
+static const char *TAG = "smart-oil-heater-control-system-sntp";
+static eSntpState sntpState = SYNC_NOT_STARTED;
+void time_sync_notification_cb(struct timeval *tv);
+
+void initSntp(void)
+{
+    esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
+    esp_sntp_setservername(0, CONFIG_SNTP_SERVER_IP_ADDR);
+
+    sntp_set_time_sync_notification_cb(time_sync_notification_cb);
+    esp_sntp_init();
+}
+
+eSntpState getSntpState(void)
+{
+    return sntpState;
+}
+
+void time_sync_notification_cb(struct timeval *tv)
+{
+    ESP_LOGI(TAG, "SNTP synchronization! Unix Time: %lld", tv->tv_sec);
+    sntpState = SYNC_SUCCESSFUL;
+}
diff --git a/main/sntp.h b/main/sntp.h
index 473a0f4..4feb88b 100644
--- a/main/sntp.h
+++ b/main/sntp.h
@@ -0,0 +1,11 @@
+#pragma once
+
+typedef enum _SntpState
+{
+    SYNC_SUCCESSFUL,
+    SYNC_NOT_STARTED,
+    SYNC_FAILED,
+} eSntpState;
+
+void initSntp(void);
+eSntpState getSntpState(void);
\ No newline at end of file

From bf8038d9e291166e5343b8b841a8356c500f076fb5fa514d5455eee4cb4a9dc8 Mon Sep 17 00:00:00 2001
From: localhorst <localhorst@mosad.xyz>
Date: Thu, 19 Dec 2024 21:15:09 +0100
Subject: [PATCH 5/5] cleanup and sort metrics

---
 main/metrics.c | 211 +++++++++++++++++++++++++++----------------------
 main/metrics.h |  10 +++
 2 files changed, 128 insertions(+), 93 deletions(-)

diff --git a/main/metrics.c b/main/metrics.c
index dcb90cf..e0c8719 100644
--- a/main/metrics.c
+++ b/main/metrics.c
@@ -55,133 +55,113 @@ void taskMetrics(void *pvParameters)
 
         u16MetricCounter = 0U;
 
-        /*Uptime*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "uptime_seconds");
-        aMetrics[u16MetricCounter].fMetricValue = (esp_timer_get_time() / 1000000U);
-        u16MetricCounter++;
+        /*Circulation Pump State*/
+        if (getCirculationPumpState() == ENABLED)
+        {
+            strcpy(aMetrics[u16MetricCounter].caMetricName, "circulation_pump_enabled");
+            aMetrics[u16MetricCounter].type = INTEGER_U8;
+            aMetrics[u16MetricCounter].u8MetricValue = 1U;
+            u16MetricCounter++;
+        }
+        else
+        {
+            strcpy(aMetrics[u16MetricCounter].caMetricName, "circulation_pump_enabled");
+            aMetrics[u16MetricCounter].type = INTEGER_U8;
+            aMetrics[u16MetricCounter].u8MetricValue = 0U;
+            u16MetricCounter++;
+        }
 
-        /*SNTP Status*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "sntp_status");
-        aMetrics[u16MetricCounter].fMetricValue = getSntpState();
-        u16MetricCounter++;
-
-        /*System time
-        time_t now;
-        struct tm timeinfo;
-        time(&now);
-        localtime_r(&now, &timeinfo);
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "system_unixtime");
-        aMetrics[u16MetricCounter].fMetricValue = (float) now;
-        u16MetricCounter++;
-        */
-
-        /*Wifi RSSI*/
-        wifi_ap_record_t ap;
-        esp_wifi_sta_get_ap_info(&ap);
-        // printf("WiFi RSSI: %d\n", ap.rssi);
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "wifi_rssi");
-        aMetrics[u16MetricCounter].fMetricValue = ap.rssi;
+        /*Burner Error State*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "burner_fault_pending");
+        aMetrics[u16MetricCounter].type = INTEGER_U8;
+        aMetrics[u16MetricCounter].u8MetricValue = getBurnerError();
         u16MetricCounter++;
 
         /*Burner State*/
         if (getBurnerState() == ENABLED)
         {
             strcpy(aMetrics[u16MetricCounter].caMetricName, "burner_enabled");
-            aMetrics[u16MetricCounter].fMetricValue = 1.0f;
+            aMetrics[u16MetricCounter].type = INTEGER_U8;
+            aMetrics[u16MetricCounter].u8MetricValue = 1U;
             u16MetricCounter++;
         }
         else
         {
             strcpy(aMetrics[u16MetricCounter].caMetricName, "burner_enabled");
-            aMetrics[u16MetricCounter].fMetricValue = 0.0f;
-            u16MetricCounter++;
-        }
-
-        /*Circulation Pump State*/
-        if (getCirculationPumpState() == ENABLED)
-        {
-            strcpy(aMetrics[u16MetricCounter].caMetricName, "circulation_pump_enabled");
-            aMetrics[u16MetricCounter].fMetricValue = 1.0f;
-            u16MetricCounter++;
-        }
-        else
-        {
-            strcpy(aMetrics[u16MetricCounter].caMetricName, "circulation_pump_enabled");
-            aMetrics[u16MetricCounter].fMetricValue = 0.0f;
-            u16MetricCounter++;
-        }
-
-        /*Burner Error State*/
-        if (getBurnerError() == FAULT)
-        {
-            strcpy(aMetrics[u16MetricCounter].caMetricName, "burner_fault_pending");
-            aMetrics[u16MetricCounter].fMetricValue = 1.0f;
-            u16MetricCounter++;
-        }
-        else
-        {
-            strcpy(aMetrics[u16MetricCounter].caMetricName, "burner_fault_pending");
-            aMetrics[u16MetricCounter].fMetricValue = 0.0f;
+            aMetrics[u16MetricCounter].type = INTEGER_U8;
+            aMetrics[u16MetricCounter].u8MetricValue = 0U;
             u16MetricCounter++;
         }
 
         /*Chamber Temperature*/
         strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature");
+        aMetrics[u16MetricCounter].type = FLOAT;
         aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().fCurrentValue;
         u16MetricCounter++;
 
-        /*Outdoor Temperature*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature");
-        aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().fCurrentValue;
-        u16MetricCounter++;
-
-        /*Chamber Temperature*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature");
-        aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().fCurrentValue;
-        u16MetricCounter++;
-
-        /*Chamber Temperature*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature");
-        aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().fCurrentValue;
-        u16MetricCounter++;
-
         /*Chamber Temperature Average 10s*/
         strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg10");
+        aMetrics[u16MetricCounter].type = FLOAT;
         aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average10s.fValue;
         u16MetricCounter++;
 
-        /*Outdoor Temperature Average 10s*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg10");
-        aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average10s.fValue;
-        u16MetricCounter++;
-
-        /*Chamber Temperature Average 10s*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg10");
-        aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average10s.fValue;
-        u16MetricCounter++;
-
-        /*Chamber Temperature Average 10s*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg10");
-        aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average10s.fValue;
-        u16MetricCounter++;
-
         /*Chamber Temperature Average 60s*/
         strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg60");
+        aMetrics[u16MetricCounter].type = FLOAT;
         aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average60s.fValue;
         u16MetricCounter++;
 
+        /*Inlet Flow Temperature*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().fCurrentValue;
+        u16MetricCounter++;
+
+        /*Inlet Flow Temperature Average 10s*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg10");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average10s.fValue;
+        u16MetricCounter++;
+
+        /*Inlet Flow Temperature Average 60s*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg60");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average60s.fValue;
+        u16MetricCounter++;
+
+        /*Outdoor Temperature*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().fCurrentValue;
+        u16MetricCounter++;
+
+        /*Outdoor Temperature Average 10s*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg10");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average10s.fValue;
+        u16MetricCounter++;
+
         /*Outdoor Temperature Average 60s*/
         strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg60");
+        aMetrics[u16MetricCounter].type = FLOAT;
         aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average60s.fValue;
         u16MetricCounter++;
 
-        /*Chamber Temperature Average 60s*/
-        strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg60");
-        aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average60s.fValue;
+        /*Return Flow Temperature*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().fCurrentValue;
         u16MetricCounter++;
 
-        /*Chamber Temperature Average 60s*/
+        /*Return Flow Temperature Average 10s*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg10");
+        aMetrics[u16MetricCounter].type = FLOAT;
+        aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average10s.fValue;
+        u16MetricCounter++;
+
+        /*Return Flow Temperature Average 60s*/
         strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg60");
+        aMetrics[u16MetricCounter].type = FLOAT;
         aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average60s.fValue;
         u16MetricCounter++;
 
@@ -192,13 +172,43 @@ void taskMetrics(void *pvParameters)
         {
             strcpy(aMetrics[u16MetricCounter].caMetricName, aChecks[i].name);
             strcat(aMetrics[u16MetricCounter].caMetricName, "_status");
-            aMetrics[u16MetricCounter].fMetricValue = aChecks[i].status;
+            aMetrics[u16MetricCounter].type = INTEGER_U8;
+            aMetrics[u16MetricCounter].u8MetricValue = aChecks[i].status;
             u16MetricCounter++;
         }
 
-        /*Safety state*/
+        /*Safety State*/
         strcpy(aMetrics[u16MetricCounter].caMetricName, "safety_state");
-        aMetrics[u16MetricCounter].fMetricValue = getSafetyState();
+        aMetrics[u16MetricCounter].type = INTEGER_U8;
+        aMetrics[u16MetricCounter].u8MetricValue = getSafetyState();
+        u16MetricCounter++;
+
+        /*SNTP Status*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "sntp_status");
+        aMetrics[u16MetricCounter].type = INTEGER_U8;
+        aMetrics[u16MetricCounter].u8MetricValue = getSntpState();
+        u16MetricCounter++;
+
+        /*System Time*/
+        time_t now;
+        time(&now);
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "system_unixtime");
+        aMetrics[u16MetricCounter].type = INTEGER_64;
+        aMetrics[u16MetricCounter].i64MetricValue = now;
+        u16MetricCounter++;
+
+        /*Uptime*/
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "uptime_seconds");
+        aMetrics[u16MetricCounter].type = INTEGER_64;
+        aMetrics[u16MetricCounter].i64MetricValue = (esp_timer_get_time() / 1000000U);
+        u16MetricCounter++;
+
+        /*Wifi RSSI*/
+        wifi_ap_record_t ap;
+        esp_wifi_sta_get_ap_info(&ap);
+        strcpy(aMetrics[u16MetricCounter].caMetricName, "wifi_rssi");
+        aMetrics[u16MetricCounter].type = INTEGER_64;
+        aMetrics[u16MetricCounter].i64MetricValue = ap.rssi;
         u16MetricCounter++;
 
         vSetMetrics(aMetrics, u16MetricCounter);
@@ -214,7 +224,22 @@ void vSetMetrics(sMetric *paMetrics, uint16_t u16Size)
         for (uint16_t u16Index = 0U; u16Index < u16Size; u16Index++)
         {
             char caValueBuffer[64];
-            sprintf(caValueBuffer, " %f", paMetrics[u16Index].fMetricValue);
+
+            switch (paMetrics[u16Index].type)
+            {
+            case FLOAT:
+                sprintf(caValueBuffer, " %f", paMetrics[u16Index].fMetricValue);
+                break;
+            case INTEGER_64:
+                sprintf(caValueBuffer, " %lli", paMetrics[u16Index].i64MetricValue);
+                break;
+            case INTEGER_U8:
+                sprintf(caValueBuffer, " %u", paMetrics[u16Index].u8MetricValue);
+                break;
+            default:
+                break;
+            }
+
             // printf("%s\n", caValueBuffer);
             strcat(caHtmlResponse, paMetrics[u16Index].caMetricName);
             strcat(caHtmlResponse, caValueBuffer);
diff --git a/main/metrics.h b/main/metrics.h
index ad7dd23..b02342a 100644
--- a/main/metrics.h
+++ b/main/metrics.h
@@ -6,10 +6,20 @@
 #define METRIC_NAME_MAX_SIZE 256U
 #define METRIC_MAX_COUNT 64U
 
+typedef enum _MetricValueType
+{
+    FLOAT,
+    INTEGER_U8,
+    INTEGER_64,
+} eMetricValueType;
+
 typedef struct _metric
 {
     char caMetricName[METRIC_NAME_MAX_SIZE];
+    eMetricValueType type;
     float fMetricValue;
+    uint8_t u8MetricValue;
+    int64_t i64MetricValue;
 } sMetric;
 
 void initMetrics(void);