From 9dd525457eab00692a03a6e2ef6690a476341ebe2946499855f6814eea82aead Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 22 Dec 2024 16:34:26 +0100 Subject: [PATCH 1/3] add control table --- .vscode/settings.json | 8 +++++++- README.md | 2 +- main/control.c | 31 ++++++++++++++++++++++++++++--- main/control.h | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b007ac5..d853b22 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,7 +23,13 @@ "string.h": "c", "time.h": "c", "timers.h": "c", - "nvs_flash.h": "c" + "nvs_flash.h": "c", + "numbers": "c", + "array": "c", + "string_view": "c", + "format": "c", + "initializer_list": "c", + "span": "c" }, "idf.openOcdConfigs": [ "board/esp32-wrover-kit-3.3v.cfg" diff --git a/README.md b/README.md index 22859b8..5e80aad 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Sntp <|-- Metrics class Control{ +taskControl() - -timetable + -controlTable +getControlState() } diff --git a/main/control.c b/main/control.c index a833069..7f70c51 100644 --- a/main/control.c +++ b/main/control.c @@ -7,15 +7,29 @@ #include "safety.h" #include "sntp.h" -#define PERIODIC_INTERVAL 1U // run safety checks every 1sec +#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 20.0 +#define CHAMPER_TEMPERATURE_TARGET 70.0 static const char *TAG = "smart-oil-heater-control-system-control"; static eControlState sControlState = CONTROL_STARTING; + +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}}}, +}; + void taskControl(void *pvParameters); void initControl(void) { - BaseType_t taskCreated = xTaskCreate( taskControl, // Function to implement the task "taskControl", // Task name @@ -55,10 +69,21 @@ void taskControl(void *pvParameters) continue; } - // TODO: control the burner based on timetable + // TODO: control the burner based on controltable setCirculationPumpState(DISABLED); setBurnerState(ENABLED); setSafetyControlState(ENABLED); + + int numberOfDays = sizeof(aControlTable) / sizeof(aControlTable[0]); + ESP_LOGI(TAG, "Number of days: %i", numberOfDays); + + for (int i = 0; i < numberOfDays; i++) + { + ESP_LOGI(TAG, "Day %d: %d", i + 1, aControlTable[i].day); + + int numberOfEntries = aControlTable[i].entryCount; + ESP_LOGI(TAG, "Number of entries: %i", numberOfEntries); + } } } diff --git a/main/control.h b/main/control.h index bd80ca4..9ac2179 100644 --- a/main/control.h +++ b/main/control.h @@ -1,4 +1,7 @@ #pragma once +#include + +#define MAX_TEMPERATURE_ENTRIES_PER_DAY 24U typedef enum _ControlState { @@ -10,5 +13,37 @@ typedef enum _ControlState CONTROL_FAULT, } eControlState; +typedef enum _ControlWeekday +{ + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY, + WEEKDAY_COUNT +} eControlWeekday; + +typedef struct _ControlTimestamp +{ + uint8_t hour; + uint8_t minute; +} sControlTimestamp; + +typedef struct _ControlTemperatureEntry +{ + sControlTimestamp timestamp; + float fReturnFlowTemperature; + float fChamberTemperature; +} sControlTemperatureEntry; + +typedef struct _ControlDay +{ + eControlWeekday day; + size_t entryCount; // number of entries for each day + sControlTemperatureEntry aTemperatureEntries[MAX_TEMPERATURE_ENTRIES_PER_DAY]; +} sControlDay; + void initControl(void); eControlState getControlState(void); \ No newline at end of file From e314b1a5b4664022a19bfadf9a6b4720765117ee0ee8390385eed74bda73b88b Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 22 Dec 2024 23:35:40 +0100 Subject: [PATCH 2/3] control burner based on table --- main/control.c | 115 +++++++++++++++++++++++++++++++++++++++++++------ main/control.h | 3 +- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/main/control.c b/main/control.c index 7f70c51..47d2923 100644 --- a/main/control.c +++ b/main/control.c @@ -10,7 +10,7 @@ #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 20.0 +#define RETURN_FLOW_TEMPERATURE_LOWER_LIMIT_NIGHT 25.0 #define CHAMPER_TEMPERATURE_TARGET 70.0 static const char *TAG = "smart-oil-heater-control-system-control"; @@ -27,6 +27,8 @@ static sControlDay aControlTable[] = { }; void taskControl(void *pvParameters); +eControlWeekday getCurrentWeekday(void); +sControlTemperatureEntry getCurrentTemperatureEntry(void); void initControl(void) { @@ -51,6 +53,7 @@ void initControl(void) void taskControl(void *pvParameters) { + bool bHeatingInAction = false; while (1) { vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS); @@ -69,20 +72,38 @@ void taskControl(void *pvParameters) continue; } - // TODO: control the burner based on controltable - setCirculationPumpState(DISABLED); - setBurnerState(ENABLED); - setSafetyControlState(ENABLED); + 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); - int numberOfDays = sizeof(aControlTable) / sizeof(aControlTable[0]); - ESP_LOGI(TAG, "Number of days: %i", numberOfDays); - - for (int i = 0; i < numberOfDays; i++) + if (getChamberTemperature().fCurrentValue >= currentControlEntry.fChamberTemperature) { - ESP_LOGI(TAG, "Day %d: %d", i + 1, aControlTable[i].day); + bHeatingInAction = false; + setCirculationPumpState(ENABLED); + setBurnerState(DISABLED); + setSafetyControlState(ENABLED); + } + else + { + if (bHeatingInAction) + { + // TODO: Check burner fault signal here + } + } - int numberOfEntries = aControlTable[i].entryCount; - ESP_LOGI(TAG, "Number of entries: %i", numberOfEntries); + if (bHeatingInAction == false) + { + if (getReturnFlowTemperature().average60s.fValue <= currentControlEntry.fReturnFlowTemperature) + { + bHeatingInAction = true; + setCirculationPumpState(ENABLED); + setBurnerState(ENABLED); + setSafetyControlState(ENABLED); + sControlState = CONTROL_HEATING; + } + else + { + sControlState = CONTROL_RETURN_FLOW_TOO_WARM; + } } } } @@ -91,3 +112,73 @@ eControlState getControlState(void) { return sControlState; } + +eControlWeekday getCurrentWeekday(void) +{ + time_t now; + struct tm *timeinfo; + + // Get the current time + time(&now); + timeinfo = localtime(&now); // Convert to local time + + // 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; +} + +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); + + 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++) + { + // 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]; + + if (((aControlTable[i].day + 1) % 6) >= currentDay) + { + if (aControlTable[i].aTemperatureEntries[j].timestamp.hour >= hour) + { + if (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; + } + } + } + } + } + return result; +} \ No newline at end of file diff --git a/main/control.h b/main/control.h index 9ac2179..d62b061 100644 --- a/main/control.h +++ b/main/control.h @@ -22,7 +22,6 @@ typedef enum _ControlWeekday FRIDAY, SATURDAY, SUNDAY, - WEEKDAY_COUNT } eControlWeekday; typedef struct _ControlTimestamp @@ -46,4 +45,4 @@ typedef struct _ControlDay } sControlDay; void initControl(void); -eControlState getControlState(void); \ No newline at end of file +eControlState getControlState(void); From 0a0b51edb668d11dcf4c8a711cbf243bcc4b97150355458afbe03f6af7016e30 Mon Sep 17 00:00:00 2001 From: localhorst Date: Mon, 23 Dec 2024 13:19:53 +0100 Subject: [PATCH 3/3] fix find of correct control entry --- main/control.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/main/control.c b/main/control.c index 47d2923..fb1b7ff 100644 --- a/main/control.c +++ b/main/control.c @@ -164,20 +164,26 @@ sControlTemperatureEntry getCurrentTemperatureEntry(void) for (int j = 0; j < aControlTable[i].entryCount; j++) { + if ((aControlTable[i].day) > currentDay) + { + // 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; + } + + 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]; - - if (((aControlTable[i].day + 1) % 6) >= currentDay) - { - if (aControlTable[i].aTemperatureEntries[j].timestamp.hour >= hour) - { - if (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; - } - } - } } } return result;