Merge pull request 'Add control loop state' (#7) from feature/control-status into main
Reviewed-on: #7
This commit is contained in:
		
							
								
								
									
										96
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								README.md
									
									
									
									
									
								
							| @ -40,6 +40,7 @@ Sntp <|-- Metrics | ||||
|     class Control{ | ||||
|         +taskControl() | ||||
|         -timetable | ||||
|         +getControlState() | ||||
|     } | ||||
|  | ||||
|     class Safety{ | ||||
| @ -71,12 +72,91 @@ Sntp <|-- Metrics | ||||
|     } | ||||
| ``` | ||||
|  | ||||
| ### Hardware | ||||
| ### Prometheus Metrics | ||||
| `curl http://X.X.X.X:9100/metrics` | ||||
| #### Example | ||||
| ``` | ||||
| burner_fault_pending 1 | ||||
| circulation_pump_enabled 0 | ||||
| burner_enabled 1 | ||||
| safety_contact_enabled 1 | ||||
| chamber_temperature 21.812500 | ||||
| chamber_temperature_avg10 21.837500 | ||||
| chamber_temperature_avg60 21.825521 | ||||
| inlet_flow_temperature 22.437500 | ||||
| inlet_flow_temperature_avg10 22.437500 | ||||
| inlet_flow_temperature_avg60 22.434896 | ||||
| outdoor_temperature 21.937500 | ||||
| outdoor_temperature_avg10 21.937500 | ||||
| outdoor_temperature_avg60 21.933594 | ||||
| return_flow_temperature 22.375000 | ||||
| return_flow_temperature_avg10 22.375000 | ||||
| return_flow_temperature_avg60 22.375000 | ||||
| chamber_temperature_state 0 | ||||
| outdoor_temperature_state 0 | ||||
| inlet_flow_temperature_state 0 | ||||
| return_flow_temperature_state 0 | ||||
| safety_state 0 | ||||
| control_state 5 | ||||
| sntp_state 0 | ||||
| system_unixtime 1734814285 | ||||
| uptime_seconds 90 | ||||
| wifi_rssi -63 | ||||
| ``` | ||||
|  | ||||
| #### Status Encoding | ||||
| ##### Digital Themperatur Sensor DS10B20 | ||||
|  - chamber_temperature_state | ||||
|  - outdoor_temperature_state | ||||
|  - inlet_flow_temperature_state | ||||
|  - return_flow_temperature_state | ||||
|  | ||||
| | Enum eSensorErrorState in [safety.h](main/safety.h) | Value | Description         | | ||||
| |-----------------------------------------------------|-------|---------------------| | ||||
| | SENSOR_NO_ERROR                                     | 0     |                     | | ||||
| | SENSOR_TOO_HIGH                                     | 1     | Sanity check failed | | ||||
| | SENSOR_TOO_LOW                                      | 2     | Sanity check failed | | ||||
| | SENSOR_UNCHANGED                                    | 3     | Sanity check failed | | ||||
| | SENSOR_NOT_FOUND                                    | 4     | No Communication    | | ||||
|  | ||||
| ##### Safety Loop | ||||
|  - safety_state | ||||
|  | ||||
| | Enum eSafetyState in [safety.h](main/safety.h) | Value | Description                | | ||||
| |------------------------------------------------|-------|----------------------------| | ||||
| | SAFETY_NO_ERROR                                | 0     |                            | | ||||
| | SAFETY_SENSOR_ERROR                            | 1     | At least one sensor failed | | ||||
| | SAFETY_INTERNAL_ERROR                          | 2     | Internal error             | | ||||
|  | ||||
| ##### Control Loop | ||||
|  - control_state | ||||
|  | ||||
| | Enum eControlState in [control.h](main/control.h) | Value | Description           | | ||||
| |---------------------------------------------------|-------|-----------------------| | ||||
| | CONTROL_STARTING                                  | 0     |                       | | ||||
| | CONTROL_HEATING                                   | 1     | Burner running        | | ||||
| | CONTROL_OUTDOOR_TOO_WARM                          | 2     | Heating not needed    | | ||||
| | CONTROL_RETURN_FLOW_TOO_WARM                      | 3     | Heating not needed    | | ||||
| | CONTROL_BURNER_FAULT                              | 4     | Burner reported fault | | ||||
| | CONTROL_FAULT                                     | 5     | Unable to control     | | ||||
|  | ||||
| ##### SNTP Client | ||||
|  - sntp_state | ||||
|  | ||||
| | Enum eSntpState in [sntp.h](main/sntp.h) | Value | Description | | ||||
| |------------------------------------------|-------|-------------| | ||||
| | SYNC_SUCCESSFUL                          | 0     |             | | ||||
| | SYNC_NOT_STARTED                         | 1     |             | | ||||
| | SYNC_FAILED                              | 2     |             | | ||||
|  | ||||
| ## Hardware | ||||
|  | ||||
| | Function                              | ESP32 | PLC ES32C14       | | ||||
| |---------------------------------------|-------|-------------------| | ||||
| | Output CirculationPump                | IO27  | Relay 1 NC1       | | ||||
| | Output Burner Fire Signal             | IO14  | Relay 2 NC2       | | ||||
| | Output Safety Contact (powers Burner) | IO12  | Relay 3 NC2       | | ||||
| | Input Burner Fault                    | IO19  | Digital Input IN1 | | ||||
| | Input Temperature DS10B20             | IO04  | 1-Wire            | | ||||
|  | ||||
|  | ||||
| | Function                              | ESP32 | PLC ES32C14               | | ||||
| |---------------------------------------|-------|---------------------------| | ||||
| | Output CirculationPump                | IO27  | Relay 1 NC1               | | ||||
| | Output Burner Fire Signal             | IO14  | Relay 2 NC2               | | ||||
| | Output Safety Contact (powers Burner) | IO12  | Relay 3 NC2               | | ||||
| | Input Burner Fault                    | IO19  | Digital Input IN1         | | ||||
| | Input Temperature DS10B20             | IO04  | 1-Wire                    | | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
| #define PERIODIC_INTERVAL 1U // run safety checks every 1sec | ||||
|  | ||||
| static const char *TAG = "smart-oil-heater-control-system-control"; | ||||
|  | ||||
| static eControlState sControlState = CONTROL_STARTING; | ||||
| void taskControl(void *pvParameters); | ||||
|  | ||||
| void initControl(void) | ||||
| @ -44,12 +44,14 @@ void taskControl(void *pvParameters) | ||||
|         if (getSafetyState() != SAFETY_NO_ERROR) | ||||
|         { | ||||
|             ESP_LOGW(TAG, "Control not possible due to safety fault!"); | ||||
|             sControlState = CONTROL_FAULT; | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (getSntpState() != SYNC_SUCCESSFUL) | ||||
|         { | ||||
|             ESP_LOGW(TAG, "Control not possible due to sntp fault!"); | ||||
|             sControlState = CONTROL_FAULT; | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
| @ -59,3 +61,8 @@ void taskControl(void *pvParameters) | ||||
|         setSafetyControlState(ENABLED); | ||||
|     } | ||||
| } | ||||
|  | ||||
| eControlState getControlState(void) | ||||
| { | ||||
|     return sControlState; | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,14 @@ | ||||
| #pragma once | ||||
|  | ||||
| typedef enum _ControlState | ||||
| { | ||||
|     CONTROL_STARTING, | ||||
|     CONTROL_HEATING, | ||||
|     CONTROL_OUTDOOR_TOO_WARM, | ||||
|     CONTROL_RETURN_FLOW_TOO_WARM, | ||||
|     CONTROL_BURNER_FAULT, | ||||
|     CONTROL_FAULT, | ||||
| } eControlState; | ||||
|  | ||||
| void initControl(void); | ||||
| eControlState getControlState(void); | ||||
| @ -12,6 +12,7 @@ | ||||
| #include "inputs.h" | ||||
| #include "safety.h" | ||||
| #include "sntp.h" | ||||
| #include "control.h" | ||||
|  | ||||
| static const char *TAG = "smart-oil-heater-control-system-metrics"; | ||||
|  | ||||
| @ -181,15 +182,15 @@ void taskMetrics(void *pvParameters) | ||||
|         aMetrics[u16MetricCounter].fMetricValue = getReturnFlowTemperature().average60s.fValue; | ||||
|         u16MetricCounter++; | ||||
|  | ||||
|         /*Sensor status*/ | ||||
|         /*Sensor State*/ | ||||
|         sSensorSanityCheck aChecks[NUMBER_OF_SENSOR_SANITY_CHECKS]; | ||||
|         getSensorSanityStates(aChecks); | ||||
|         for (size_t i = 0; i < NUMBER_OF_SENSOR_SANITY_CHECKS; i++) | ||||
|         { | ||||
|             strcpy(aMetrics[u16MetricCounter].caMetricName, aChecks[i].name); | ||||
|             strcat(aMetrics[u16MetricCounter].caMetricName, "_status"); | ||||
|             strcat(aMetrics[u16MetricCounter].caMetricName, "_state"); | ||||
|             aMetrics[u16MetricCounter].type = INTEGER_U8; | ||||
|             aMetrics[u16MetricCounter].u8MetricValue = aChecks[i].status; | ||||
|             aMetrics[u16MetricCounter].u8MetricValue = aChecks[i].state; | ||||
|             u16MetricCounter++; | ||||
|         } | ||||
|  | ||||
| @ -199,8 +200,14 @@ void taskMetrics(void *pvParameters) | ||||
|         aMetrics[u16MetricCounter].u8MetricValue = getSafetyState(); | ||||
|         u16MetricCounter++; | ||||
|  | ||||
|         /*SNTP Status*/ | ||||
|         strcpy(aMetrics[u16MetricCounter].caMetricName, "sntp_status"); | ||||
|         /*Control State*/ | ||||
|         strcpy(aMetrics[u16MetricCounter].caMetricName, "control_state"); | ||||
|         aMetrics[u16MetricCounter].type = INTEGER_U8; | ||||
|         aMetrics[u16MetricCounter].u8MetricValue = getControlState(); | ||||
|         u16MetricCounter++; | ||||
|  | ||||
|         /*SNTP State*/ | ||||
|         strcpy(aMetrics[u16MetricCounter].caMetricName, "sntp_state"); | ||||
|         aMetrics[u16MetricCounter].type = INTEGER_U8; | ||||
|         aMetrics[u16MetricCounter].u8MetricValue = getSntpState(); | ||||
|         u16MetricCounter++; | ||||
|  | ||||
| @ -77,7 +77,7 @@ void checkSensorSanity(void) | ||||
|     for (int i = 0; i < NUMBER_OF_SENSOR_SANITY_CHECKS; i++) | ||||
|     { | ||||
|         // printf("Check sanity of sensor %s:\n", sanityChecks[i].name); | ||||
|         // printf("  Status: %u\n", sanityChecks[i].status); | ||||
|         // printf("  state: %u\n", sanityChecks[i].state); | ||||
|         // printf("  Sensor Limits: Max = %.2f, Min = %.2f\n", sanityChecks[i].sSensorLimit.max, sanityChecks[i].sSensorLimit.min); | ||||
|         // printf("  Last Sensor Temperature: %.2f\n", sanityChecks[i].fSensorTemperatureLast); | ||||
|  | ||||
| @ -86,7 +86,7 @@ void checkSensorSanity(void) | ||||
|         if (sCurrentMeasurement.state == MEASUREMENT_FAULT) | ||||
|         { | ||||
|             ESP_LOGE(TAG, "%s Sensor not found!", sanityChecks[i].name); | ||||
|             sanityChecks[i].status = SENSOR_NOT_FOUND; | ||||
|             sanityChecks[i].state = SENSOR_NOT_FOUND; | ||||
|             sSafetyState = SAFETY_SENSOR_ERROR; | ||||
|         } | ||||
|         else | ||||
| @ -97,7 +97,7 @@ void checkSensorSanity(void) | ||||
|                 if (sanityChecks[i].uUnchangedCounter >= (SENSOR_GRACE_PERIOD / PERIODIC_INTERVAL)) | ||||
|                 { | ||||
|                     ESP_LOGE(TAG, "%s Sensor reported unchanged value! %lf == %lf", sanityChecks[i].name, sCurrentMeasurement.fCurrentValue, sanityChecks[i].fSensorTemperatureLast); | ||||
|                     sanityChecks[i].status = SENSOR_UNCHANGED; | ||||
|                     sanityChecks[i].state = SENSOR_UNCHANGED; | ||||
|                     sSafetyState = SAFETY_SENSOR_ERROR; | ||||
|                 } | ||||
|             } | ||||
| @ -108,23 +108,23 @@ void checkSensorSanity(void) | ||||
|                 if (sCurrentMeasurement.fCurrentValue > sanityChecks[i].sSensorLimit.max) | ||||
|                 { | ||||
|                     ESP_LOGE(TAG, "%s Sensor reported too high value! %lf > %lf", sanityChecks[i].name, sCurrentMeasurement.fCurrentValue, sanityChecks[i].sSensorLimit.max); | ||||
|                     sanityChecks[i].status = SENSOR_TOO_HIGH; | ||||
|                     sanityChecks[i].state = SENSOR_TOO_HIGH; | ||||
|                     sSafetyState = SAFETY_SENSOR_ERROR; | ||||
|                 } | ||||
|                 else if (sCurrentMeasurement.fCurrentValue < sanityChecks[i].sSensorLimit.min) | ||||
|                 { | ||||
|                     ESP_LOGE(TAG, "%s Sensor reported too low value! %lf < %lf", sanityChecks[i].name, sCurrentMeasurement.fCurrentValue, sanityChecks[i].sSensorLimit.min); | ||||
|                     sanityChecks[i].status = SENSOR_TOO_LOW; | ||||
|                     sanityChecks[i].state = SENSOR_TOO_LOW; | ||||
|                     sSafetyState = SAFETY_SENSOR_ERROR; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     sanityChecks[i].uUnchangedCounter = 0U; | ||||
|                     sanityChecks[i].status = SENSOR_NO_ERROR; | ||||
|                     sanityChecks[i].state = SENSOR_NO_ERROR; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // printf("  Status: %u\n", sanityChecks[i].status); | ||||
|         // printf("  state: %u\n", sanityChecks[i].state); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -142,7 +142,7 @@ void getSensorSanityStates(sSensorSanityCheck *pSensorSanityChecks) | ||||
|         for (size_t i = 0; i < NUMBER_OF_SENSOR_SANITY_CHECKS; i++) | ||||
|         { | ||||
|             // Copy only the needed attributes | ||||
|             pSensorSanityChecks[i].status = sanityChecks[i].status; | ||||
|             pSensorSanityChecks[i].state = sanityChecks[i].state; | ||||
|             strcpy(pSensorSanityChecks[i].name, sanityChecks[i].name); | ||||
|         } | ||||
|         xSemaphoreGiveRecursive(xMutexAccessSafety); | ||||
|  | ||||
| @ -30,7 +30,7 @@ typedef struct _TemperatureSensorLimit | ||||
| } sTemperatureSensorLimit; | ||||
| typedef struct _SensorSanityCheck | ||||
| { | ||||
|     eSensorErrorState status; | ||||
|     eSensorErrorState state; | ||||
|     char name[MAX_ERROR_STRING_SIZE]; | ||||
|     sTemperatureSensorLimit sSensorLimit; | ||||
|     float fSensorTemperatureLast; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user