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..fb1b7ff 100644 --- a/main/control.c +++ b/main/control.c @@ -7,15 +7,31 @@ #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 25.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); +eControlWeekday getCurrentWeekday(void); +sControlTemperatureEntry getCurrentTemperatureEntry(void); void initControl(void) { - BaseType_t taskCreated = xTaskCreate( taskControl, // Function to implement the task "taskControl", // Task name @@ -37,6 +53,7 @@ void initControl(void) void taskControl(void *pvParameters) { + bool bHeatingInAction = false; while (1) { vTaskDelay(PERIODIC_INTERVAL * 1000U / portTICK_PERIOD_MS); @@ -55,10 +72,39 @@ void taskControl(void *pvParameters) continue; } - // TODO: control the burner based on timetable - 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); + + if (getChamberTemperature().fCurrentValue >= currentControlEntry.fChamberTemperature) + { + bHeatingInAction = false; + setCirculationPumpState(ENABLED); + setBurnerState(DISABLED); + setSafetyControlState(ENABLED); + } + else + { + if (bHeatingInAction) + { + // TODO: Check burner fault signal here + } + } + + 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; + } + } } } @@ -66,3 +112,79 @@ 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++) + { + 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]; + } + } + return result; +} \ No newline at end of file diff --git a/main/control.h b/main/control.h index bd80ca4..d62b061 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,36 @@ typedef enum _ControlState CONTROL_FAULT, } eControlState; +typedef enum _ControlWeekday +{ + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY, +} 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 +eControlState getControlState(void);