From 3771a83fcc26a6e376b8130c2b946e6aa656c7745146b7fda58ef6982f75e094 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 1 Mar 2025 14:27:12 +0100 Subject: [PATCH 01/19] change onewire addr to new outdoor sensor --- main/inputs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/inputs.c b/main/inputs.c index 62e7086..0c118e7 100644 --- a/main/inputs.c +++ b/main/inputs.c @@ -17,7 +17,7 @@ const uint8_t uBurnerFaultPin = 19U; const uint8_t uDS18B20Pin = 4U; const onewire_addr_t uChamperTempSensorAddr = 0xd00000108cd01d28; -const onewire_addr_t uOutdoorTempSensorAddr = 0x78000000c6c2f728; +const onewire_addr_t uOutdoorTempSensorAddr = 0xd70000108a9b9128; const onewire_addr_t uInletFlowTempSensorAddr = 0x410000108b8c0628; const onewire_addr_t uReturnFlowTempSensorAddr = 0x90000108cc77c28; From fa958dd53b8834d7c2c2c43fa44f884664a02b8af3c484c9c9b64444a0f03db3 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 1 Mar 2025 15:17:22 +0100 Subject: [PATCH 02/19] add outdoor threshold --- main/control.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/main/control.c b/main/control.c index 29a6295..387c953 100644 --- a/main/control.c +++ b/main/control.c @@ -10,9 +10,11 @@ #define PERIODIC_INTERVAL 1U // run control loop every 1sec -#define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY 30.0 -#define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0 -#define CHAMPER_TEMPERATURE_TARGET 80.0 +#define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY 30.0f +#define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0f +#define CHAMPER_TEMPERATURE_TARGET 80.0f // Max cut off temperature, burner will stop if chamber is even or higher +#define CHAMPER_TEMPERATURE_THRESHOLD 45.0f // Min threshold temperature for enabling burner, burner will only start if chamber is even or lower +#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold temperature for enabling burner, burner will only start if outdoor is even or lower #define BURNER_FAULT_DETECTION_THRESHOLD (60U * 3U) // Detect burner fault if after 3 minutes no burner start detected static const char *TAG = "smart-oil-heater-control-system-control"; @@ -132,15 +134,26 @@ void taskControl(void *pvParameters) if ((bHeatingInAction == false) && (bBurnerFaultDetected == false)) { - if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && (getChamberTemperature().fCurrentValue <= 45.0)) + if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && (getChamberTemperature().fCurrentValue <= CHAMPER_TEMPERATURE_THRESHOLD)) { - ESP_LOGI(TAG, "Return Flow Target Temperature reached: Enable Burner"); - bHeatingInAction = true; - setCirculationPumpState(ENABLED); - setBurnerState(ENABLED); - setSafetyControlState(ENABLED); - i64BurnerEnableTimestamp = esp_timer_get_time(); - sControlState = CONTROL_HEATING; + if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) + { + ESP_LOGI(TAG, "Outdoor temperature too warm: Waiting for winter."); + setCirculationPumpState(DISABLED); + setBurnerState(DISABLED); + setSafetyControlState(DISABLED); + sControlState = CONTROL_OUTDOOR_TOO_WARM; + } + else + { + ESP_LOGI(TAG, "Return Flow Target Temperature reached: Enable Burner"); + bHeatingInAction = true; + setCirculationPumpState(ENABLED); + setBurnerState(ENABLED); + setSafetyControlState(ENABLED); + i64BurnerEnableTimestamp = esp_timer_get_time(); + sControlState = CONTROL_HEATING; + } } else { From c9b7313608fc34dee64d77df9771b011299087387966bf1df9de17a20a1d801e Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 1 Mar 2025 15:24:48 +0100 Subject: [PATCH 03/19] refactor --- main/control.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/main/control.c b/main/control.c index 387c953..1bb1726 100644 --- a/main/control.c +++ b/main/control.c @@ -134,17 +134,17 @@ void taskControl(void *pvParameters) if ((bHeatingInAction == false) && (bBurnerFaultDetected == false)) { - if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && (getChamberTemperature().fCurrentValue <= CHAMPER_TEMPERATURE_THRESHOLD)) + if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) { - if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) - { - ESP_LOGI(TAG, "Outdoor temperature too warm: Waiting for winter."); - setCirculationPumpState(DISABLED); - setBurnerState(DISABLED); - setSafetyControlState(DISABLED); - sControlState = CONTROL_OUTDOOR_TOO_WARM; - } - else + ESP_LOGI(TAG, "Outdoor temperature too warm: Waiting for winter."); + setCirculationPumpState(DISABLED); + setBurnerState(DISABLED); + setSafetyControlState(DISABLED); + sControlState = CONTROL_OUTDOOR_TOO_WARM; + } + else + { + if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && (getChamberTemperature().fCurrentValue <= CHAMPER_TEMPERATURE_THRESHOLD)) { ESP_LOGI(TAG, "Return Flow Target Temperature reached: Enable Burner"); bHeatingInAction = true; @@ -154,10 +154,10 @@ void taskControl(void *pvParameters) i64BurnerEnableTimestamp = esp_timer_get_time(); sControlState = CONTROL_HEATING; } - } - else - { - sControlState = CONTROL_RETURN_FLOW_TOO_WARM; + else + { + sControlState = CONTROL_RETURN_FLOW_TOO_WARM; + } } } } From 8ca3d9716599b1504bec9b1e854b55e5fc19bb24ed56b715450420b94d5a1042 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 1 Mar 2025 15:36:05 +0100 Subject: [PATCH 04/19] refactoring --- main/control.c | 160 +++++++++++++++++++------------------------------ 1 file changed, 60 insertions(+), 100 deletions(-) diff --git a/main/control.c b/main/control.c index 1bb1726..04ccd8b 100644 --- a/main/control.c +++ b/main/control.c @@ -8,28 +8,31 @@ #include "safety.h" #include "sntp.h" -#define PERIODIC_INTERVAL 1U // run control loop every 1sec +#define PERIODIC_INTERVAL 1U // Run control loop every 1 second +// Temperature thresholds #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY 30.0f #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0f -#define CHAMPER_TEMPERATURE_TARGET 80.0f // Max cut off temperature, burner will stop if chamber is even or higher -#define CHAMPER_TEMPERATURE_THRESHOLD 45.0f // Min threshold temperature for enabling burner, burner will only start if chamber is even or lower -#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold temperature for enabling burner, burner will only start if outdoor is even or lower -#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 3U) // Detect burner fault if after 3 minutes no burner start detected +#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature +#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable +#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable +#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 3U) // Burner fault detection after 3 minutes static const char *TAG = "smart-oil-heater-control-system-control"; static eControlState sControlState = CONTROL_STARTING; +// Control table for daily schedules static sControlDay aControlTable[] = { - {MONDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, - {TUESDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, - {WEDNESDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, - {THURSDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, - {FRIDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{23, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, - {SATURDAY, 2U, {{{6, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{23, 30}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, - {SUNDAY, 2U, {{{6, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMPER_TEMPERATURE_TARGET}, {{22, 30}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMPER_TEMPERATURE_TARGET}}}, + {MONDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, + {TUESDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, + {WEDNESDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, + {THURSDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, + {FRIDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{23, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, + {SATURDAY, 2U, {{{6, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{23, 30}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, + {SUNDAY, 2U, {{{6, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 30}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, }; +// Function prototypes void taskControl(void *pvParameters); eControlWeekday getCurrentWeekday(void); sControlTemperatureEntry getCurrentTemperatureEntry(void); @@ -65,13 +68,14 @@ void taskControl(void *pvParameters) { vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS); + // Handle safety faults if (getSafetyState() != SAFETY_NO_ERROR) { ESP_LOGW(TAG, "Control not possible due to safety fault!"); sControlState = CONTROL_FAULT_SAFETY; - if (bHeatingInAction == true) + if (bHeatingInAction) { - ESP_LOGW(TAG, "Control not possible due to safety fault: Disable burner"); + ESP_LOGW(TAG, "Disabling burner due to safety fault"); bHeatingInAction = false; setCirculationPumpState(ENABLED); setBurnerState(DISABLED); @@ -80,13 +84,14 @@ void taskControl(void *pvParameters) continue; } + // Handle SNTP faults if (getSntpState() != SYNC_SUCCESSFUL) { - ESP_LOGW(TAG, "Control not possible due to sntp fault!"); + ESP_LOGW(TAG, "Control not possible due to SNTP fault!"); sControlState = CONTROL_FAULT_SNTP; - if (bHeatingInAction == true) + if (bHeatingInAction) { - ESP_LOGW(TAG, "Control not possible due to sntp fault: Disable burner"); + ESP_LOGW(TAG, "Disabling burner due to SNTP fault"); bHeatingInAction = false; setCirculationPumpState(ENABLED); setBurnerState(DISABLED); @@ -95,69 +100,59 @@ void taskControl(void *pvParameters) continue; } + // Get current temperature entry sControlTemperatureEntry currentControlEntry = getCurrentTemperatureEntry(); - // ESP_LOGI(TAG, "Control Entry Hour: %i Minute: %i ChamberTemp: %lf ReturnFlowTemp: %lf", currentControlEntry.timestamp.hour, currentControlEntry.timestamp.minute, currentControlEntry.fChamberTemperature, currentControlEntry.fReturnFlowTemperature); - if (bHeatingInAction == true) + if (bHeatingInAction) { - if ((getChamberTemperature().fCurrentValue >= currentControlEntry.fChamberTemperature) || (getChamberTemperature().predict60s.fValue >= currentControlEntry.fChamberTemperature)) + if ((getChamberTemperature().fCurrentValue >= currentControlEntry.fChamberTemperature) || + (getChamberTemperature().predict60s.fValue >= currentControlEntry.fChamberTemperature)) { - ESP_LOGI(TAG, "Chamber Target Temperature reached: Disable burner"); + ESP_LOGI(TAG, "Chamber target temperature reached: Disabling burner"); bHeatingInAction = false; setCirculationPumpState(ENABLED); setBurnerState(DISABLED); setSafetyControlState(ENABLED); } - else + else if (esp_timer_get_time() - i64BurnerEnableTimestamp >= BURNER_FAULT_DETECTION_THRESHOLD * 1000000U) { - if (bHeatingInAction) + if (getBurnerError() == FAULT) { - int64_t i64Delta = esp_timer_get_time() - i64BurnerEnableTimestamp; - - if ((i64Delta / 1000000U) >= BURNER_FAULT_DETECTION_THRESHOLD) - { - if (getBurnerError() == FAULT) - { - ESP_LOGW(TAG, "Detected burner fault after %lli seconds!", (i64Delta / 1000000U)); - ESP_LOGW(TAG, "Control not possible due to burner fault: Disable burner"); - sControlState = CONTROL_FAULT_BURNER; - bHeatingInAction = false; - bBurnerFaultDetected = true; - setCirculationPumpState(ENABLED); - setBurnerState(DISABLED); - setSafetyControlState(ENABLED); - } - } + ESP_LOGW(TAG, "Burner fault detected after timeout!"); + bHeatingInAction = false; + bBurnerFaultDetected = true; + sControlState = CONTROL_FAULT_BURNER; + setCirculationPumpState(ENABLED); + setBurnerState(DISABLED); + setSafetyControlState(ENABLED); } } } - if ((bHeatingInAction == false) && (bBurnerFaultDetected == false)) + if (!bHeatingInAction && !bBurnerFaultDetected) { if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) { - ESP_LOGI(TAG, "Outdoor temperature too warm: Waiting for winter."); + ESP_LOGI(TAG, "Outdoor temperature too warm: Disabling heating"); setCirculationPumpState(DISABLED); setBurnerState(DISABLED); setSafetyControlState(DISABLED); sControlState = CONTROL_OUTDOOR_TOO_WARM; } + else if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && + (getChamberTemperature().fCurrentValue <= CHAMBER_TEMPERATURE_THRESHOLD)) + { + ESP_LOGI(TAG, "Enabling burner: Return flow temperature target reached"); + bHeatingInAction = true; + setCirculationPumpState(ENABLED); + setBurnerState(ENABLED); + setSafetyControlState(ENABLED); + i64BurnerEnableTimestamp = esp_timer_get_time(); + sControlState = CONTROL_HEATING; + } else { - if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && (getChamberTemperature().fCurrentValue <= CHAMPER_TEMPERATURE_THRESHOLD)) - { - ESP_LOGI(TAG, "Return Flow Target Temperature reached: Enable Burner"); - bHeatingInAction = true; - setCirculationPumpState(ENABLED); - setBurnerState(ENABLED); - setSafetyControlState(ENABLED); - i64BurnerEnableTimestamp = esp_timer_get_time(); - sControlState = CONTROL_HEATING; - } - else - { - sControlState = CONTROL_RETURN_FLOW_TOO_WARM; - } + sControlState = CONTROL_RETURN_FLOW_TOO_WARM; } } } @@ -173,73 +168,38 @@ eControlWeekday getCurrentWeekday(void) time_t now; struct tm *timeinfo; - // Get the current time time(&now); - timeinfo = localtime(&now); // Convert to local time + timeinfo = localtime(&now); - // Get the day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday) int day = timeinfo->tm_wday; - - // Adjust so that Monday = 0, Sunday = 6 - if (day == 0) - { - day = 6; // Sunday becomes 6 - } - else - { - day -= 1; // Shift other days to make Monday = 0 - } - - return (eControlWeekday)day; + return (eControlWeekday)((day == 0) ? 6 : day - 1); } sControlTemperatureEntry getCurrentTemperatureEntry(void) { sControlTemperatureEntry result = aControlTable[0].aTemperatureEntries[0]; eControlWeekday currentDay = getCurrentWeekday(); + time_t now; struct tm timeinfo; - - // Get the current time time(&now); - // Convert to local time structure localtime_r(&now, &timeinfo); - // Extract hour and minute - int hour = timeinfo.tm_hour; // Hour (0-23) - int minute = timeinfo.tm_min; // Minute (0-59)u - // ESP_LOGI(TAG, "Current Day: %i Hour: %i Minute: %i", currentDay, hour, minute); + int hour = timeinfo.tm_hour; + int minute = timeinfo.tm_min; for (int i = 0; i < sizeof(aControlTable) / sizeof(aControlTable[0]); i++) { - /// loops through days - // ESP_LOGI(TAG, "Day %d: %d", i + 1, aControlTable[i].day); - // int numberOfEntries = aControlTable[i].entryCount; - // ESP_LOGI(TAG, "Number of entries: %i", numberOfEntries); - for (int j = 0; j < aControlTable[i].entryCount; j++) { - if ((aControlTable[i].day) > currentDay) + if ((aControlTable[i].day > currentDay) || + (aControlTable[i].day == currentDay && aControlTable[i].aTemperatureEntries[j].timestamp.hour > hour) || + (aControlTable[i].day == currentDay && aControlTable[i].aTemperatureEntries[j].timestamp.hour == hour && aControlTable[i].aTemperatureEntries[j].timestamp.minute >= minute)) { - // ESP_LOGI(TAG, "DAY Return Control Entry Day: %i Hour: %i Minute: %i ChamberTemp: %lf ReturnFlowTemp: %lf", aControlTable[i].day, aControlTable[i].aTemperatureEntries[j].timestamp.hour, aControlTable[i].aTemperatureEntries[j].timestamp.minute, aControlTable[i].aTemperatureEntries[j].fChamberTemperature, aControlTable[i].aTemperatureEntries[j].fReturnFlowTemperature); - return result; + return aControlTable[i].aTemperatureEntries[j]; } - - if ((aControlTable[i].day == currentDay) && (aControlTable[i].aTemperatureEntries[j].timestamp.hour > hour)) - { - // ESP_LOGI(TAG, "HOUR Return Control Entry Day: %i Hour: %i Minute: %i ChamberTemp: %lf ReturnFlowTemp: %lf", aControlTable[i].day, aControlTable[i].aTemperatureEntries[j].timestamp.hour, aControlTable[i].aTemperatureEntries[j].timestamp.minute, aControlTable[i].aTemperatureEntries[j].fChamberTemperature, aControlTable[i].aTemperatureEntries[j].fReturnFlowTemperature); - return result; - } - - if ((aControlTable[i].day == currentDay) && (aControlTable[i].aTemperatureEntries[j].timestamp.hour == hour) && (aControlTable[i].aTemperatureEntries[j].timestamp.minute == minute)) - { - // ESP_LOGI(TAG, "MINUTE Return Control Entry Day: %i Hour: %i Minute: %i ChamberTemp: %lf ReturnFlowTemp: %lf", aControlTable[i].day, aControlTable[i].aTemperatureEntries[j].timestamp.hour, aControlTable[i].aTemperatureEntries[j].timestamp.minute, aControlTable[i].aTemperatureEntries[j].fChamberTemperature, aControlTable[i].aTemperatureEntries[j].fReturnFlowTemperature); - return result; - } - - // ESP_LOGI(TAG, "SET Return Control Entry Day: %i Hour: %i Minute: %i ChamberTemp: %lf ReturnFlowTemp: %lf", aControlTable[i].day, aControlTable[i].aTemperatureEntries[j].timestamp.hour, aControlTable[i].aTemperatureEntries[j].timestamp.minute, aControlTable[i].aTemperatureEntries[j].fChamberTemperature, aControlTable[i].aTemperatureEntries[j].fReturnFlowTemperature); result = aControlTable[i].aTemperatureEntries[j]; } } return result; -} \ No newline at end of file +} From 416cda0f50272e7602ccb136e102894383c61f7c92d7d6bedd2e38dd15138c73 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 1 Mar 2025 15:43:29 +0100 Subject: [PATCH 05/19] disable log of event --- main/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/control.c b/main/control.c index 04ccd8b..91e35fb 100644 --- a/main/control.c +++ b/main/control.c @@ -133,7 +133,7 @@ void taskControl(void *pvParameters) { if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) { - ESP_LOGI(TAG, "Outdoor temperature too warm: Disabling heating"); + // ESP_LOGI(TAG, "Outdoor temperature too warm: Disabling heating"); setCirculationPumpState(DISABLED); setBurnerState(DISABLED); setSafetyControlState(DISABLED); From 66b7f8320ef075afeae2c93722735d796443b8ba0c3c913f26628d6e1c71b101 Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 18 Apr 2025 17:50:20 +0200 Subject: [PATCH 06/19] increase burner fault threshold --- main/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/control.c b/main/control.c index 91e35fb..938a1a3 100644 --- a/main/control.c +++ b/main/control.c @@ -16,7 +16,7 @@ #define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature #define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable #define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable -#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 3U) // Burner fault detection after 3 minutes +#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 15U) // Burner fault detection after 15 minutes static const char *TAG = "smart-oil-heater-control-system-control"; static eControlState sControlState = CONTROL_STARTING; From f66b8316669f52e22ec3f5f98c333cac7d53a02e2fed9e4f263f8442466e13e4 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 19 Apr 2025 08:36:19 +0200 Subject: [PATCH 07/19] rework burner fault detection --- main/control.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/main/control.c b/main/control.c index 938a1a3..f8c9eb0 100644 --- a/main/control.c +++ b/main/control.c @@ -13,9 +13,9 @@ // Temperature thresholds #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY 30.0f #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0f -#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature -#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable -#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable +#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature +#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable +#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable #define BURNER_FAULT_DETECTION_THRESHOLD (60U * 15U) // Burner fault detection after 15 minutes static const char *TAG = "smart-oil-heater-control-system-control"; @@ -58,10 +58,17 @@ void initControl(void) } } +typedef enum _BurnerState +{ + BURNER_UNKNOWN, + BURNER_FIRED, + BURNER_FAULT +} eBurnerState; + void taskControl(void *pvParameters) { bool bHeatingInAction = false; - bool bBurnerFaultDetected = false; + eBurnerState eBurnerState = BURNER_UNKNOWN; int64_t i64BurnerEnableTimestamp = esp_timer_get_time(); while (1) @@ -116,20 +123,27 @@ void taskControl(void *pvParameters) } else if (esp_timer_get_time() - i64BurnerEnableTimestamp >= BURNER_FAULT_DETECTION_THRESHOLD * 1000000U) { - if (getBurnerError() == FAULT) + if (eBurnerState == BURNER_UNKNOWN) { - ESP_LOGW(TAG, "Burner fault detected after timeout!"); - bHeatingInAction = false; - bBurnerFaultDetected = true; - sControlState = CONTROL_FAULT_BURNER; - setCirculationPumpState(ENABLED); - setBurnerState(DISABLED); - setSafetyControlState(ENABLED); + if (getBurnerError() == FAULT) + { + ESP_LOGW(TAG, "Burner fault detected after timeout!"); + bHeatingInAction = false; + eBurnerState = BURNER_FAULT; + sControlState = CONTROL_FAULT_BURNER; + setCirculationPumpState(ENABLED); + setBurnerState(DISABLED); + setSafetyControlState(ENABLED); + } + else + { + eBurnerState = BURNER_FIRED; + } } } } - if (!bHeatingInAction && !bBurnerFaultDetected) + if (!bHeatingInAction && (eBurnerState != BURNER_FAULT)) { if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) { From 2477ccb42a70f1c65dd3897e7c79797a92d682453f0edd91b1c37c701162d30d Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 19 Apr 2025 08:48:57 +0200 Subject: [PATCH 08/19] increase threshold --- main/control.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/main/control.c b/main/control.c index f8c9eb0..f540b80 100644 --- a/main/control.c +++ b/main/control.c @@ -13,10 +13,10 @@ // Temperature thresholds #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY 30.0f #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0f -#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature -#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable -#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable -#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 15U) // Burner fault detection after 15 minutes +#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature +#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable +#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable +#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 4U) // Burner fault detection after 4 minutes static const char *TAG = "smart-oil-heater-control-system-control"; static eControlState sControlState = CONTROL_STARTING; @@ -127,7 +127,7 @@ void taskControl(void *pvParameters) { if (getBurnerError() == FAULT) { - ESP_LOGW(TAG, "Burner fault detected after timeout!"); + ESP_LOGW(TAG, "Burner fault detected after threshold!"); bHeatingInAction = false; eBurnerState = BURNER_FAULT; sControlState = CONTROL_FAULT_BURNER; @@ -137,6 +137,7 @@ void taskControl(void *pvParameters) } else { + ESP_LOGW(TAG, "No Burner fault detected after threshold!"); eBurnerState = BURNER_FIRED; } } @@ -157,6 +158,7 @@ void taskControl(void *pvParameters) (getChamberTemperature().fCurrentValue <= CHAMBER_TEMPERATURE_THRESHOLD)) { ESP_LOGI(TAG, "Enabling burner: Return flow temperature target reached"); + eBurnerState = BURNER_UNKNOWN; bHeatingInAction = true; setCirculationPumpState(ENABLED); setBurnerState(ENABLED); From dcace073d9c0d61a0e380f7658937b133bc093ccbe0e0309fa79c31977a68a92 Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 25 Apr 2025 21:45:59 +0200 Subject: [PATCH 09/19] rework circulation pump --- main/control.c | 95 ++++++++++++++++++++++++++------------------------ main/control.h | 7 ++++ 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/main/control.c b/main/control.c index f540b80..f140917 100644 --- a/main/control.c +++ b/main/control.c @@ -58,13 +58,6 @@ void initControl(void) } } -typedef enum _BurnerState -{ - BURNER_UNKNOWN, - BURNER_FIRED, - BURNER_FAULT -} eBurnerState; - void taskControl(void *pvParameters) { bool bHeatingInAction = false; @@ -84,7 +77,6 @@ void taskControl(void *pvParameters) { ESP_LOGW(TAG, "Disabling burner due to safety fault"); bHeatingInAction = false; - setCirculationPumpState(ENABLED); setBurnerState(DISABLED); setSafetyControlState(ENABLED); } @@ -100,7 +92,6 @@ void taskControl(void *pvParameters) { ESP_LOGW(TAG, "Disabling burner due to SNTP fault"); bHeatingInAction = false; - setCirculationPumpState(ENABLED); setBurnerState(DISABLED); setSafetyControlState(ENABLED); } @@ -110,46 +101,12 @@ void taskControl(void *pvParameters) // Get current temperature entry sControlTemperatureEntry currentControlEntry = getCurrentTemperatureEntry(); - if (bHeatingInAction) - { - if ((getChamberTemperature().fCurrentValue >= currentControlEntry.fChamberTemperature) || - (getChamberTemperature().predict60s.fValue >= currentControlEntry.fChamberTemperature)) - { - ESP_LOGI(TAG, "Chamber target temperature reached: Disabling burner"); - bHeatingInAction = false; - setCirculationPumpState(ENABLED); - setBurnerState(DISABLED); - setSafetyControlState(ENABLED); - } - else if (esp_timer_get_time() - i64BurnerEnableTimestamp >= BURNER_FAULT_DETECTION_THRESHOLD * 1000000U) - { - if (eBurnerState == BURNER_UNKNOWN) - { - if (getBurnerError() == FAULT) - { - ESP_LOGW(TAG, "Burner fault detected after threshold!"); - bHeatingInAction = false; - eBurnerState = BURNER_FAULT; - sControlState = CONTROL_FAULT_BURNER; - setCirculationPumpState(ENABLED); - setBurnerState(DISABLED); - setSafetyControlState(ENABLED); - } - else - { - ESP_LOGW(TAG, "No Burner fault detected after threshold!"); - eBurnerState = BURNER_FIRED; - } - } - } - } - + // Enable burner if outdoor temperature is low and return flow temperature is cooled down if (!bHeatingInAction && (eBurnerState != BURNER_FAULT)) { if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) { // ESP_LOGI(TAG, "Outdoor temperature too warm: Disabling heating"); - setCirculationPumpState(DISABLED); setBurnerState(DISABLED); setSafetyControlState(DISABLED); sControlState = CONTROL_OUTDOOR_TOO_WARM; @@ -160,7 +117,6 @@ void taskControl(void *pvParameters) ESP_LOGI(TAG, "Enabling burner: Return flow temperature target reached"); eBurnerState = BURNER_UNKNOWN; bHeatingInAction = true; - setCirculationPumpState(ENABLED); setBurnerState(ENABLED); setSafetyControlState(ENABLED); i64BurnerEnableTimestamp = esp_timer_get_time(); @@ -168,10 +124,57 @@ void taskControl(void *pvParameters) } else { + // ESP_LOGI(TAG, "Return flow temperature is still to warm: Disabling heating"); sControlState = CONTROL_RETURN_FLOW_TOO_WARM; } } - } + + // Disable burner if target temperature is reached or a fault occurred + if (bHeatingInAction) + { + if ((getChamberTemperature().fCurrentValue >= currentControlEntry.fChamberTemperature) || + (getChamberTemperature().predict60s.fValue >= currentControlEntry.fChamberTemperature)) + { + ESP_LOGI(TAG, "Chamber target temperature reached: Disabling burner"); + bHeatingInAction = false; + setBurnerState(DISABLED); + setSafetyControlState(ENABLED); + } + else if (esp_timer_get_time() - i64BurnerEnableTimestamp >= BURNER_FAULT_DETECTION_THRESHOLD * 1000000U) + { + if (eBurnerState == BURNER_UNKNOWN) + { + if (getBurnerError() == FAULT) + { + // ESP_LOGI(TAG, "Burner fault detected after threshold!"); + bHeatingInAction = false; + eBurnerState = BURNER_FAULT; + sControlState = CONTROL_FAULT_BURNER; + setBurnerState(DISABLED); + setSafetyControlState(ENABLED); + } + else + { + // ESP_LOGI(TAG, "No Burner fault detected after threshold!"); + eBurnerState = BURNER_FIRED; + } + } + } + } + + // Handle circulation pump state + if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && + (getChamberTemperature().fCurrentValue <= CHAMBER_TEMPERATURE_THRESHOLD)) + { + // ESP_LOGI(TAG, "Burner is cooled down: Disable circulation pump"); + setCirculationPumpState(DISABLED); + } + else + { + // ESP_LOGI(TAG, "Burner is heated: Enable circulation pump"); + setCirculationPumpState(ENABLED); + } + } // End of while(1) } eControlState getControlState(void) diff --git a/main/control.h b/main/control.h index ba60d4c..fe7f3ad 100644 --- a/main/control.h +++ b/main/control.h @@ -14,6 +14,13 @@ typedef enum _ControlState CONTROL_FAULT_SNTP, } eControlState; +typedef enum _BurnerState +{ + BURNER_UNKNOWN, // Burner is disabled or state after enabling is still unkown + BURNER_FIRED, // Burner fired successfully + BURNER_FAULT // Burner was unable to fire successfully +} eBurnerState; + typedef enum _ControlWeekday { MONDAY, From ac15376f6b8d47c72c9014f05a01225deb07c4102fb79045e401b604442ef57e Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 25 Apr 2025 21:52:31 +0200 Subject: [PATCH 10/19] spelling fixes --- main/control.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/main/control.c b/main/control.c index f140917..02d0ebc 100644 --- a/main/control.c +++ b/main/control.c @@ -68,7 +68,7 @@ void taskControl(void *pvParameters) { vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS); - // Handle safety faults + // Check for safety faults if (getSafetyState() != SAFETY_NO_ERROR) { ESP_LOGW(TAG, "Control not possible due to safety fault!"); @@ -83,7 +83,7 @@ void taskControl(void *pvParameters) continue; } - // Handle SNTP faults + // Check for SNTP faults if (getSntpState() != SYNC_SUCCESSFUL) { ESP_LOGW(TAG, "Control not possible due to SNTP fault!"); @@ -98,7 +98,6 @@ void taskControl(void *pvParameters) continue; } - // Get current temperature entry sControlTemperatureEntry currentControlEntry = getCurrentTemperatureEntry(); // Enable burner if outdoor temperature is low and return flow temperature is cooled down @@ -124,7 +123,7 @@ void taskControl(void *pvParameters) } else { - // ESP_LOGI(TAG, "Return flow temperature is still to warm: Disabling heating"); + // ESP_LOGI(TAG, "Return flow temperature too warm: Disabling heating"); sControlState = CONTROL_RETURN_FLOW_TOO_WARM; } } @@ -146,7 +145,7 @@ void taskControl(void *pvParameters) { if (getBurnerError() == FAULT) { - // ESP_LOGI(TAG, "Burner fault detected after threshold!"); + // ESP_LOGW(TAG, "Burner fault detected: Disabling burner"); bHeatingInAction = false; eBurnerState = BURNER_FAULT; sControlState = CONTROL_FAULT_BURNER; @@ -155,23 +154,23 @@ void taskControl(void *pvParameters) } else { - // ESP_LOGI(TAG, "No Burner fault detected after threshold!"); + // ESP_LOGI(TAG, "No burner fault detected: Marking burner as fired"); eBurnerState = BURNER_FIRED; } } } } - // Handle circulation pump state + // Manage circulation pump if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && (getChamberTemperature().fCurrentValue <= CHAMBER_TEMPERATURE_THRESHOLD)) { - // ESP_LOGI(TAG, "Burner is cooled down: Disable circulation pump"); + // ESP_LOGI(TAG, "Burner cooled down: Disabling circulation pump"); setCirculationPumpState(DISABLED); } else { - // ESP_LOGI(TAG, "Burner is heated: Enable circulation pump"); + // ESP_LOGI(TAG, "Burner heated: Enabling circulation pump"); setCirculationPumpState(ENABLED); } } // End of while(1) From 6eca00200e78e56be5de84a39a3e77a9e87dd02a11f5fe9afca275f2fd310c81 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 12 Jul 2025 12:04:08 +0200 Subject: [PATCH 11/19] suppress heating in summer --- main/control.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main/control.c b/main/control.c index 02d0ebc..f27a9a7 100644 --- a/main/control.c +++ b/main/control.c @@ -13,10 +13,11 @@ // Temperature thresholds #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY 30.0f #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0f -#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature -#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable -#define OUTDOOR_TEMPERATURE_THRESHOLD 15.0f // Min threshold for burner enable -#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 4U) // Burner fault detection after 4 minutes +#define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature +#define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable +#define OUTDOOR_TEMPERATURE_THRESHOLD 13.0f // Min threshold for burner enable +#define CIRCULATION_PUMP_TEMPERATURE_THRESHOLD 30.0f // Min threshold of chamber for circulation pump enable +#define BURNER_FAULT_DETECTION_THRESHOLD (60U * 4U) // Burner fault detection after 4 minutes static const char *TAG = "smart-oil-heater-control-system-control"; static eControlState sControlState = CONTROL_STARTING; @@ -162,8 +163,7 @@ void taskControl(void *pvParameters) } // Manage circulation pump - if ((getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) && - (getChamberTemperature().fCurrentValue <= CHAMBER_TEMPERATURE_THRESHOLD)) + if (getChamberTemperature().fCurrentValue <= CIRCULATION_PUMP_TEMPERATURE_THRESHOLD) { // ESP_LOGI(TAG, "Burner cooled down: Disabling circulation pump"); setCirculationPumpState(DISABLED); From 9974e2d738fa49f63a2939ff54e969e39050f660ba02a7badf714d809c33ca63 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 12 Oct 2025 12:59:33 +0200 Subject: [PATCH 12/19] detect summer mode based on two thresholds --- main/control.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/main/control.c b/main/control.c index f27a9a7..42eb184 100644 --- a/main/control.c +++ b/main/control.c @@ -15,7 +15,8 @@ #define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0f #define CHAMBER_TEMPERATURE_TARGET 80.0f // Max cutoff temperature #define CHAMBER_TEMPERATURE_THRESHOLD 45.0f // Min threshold for burner enable -#define OUTDOOR_TEMPERATURE_THRESHOLD 13.0f // Min threshold for burner enable +#define SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH 20.0f // Summer mode will be activated +#define SUMMER_MODE_TEMPERATURE_THRESHOLD_LOW 15.0f // Summer mode will be deactivated --> Heating starts #define CIRCULATION_PUMP_TEMPERATURE_THRESHOLD 30.0f // Min threshold of chamber for circulation pump enable #define BURNER_FAULT_DETECTION_THRESHOLD (60U * 4U) // Burner fault detection after 4 minutes @@ -62,6 +63,7 @@ void initControl(void) void taskControl(void *pvParameters) { bool bHeatingInAction = false; + bool bSummerMode = false; eBurnerState eBurnerState = BURNER_UNKNOWN; int64_t i64BurnerEnableTimestamp = esp_timer_get_time(); @@ -101,10 +103,19 @@ void taskControl(void *pvParameters) sControlTemperatureEntry currentControlEntry = getCurrentTemperatureEntry(); + if (getOutdoorTemperature().average60s.fValue >= SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH) + { + bSummerMode = true; + } + else if (getOutdoorTemperature().average60s.fValue <= SUMMER_MODE_TEMPERATURE_THRESHOLD_LOW) + { + bSummerMode = false; + } + // Enable burner if outdoor temperature is low and return flow temperature is cooled down if (!bHeatingInAction && (eBurnerState != BURNER_FAULT)) { - if (getOutdoorTemperature().average60s.fValue >= OUTDOOR_TEMPERATURE_THRESHOLD) + if (bSummerMode) { // ESP_LOGI(TAG, "Outdoor temperature too warm: Disabling heating"); setBurnerState(DISABLED); From 067dc84afaa26e9106b6c82367e456ddd93939848f2dab442af8de27eb1acba4 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 12 Oct 2025 13:10:26 +0200 Subject: [PATCH 13/19] average value for last 24h --- main/inputs.c | 40 +++++++++++++++++++++++++++++++--------- main/inputs.h | 12 +++++++----- main/metrics.c | 24 ++++++++++++++++++++++++ main/metrics.h | 2 +- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/main/inputs.c b/main/inputs.c index 0c118e7..ad9070d 100644 --- a/main/inputs.c +++ b/main/inputs.c @@ -93,17 +93,22 @@ void initMeasurement(sMeasurement *pMeasurement) pMeasurement->average10s.fValue = 0.0f; pMeasurement->average10s.bufferCount = 0U; pMeasurement->average10s.bufferIndex = 0U; - memset(pMeasurement->average10s.samples, 0U, AVG10_SAMPLE_SIZE); + memset(pMeasurement->average10s.samples, 0U, AVG10S_SAMPLE_SIZE); pMeasurement->average60s.fValue = 0.0f; pMeasurement->average60s.bufferCount = 0U; pMeasurement->average60s.bufferIndex = 0U; - memset(pMeasurement->average60s.samples, 0U, AVG60_SAMPLE_SIZE); + memset(pMeasurement->average60s.samples, 0U, AVG60S_SAMPLE_SIZE); + + pMeasurement->average24h.fValue = 0.0f; + pMeasurement->average24h.bufferCount = 0U; + pMeasurement->average24h.bufferIndex = 0U; + memset(pMeasurement->average24h.samples, 0U, AVG24H_SAMPLE_SIZE); pMeasurement->predict60s.fValue = 0.0f; pMeasurement->predict60s.bufferCount = 0U; pMeasurement->predict60s.bufferIndex = 0U; - memset(pMeasurement->predict60s.samples, 0U, PRED60_SAMPLE_SIZE); + memset(pMeasurement->predict60s.samples, 0U, PRED60S_SAMPLE_SIZE); } void updateAverage(sMeasurement *pMeasurement) @@ -113,9 +118,9 @@ void updateAverage(sMeasurement *pMeasurement) // Average form the last 10sec pMeasurement->average10s.samples[pMeasurement->average10s.bufferIndex] = pMeasurement->fCurrentValue; - pMeasurement->average10s.bufferIndex = (pMeasurement->average10s.bufferIndex + 1) % AVG10_SAMPLE_SIZE; + pMeasurement->average10s.bufferIndex = (pMeasurement->average10s.bufferIndex + 1) % AVG10S_SAMPLE_SIZE; - if (pMeasurement->average10s.bufferCount < AVG10_SAMPLE_SIZE) + if (pMeasurement->average10s.bufferCount < AVG10S_SAMPLE_SIZE) { pMeasurement->average10s.bufferCount++; } @@ -130,9 +135,9 @@ void updateAverage(sMeasurement *pMeasurement) // Average form the last 60sec pMeasurement->average60s.samples[pMeasurement->average60s.bufferIndex] = pMeasurement->fCurrentValue; - pMeasurement->average60s.bufferIndex = (pMeasurement->average60s.bufferIndex + 1) % AVG60_SAMPLE_SIZE; + pMeasurement->average60s.bufferIndex = (pMeasurement->average60s.bufferIndex + 1) % AVG60S_SAMPLE_SIZE; - if (pMeasurement->average60s.bufferCount < AVG60_SAMPLE_SIZE) + if (pMeasurement->average60s.bufferCount < AVG60S_SAMPLE_SIZE) { pMeasurement->average60s.bufferCount++; } @@ -144,6 +149,23 @@ void updateAverage(sMeasurement *pMeasurement) } pMeasurement->average60s.fValue = sum / pMeasurement->average60s.bufferCount; + + // Average form the last 24h + pMeasurement->average24h.samples[pMeasurement->average24h.bufferIndex] = pMeasurement->fCurrentValue; + pMeasurement->average24h.bufferIndex = (pMeasurement->average24h.bufferIndex + 1) % AVG24H_SAMPLE_SIZE; + + if (pMeasurement->average24h.bufferCount < AVG24H_SAMPLE_SIZE) + { + pMeasurement->average24h.bufferCount++; + } + + sum = 0.0; + for (int i = 0; i <= pMeasurement->average24h.bufferCount; i++) + { + sum += pMeasurement->average24h.samples[i]; + } + + pMeasurement->average24h.fValue = sum / pMeasurement->average24h.bufferCount; } void updatePrediction(sMeasurement *pMeasurement) @@ -154,8 +176,8 @@ void updatePrediction(sMeasurement *pMeasurement) // Update predict60s buffer sPredict *predict60s = &pMeasurement->predict60s; predict60s->samples[predict60s->bufferIndex] = pMeasurement->fCurrentValue; - predict60s->bufferIndex = (predict60s->bufferIndex + 1) % PRED60_SAMPLE_SIZE; - if (predict60s->bufferCount < PRED60_SAMPLE_SIZE) + predict60s->bufferIndex = (predict60s->bufferIndex + 1) % PRED60S_SAMPLE_SIZE; + if (predict60s->bufferCount < PRED60S_SAMPLE_SIZE) predict60s->bufferCount++; // Predict 60s future value using linear regression diff --git a/main/inputs.h b/main/inputs.h index 9af37f5..eafca07 100644 --- a/main/inputs.h +++ b/main/inputs.h @@ -1,9 +1,10 @@ #pragma once #define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define AVG10_SAMPLE_SIZE 10U -#define AVG60_SAMPLE_SIZE 60U -#define PRED60_SAMPLE_SIZE 60U +#define AVG10S_SAMPLE_SIZE 10U +#define AVG60S_SAMPLE_SIZE 60U +#define AVG24H_SAMPLE_SIZE 60U * 60U * 24U +#define PRED60S_SAMPLE_SIZE 60U typedef enum _BurnerErrorState { @@ -20,7 +21,7 @@ typedef enum _MeasurementErrorState typedef struct _Average { float fValue; - float samples[MAX(AVG10_SAMPLE_SIZE, AVG60_SAMPLE_SIZE)]; + float samples[MAX(AVG10S_SAMPLE_SIZE, AVG60S_SAMPLE_SIZE)]; size_t bufferIndex; size_t bufferCount; } sAverage; @@ -28,7 +29,7 @@ typedef struct _Average typedef struct _Predict { float fValue; - float samples[PRED60_SAMPLE_SIZE]; + float samples[PRED60S_SAMPLE_SIZE]; size_t bufferIndex; size_t bufferCount; } sPredict; @@ -38,6 +39,7 @@ typedef struct _Measurement float fCurrentValue; sAverage average10s; sAverage average60s; + sAverage average24h; sPredict predict60s; eMeasurementErrorState state; } sMeasurement; diff --git a/main/metrics.c b/main/metrics.c index c7aaf6f..0aa2548 100644 --- a/main/metrics.c +++ b/main/metrics.c @@ -128,6 +128,12 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average60s.fValue; u16MetricCounter++; + // Chamber Temperature Average 24h + strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg24h"); + aMetrics[u16MetricCounter].type = FLOAT; + aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average24h.fValue; + u16MetricCounter++; + // Chamber Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_pred60"); aMetrics[u16MetricCounter].type = FLOAT; @@ -152,6 +158,12 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average60s.fValue; u16MetricCounter++; + // Inlet Flow Temperature Average 24h + strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg24h"); + aMetrics[u16MetricCounter].type = FLOAT; + aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average24h.fValue; + u16MetricCounter++; + // Inlet Flow Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_pred60"); aMetrics[u16MetricCounter].type = FLOAT; @@ -176,6 +188,12 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average60s.fValue; u16MetricCounter++; + // Outdoor Temperature Average 24h + strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg24h"); + aMetrics[u16MetricCounter].type = FLOAT; + aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average24h.fValue; + u16MetricCounter++; + // Outdoor Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_pred60"); aMetrics[u16MetricCounter].type = FLOAT; @@ -200,6 +218,12 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average60s.fValue; u16MetricCounter++; + // Return Flow Temperature Average 24h + strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg24h"); + aMetrics[u16MetricCounter].type = FLOAT; + aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average24h.fValue; + u16MetricCounter++; + // Return Flow Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_pred60"); aMetrics[u16MetricCounter].type = FLOAT; diff --git a/main/metrics.h b/main/metrics.h index 7f48067..230d711 100644 --- a/main/metrics.h +++ b/main/metrics.h @@ -4,7 +4,7 @@ #define HTML_RESPONSE_SIZE 4096U #define METRIC_NAME_MAX_SIZE 64U -#define METRIC_MAX_COUNT 32U +#define METRIC_MAX_COUNT 34U typedef enum _MetricValueType { From 9ff3b38f70e6fa1a1d4ce6f15a3d6cfa8e1bfeeef45d9a781dc0acba75fe5a74 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 18 Oct 2025 19:26:14 +0200 Subject: [PATCH 14/19] disable avg24h --- main/inputs.c | 4 ++++ main/inputs.h | 6 +++--- main/metrics.c | 12 ++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/main/inputs.c b/main/inputs.c index ad9070d..19da2c7 100644 --- a/main/inputs.c +++ b/main/inputs.c @@ -100,10 +100,12 @@ void initMeasurement(sMeasurement *pMeasurement) pMeasurement->average60s.bufferIndex = 0U; memset(pMeasurement->average60s.samples, 0U, AVG60S_SAMPLE_SIZE); + /* pMeasurement->average24h.fValue = 0.0f; pMeasurement->average24h.bufferCount = 0U; pMeasurement->average24h.bufferIndex = 0U; memset(pMeasurement->average24h.samples, 0U, AVG24H_SAMPLE_SIZE); + */ pMeasurement->predict60s.fValue = 0.0f; pMeasurement->predict60s.bufferCount = 0U; @@ -151,6 +153,7 @@ void updateAverage(sMeasurement *pMeasurement) pMeasurement->average60s.fValue = sum / pMeasurement->average60s.bufferCount; // Average form the last 24h + /* pMeasurement->average24h.samples[pMeasurement->average24h.bufferIndex] = pMeasurement->fCurrentValue; pMeasurement->average24h.bufferIndex = (pMeasurement->average24h.bufferIndex + 1) % AVG24H_SAMPLE_SIZE; @@ -166,6 +169,7 @@ void updateAverage(sMeasurement *pMeasurement) } pMeasurement->average24h.fValue = sum / pMeasurement->average24h.bufferCount; + */ } void updatePrediction(sMeasurement *pMeasurement) diff --git a/main/inputs.h b/main/inputs.h index eafca07..c6fed83 100644 --- a/main/inputs.h +++ b/main/inputs.h @@ -3,7 +3,7 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define AVG10S_SAMPLE_SIZE 10U #define AVG60S_SAMPLE_SIZE 60U -#define AVG24H_SAMPLE_SIZE 60U * 60U * 24U +#define AVG24H_SAMPLE_SIZE 60U // * 60U * 24U #define PRED60S_SAMPLE_SIZE 60U typedef enum _BurnerErrorState @@ -21,7 +21,7 @@ typedef enum _MeasurementErrorState typedef struct _Average { float fValue; - float samples[MAX(AVG10S_SAMPLE_SIZE, AVG60S_SAMPLE_SIZE)]; + float samples[MAX(AVG10S_SAMPLE_SIZE, MAX(AVG60S_SAMPLE_SIZE, AVG24H_SAMPLE_SIZE))]; size_t bufferIndex; size_t bufferCount; } sAverage; @@ -39,7 +39,7 @@ typedef struct _Measurement float fCurrentValue; sAverage average10s; sAverage average60s; - sAverage average24h; + // sAverage average24h; sPredict predict60s; eMeasurementErrorState state; } sMeasurement; diff --git a/main/metrics.c b/main/metrics.c index 0aa2548..cf81594 100644 --- a/main/metrics.c +++ b/main/metrics.c @@ -129,10 +129,11 @@ void taskMetrics(void *pvParameters) u16MetricCounter++; // Chamber Temperature Average 24h + /* strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg24h"); aMetrics[u16MetricCounter].type = FLOAT; aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average24h.fValue; - u16MetricCounter++; + u16MetricCounter++;*/ // Chamber Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_pred60"); @@ -159,10 +160,11 @@ void taskMetrics(void *pvParameters) u16MetricCounter++; // Inlet Flow Temperature Average 24h + /* strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg24h"); aMetrics[u16MetricCounter].type = FLOAT; aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average24h.fValue; - u16MetricCounter++; + u16MetricCounter++;*/ // Inlet Flow Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_pred60"); @@ -189,11 +191,12 @@ void taskMetrics(void *pvParameters) u16MetricCounter++; // Outdoor Temperature Average 24h + /* strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg24h"); aMetrics[u16MetricCounter].type = FLOAT; aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average24h.fValue; u16MetricCounter++; - +*/ // Outdoor Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_pred60"); aMetrics[u16MetricCounter].type = FLOAT; @@ -219,10 +222,11 @@ void taskMetrics(void *pvParameters) u16MetricCounter++; // Return Flow Temperature Average 24h + /* strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg24h"); aMetrics[u16MetricCounter].type = FLOAT; aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average24h.fValue; - u16MetricCounter++; + u16MetricCounter++;*/ // Return Flow Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_pred60"); From b3a571da3f3531cf7f56258a7397007db1f3b4c354874a73f11d276c88cfd512 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 18 Oct 2025 20:39:36 +0200 Subject: [PATCH 15/19] damping instead of 24h average --- main/inputs.c | 46 +++++++++++++++++++--------------------------- main/inputs.h | 6 ++++-- main/metrics.c | 37 +++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 49 deletions(-) diff --git a/main/inputs.c b/main/inputs.c index 19da2c7..0f27cc6 100644 --- a/main/inputs.c +++ b/main/inputs.c @@ -88,26 +88,20 @@ void initMeasurement(sMeasurement *pMeasurement) return; pMeasurement->state = MEASUREMENT_FAULT; - pMeasurement->fCurrentValue = 0.0f; + pMeasurement->fCurrentValue = INITIALISATION_VALUE; + pMeasurement->fDampedValue = INITIALISATION_VALUE; - pMeasurement->average10s.fValue = 0.0f; + pMeasurement->average10s.fValue = INITIALISATION_VALUE; pMeasurement->average10s.bufferCount = 0U; pMeasurement->average10s.bufferIndex = 0U; memset(pMeasurement->average10s.samples, 0U, AVG10S_SAMPLE_SIZE); - pMeasurement->average60s.fValue = 0.0f; + pMeasurement->average60s.fValue = INITIALISATION_VALUE; pMeasurement->average60s.bufferCount = 0U; pMeasurement->average60s.bufferIndex = 0U; memset(pMeasurement->average60s.samples, 0U, AVG60S_SAMPLE_SIZE); - /* - pMeasurement->average24h.fValue = 0.0f; - pMeasurement->average24h.bufferCount = 0U; - pMeasurement->average24h.bufferIndex = 0U; - memset(pMeasurement->average24h.samples, 0U, AVG24H_SAMPLE_SIZE); - */ - - pMeasurement->predict60s.fValue = 0.0f; + pMeasurement->predict60s.fValue = INITIALISATION_VALUE; pMeasurement->predict60s.bufferCount = 0U; pMeasurement->predict60s.bufferIndex = 0U; memset(pMeasurement->predict60s.samples, 0U, PRED60S_SAMPLE_SIZE); @@ -152,24 +146,22 @@ void updateAverage(sMeasurement *pMeasurement) pMeasurement->average60s.fValue = sum / pMeasurement->average60s.bufferCount; - // Average form the last 24h - /* - pMeasurement->average24h.samples[pMeasurement->average24h.bufferIndex] = pMeasurement->fCurrentValue; - pMeasurement->average24h.bufferIndex = (pMeasurement->average24h.bufferIndex + 1) % AVG24H_SAMPLE_SIZE; - - if (pMeasurement->average24h.bufferCount < AVG24H_SAMPLE_SIZE) + // Damped current value + if (pMeasurement->fDampedValue == INITIALISATION_VALUE) { - pMeasurement->average24h.bufferCount++; + pMeasurement->fDampedValue = pMeasurement->fCurrentValue; } - - sum = 0.0; - for (int i = 0; i <= pMeasurement->average24h.bufferCount; i++) + else { - sum += pMeasurement->average24h.samples[i]; + if (pMeasurement->fCurrentValue > pMeasurement->fDampedValue) + { + pMeasurement->fDampedValue = pMeasurement->fDampedValue + (DAMPING_FACTOR * (pMeasurement->fCurrentValue - pMeasurement->fDampedValue)); + } + else + { + pMeasurement->fDampedValue = pMeasurement->fDampedValue - (DAMPING_FACTOR * (pMeasurement->fDampedValue - pMeasurement->fCurrentValue)); + } } - - pMeasurement->average24h.fValue = sum / pMeasurement->average24h.bufferCount; - */ } void updatePrediction(sMeasurement *pMeasurement) @@ -297,9 +289,9 @@ void taskInput(void *pvParameters) float linearRegressionPredict(const float *samples, size_t count, size_t bufferIndex, float futureIndex) { if (count == 0) - return 0.0f; // No prediction possible with no data + return INITIALISATION_VALUE; // No prediction possible with no data - float sumX = 0.0f, sumY = 0.0f, sumXY = 0.0f, sumX2 = 0.0f; + float sumX = INITIALISATION_VALUE, sumY = INITIALISATION_VALUE, sumXY = INITIALISATION_VALUE, sumX2 = INITIALISATION_VALUE; for (size_t i = 0; i < count; i++) { diff --git a/main/inputs.h b/main/inputs.h index c6fed83..eed75b7 100644 --- a/main/inputs.h +++ b/main/inputs.h @@ -1,10 +1,12 @@ #pragma once #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define INITIALISATION_VALUE 0.0f #define AVG10S_SAMPLE_SIZE 10U #define AVG60S_SAMPLE_SIZE 60U -#define AVG24H_SAMPLE_SIZE 60U // * 60U * 24U +#define AVG24H_SAMPLE_SIZE 24U #define PRED60S_SAMPLE_SIZE 60U +#define DAMPING_FACTOR 0.01f typedef enum _BurnerErrorState { @@ -37,9 +39,9 @@ typedef struct _Predict typedef struct _Measurement { float fCurrentValue; + float fDampedValue; sAverage average10s; sAverage average60s; - // sAverage average24h; sPredict predict60s; eMeasurementErrorState state; } sMeasurement; diff --git a/main/metrics.c b/main/metrics.c index cf81594..ca430b9 100644 --- a/main/metrics.c +++ b/main/metrics.c @@ -128,12 +128,11 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average60s.fValue; u16MetricCounter++; - // Chamber Temperature Average 24h - /* - strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_avg24h"); + // Chamber Temperature Damped + strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_damped"); aMetrics[u16MetricCounter].type = FLOAT; - aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().average24h.fValue; - u16MetricCounter++;*/ + aMetrics[u16MetricCounter].fMetricValue = getChamberTemperature().fDampedValue; + u16MetricCounter++; // Chamber Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "chamber_temperature_pred60"); @@ -159,12 +158,11 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average60s.fValue; u16MetricCounter++; - // Inlet Flow Temperature Average 24h - /* - strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_avg24h"); + // Inlet Flow Temperature Damped + strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_damped"); aMetrics[u16MetricCounter].type = FLOAT; - aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().average24h.fValue; - u16MetricCounter++;*/ + aMetrics[u16MetricCounter].fMetricValue = getInletFlowTemperature().fDampedValue; + u16MetricCounter++; // Inlet Flow Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "inlet_flow_temperature_pred60"); @@ -190,13 +188,12 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average60s.fValue; u16MetricCounter++; - // Outdoor Temperature Average 24h - /* - strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_avg24h"); + // Outdoor Temperature Average Damped + strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_damped"); aMetrics[u16MetricCounter].type = FLOAT; - aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().average24h.fValue; + aMetrics[u16MetricCounter].fMetricValue = getOutdoorTemperature().fDampedValue; u16MetricCounter++; -*/ + // Outdoor Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "outdoor_temperature_pred60"); aMetrics[u16MetricCounter].type = FLOAT; @@ -221,12 +218,11 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average60s.fValue; u16MetricCounter++; - // Return Flow Temperature Average 24h - /* - strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_avg24h"); + // Return Flow Temperature Damped + strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_damped"); aMetrics[u16MetricCounter].type = FLOAT; - aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average24h.fValue; - u16MetricCounter++;*/ + aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().fDampedValue; + u16MetricCounter++; // Return Flow Temperature Predict 60s strcpy(aMetrics[u16MetricCounter].caMetricName, "return_flow_temperature_pred60"); @@ -286,6 +282,7 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].i64MetricValue = ap.rssi; u16MetricCounter++; + ESP_ERROR_CHECK(u16MetricCounter > METRIC_MAX_COUNT); vSetMetrics(aMetrics, u16MetricCounter); } } From 5b987bfd5b0829a9b0abc72b7deedbe0d49e10ad89cbdd827624c9f23d9b697b Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 24 Oct 2025 11:14:10 +0200 Subject: [PATCH 16/19] improve damping --- main/inputs.c | 7 ++++--- main/inputs.h | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/main/inputs.c b/main/inputs.c index 0f27cc6..a9ef723 100644 --- a/main/inputs.c +++ b/main/inputs.c @@ -155,11 +155,12 @@ void updateAverage(sMeasurement *pMeasurement) { if (pMeasurement->fCurrentValue > pMeasurement->fDampedValue) { - pMeasurement->fDampedValue = pMeasurement->fDampedValue + (DAMPING_FACTOR * (pMeasurement->fCurrentValue - pMeasurement->fDampedValue)); + pMeasurement->fDampedValue = pMeasurement->fDampedValue + (DAMPING_FACTOR_WARMER * (pMeasurement->fCurrentValue - pMeasurement->fDampedValue)); } - else + + if (pMeasurement->fCurrentValue < pMeasurement->fDampedValue) { - pMeasurement->fDampedValue = pMeasurement->fDampedValue - (DAMPING_FACTOR * (pMeasurement->fDampedValue - pMeasurement->fCurrentValue)); + pMeasurement->fDampedValue = pMeasurement->fDampedValue - (DAMPING_FACTOR_COLDER * (pMeasurement->fDampedValue - pMeasurement->fCurrentValue)); } } } diff --git a/main/inputs.h b/main/inputs.h index eed75b7..a005e3c 100644 --- a/main/inputs.h +++ b/main/inputs.h @@ -6,7 +6,8 @@ #define AVG60S_SAMPLE_SIZE 60U #define AVG24H_SAMPLE_SIZE 24U #define PRED60S_SAMPLE_SIZE 60U -#define DAMPING_FACTOR 0.01f +#define DAMPING_FACTOR_WARMER 0.001f +#define DAMPING_FACTOR_COLDER 0.005f typedef enum _BurnerErrorState { From e8c62a1bd71cf662ad44e565cdfc5ebe203e19539969683c26c068c79b5e3d7c Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 24 Oct 2025 15:35:23 +0200 Subject: [PATCH 17/19] slow down damping --- main/inputs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/inputs.h b/main/inputs.h index a005e3c..17e095b 100644 --- a/main/inputs.h +++ b/main/inputs.h @@ -6,8 +6,8 @@ #define AVG60S_SAMPLE_SIZE 60U #define AVG24H_SAMPLE_SIZE 24U #define PRED60S_SAMPLE_SIZE 60U -#define DAMPING_FACTOR_WARMER 0.001f -#define DAMPING_FACTOR_COLDER 0.005f +#define DAMPING_FACTOR_WARMER 0.00001f // 0.001% +#define DAMPING_FACTOR_COLDER 0.00005f // 0.005% typedef enum _BurnerErrorState { From 524d94c515ea2dd34fc2e2ef886c3ab233ba9afcdcb3c2e0789fe1a15baa1dc4 Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 24 Oct 2025 16:19:49 +0200 Subject: [PATCH 18/19] Export current entry temperatures as metrics --- main/control.c | 26 ++++++++++++++------------ main/control.h | 2 ++ main/metrics.c | 25 +++++++++++++++++++++++++ main/metrics.h | 2 +- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/main/control.c b/main/control.c index 42eb184..4ff2ffa 100644 --- a/main/control.c +++ b/main/control.c @@ -22,9 +22,8 @@ static const char *TAG = "smart-oil-heater-control-system-control"; static eControlState sControlState = CONTROL_STARTING; - // Control table for daily schedules -static sControlDay aControlTable[] = { +static const sControlDay aControlTable[] = { {MONDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, {TUESDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, {WEDNESDAY, 2U, {{{4, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 0}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, @@ -33,11 +32,11 @@ static sControlDay aControlTable[] = { {SATURDAY, 2U, {{{6, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{23, 30}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, {SUNDAY, 2U, {{{6, 45}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_DAY, CHAMBER_TEMPERATURE_TARGET}, {{22, 30}, RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT, CHAMBER_TEMPERATURE_TARGET}}}, }; +static sControlTemperatureEntry currentControlEntry = aControlTable[0].aTemperatureEntries[0]; // Function prototypes void taskControl(void *pvParameters); -eControlWeekday getCurrentWeekday(void); -sControlTemperatureEntry getCurrentTemperatureEntry(void); +void findControlCurrentTemperatureEntry(void); void initControl(void) { @@ -101,7 +100,7 @@ void taskControl(void *pvParameters) continue; } - sControlTemperatureEntry currentControlEntry = getCurrentTemperatureEntry(); + sControlTemperatureEntry currentControlEntry = getControlCurrentTemperatureEntry(); if (getOutdoorTemperature().average60s.fValue >= SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH) { @@ -192,7 +191,7 @@ eControlState getControlState(void) return sControlState; } -eControlWeekday getCurrentWeekday(void) +eControlWeekday getControlCurrentWeekday(void) { time_t now; struct tm *timeinfo; @@ -204,10 +203,9 @@ eControlWeekday getCurrentWeekday(void) return (eControlWeekday)((day == 0) ? 6 : day - 1); } -sControlTemperatureEntry getCurrentTemperatureEntry(void) +void findControlCurrentTemperatureEntry(void) { - sControlTemperatureEntry result = aControlTable[0].aTemperatureEntries[0]; - eControlWeekday currentDay = getCurrentWeekday(); + eControlWeekday currentDay = getControlCurrentWeekday(); time_t now; struct tm timeinfo; @@ -225,10 +223,14 @@ sControlTemperatureEntry getCurrentTemperatureEntry(void) (aControlTable[i].day == currentDay && aControlTable[i].aTemperatureEntries[j].timestamp.hour > hour) || (aControlTable[i].day == currentDay && aControlTable[i].aTemperatureEntries[j].timestamp.hour == hour && aControlTable[i].aTemperatureEntries[j].timestamp.minute >= minute)) { - return aControlTable[i].aTemperatureEntries[j]; + currentControlEntry = aControlTable[i].aTemperatureEntries[j]; } - result = aControlTable[i].aTemperatureEntries[j]; + currentControlEntry = aControlTable[i].aTemperatureEntries[j]; } } - return result; +} + +sControlTemperatureEntry getControlCurrentTemperatureEntry(void) +{ + return currentControlEntry; } diff --git a/main/control.h b/main/control.h index fe7f3ad..7690bd1 100644 --- a/main/control.h +++ b/main/control.h @@ -54,3 +54,5 @@ typedef struct _ControlDay void initControl(void); eControlState getControlState(void); +eControlWeekday getControlCurrentWeekday(void); +sControlTemperatureEntry getControlCurrentTemperatureEntry(void); diff --git a/main/metrics.c b/main/metrics.c index ca430b9..6f1b2db 100644 --- a/main/metrics.c +++ b/main/metrics.c @@ -254,6 +254,31 @@ void taskMetrics(void *pvParameters) aMetrics[u16MetricCounter].u8MetricValue = getControlState(); u16MetricCounter++; + // Control Current Weekday + strcpy(aMetrics[u16MetricCounter].caMetricName, "control_current_weekday"); + aMetrics[u16MetricCounter].type = INTEGER_U8; + aMetrics[u16MetricCounter].u8MetricValue = getControlCurrentWeekday(); + u16MetricCounter++; + + // Control Current Entry Time + strcpy(aMetrics[u16MetricCounter].caMetricName, "control_current_entry_time"); + aMetrics[u16MetricCounter].type = INTEGER_64; + int64_t i64SecondsSinceMidnight = (getControlCurrentTemperatureEntry().timestamp.hour * 60U * 60U) + (getControlCurrentTemperatureEntry().timestamp.minute * 60U); + aMetrics[u16MetricCounter].i64MetricValue = i64SecondsSinceMidnight; + u16MetricCounter++; + + // Control Current Entry Chamber Temperature + strcpy(aMetrics[u16MetricCounter].caMetricName, "control_current_entry_chamber_temperature"); + aMetrics[u16MetricCounter].type = FLOAT; + aMetrics[u16MetricCounter].fMetricValue = getControlCurrentTemperatureEntry().fChamberTemperature; + u16MetricCounter++; + + // Control Current Entry Return Flow Temperature + strcpy(aMetrics[u16MetricCounter].caMetricName, "control_current_entry_return_flow_temperature"); + aMetrics[u16MetricCounter].type = FLOAT; + aMetrics[u16MetricCounter].fMetricValue = getControlCurrentTemperatureEntry().fReturnFlowTemperature; + u16MetricCounter++; + // SNTP State strcpy(aMetrics[u16MetricCounter].caMetricName, "sntp_state"); aMetrics[u16MetricCounter].type = INTEGER_U8; diff --git a/main/metrics.h b/main/metrics.h index 230d711..e8eafed 100644 --- a/main/metrics.h +++ b/main/metrics.h @@ -4,7 +4,7 @@ #define HTML_RESPONSE_SIZE 4096U #define METRIC_NAME_MAX_SIZE 64U -#define METRIC_MAX_COUNT 34U +#define METRIC_MAX_COUNT 38U typedef enum _MetricValueType { From 33c7bc4007d90ba90dd4cf51248c8de2c509f97f38d45ebe8d66ca24d79e6ef6 Mon Sep 17 00:00:00 2001 From: localhorst Date: Fri, 24 Oct 2025 17:23:47 +0200 Subject: [PATCH 19/19] use damped value as event source --- main/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/control.c b/main/control.c index 4ff2ffa..7ddcab4 100644 --- a/main/control.c +++ b/main/control.c @@ -102,11 +102,11 @@ void taskControl(void *pvParameters) sControlTemperatureEntry currentControlEntry = getControlCurrentTemperatureEntry(); - if (getOutdoorTemperature().average60s.fValue >= SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH) + if (getOutdoorTemperature().fDampedValue >= SUMMER_MODE_TEMPERATURE_THRESHOLD_HIGH) { bSummerMode = true; } - else if (getOutdoorTemperature().average60s.fValue <= SUMMER_MODE_TEMPERATURE_THRESHOLD_LOW) + else if (getOutdoorTemperature().fDampedValue <= SUMMER_MODE_TEMPERATURE_THRESHOLD_LOW) { bSummerMode = false; }