Add control based on control table #8
							
								
								
									
										8
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -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" | ||||
|  | ||||
| @ -39,7 +39,7 @@ Sntp <|-- Metrics | ||||
|  | ||||
|     class Control{ | ||||
|         +taskControl() | ||||
|         -timetable | ||||
|         -controlTable | ||||
|         +getControlState() | ||||
|     } | ||||
|  | ||||
|  | ||||
							
								
								
									
										134
									
								
								main/control.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								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; | ||||
| } | ||||
| @ -1,4 +1,7 @@ | ||||
| #pragma once | ||||
| #include <time.h> | ||||
|  | ||||
| #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); | ||||
| eControlState getControlState(void); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user