From 612ac1e159350a6aec9e11acf7952a019b68d0b5 Mon Sep 17 00:00:00 2001 From: Lorenz Uhlig <98092139+LoQue90@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:59:07 +0200 Subject: [PATCH] rework brew() clean up and less states removed brewOn and used bool brew() removed manualFlushOn and used bool manualFlush() --- src/brewHandler.h | 341 +++++++++++++++++++++++----------------------- src/main.cpp | 104 ++++++++------ 2 files changed, 227 insertions(+), 218 deletions(-) diff --git a/src/brewHandler.h b/src/brewHandler.h index 675f2ec76..c5e0de71d 100644 --- a/src/brewHandler.h +++ b/src/brewHandler.h @@ -5,6 +5,7 @@ * */ // TODO: +// FEATURE_BREWCONTROL has to be removed from userconfig, setup on website // clean up backflush // Flush Timer configurable and seperated from shottimer? // move brewPIDDisabled to kBrew? new fuction to set PID State based on mashine state switching? if kBrew -> disable PID/wait/BDPID or NORMALPID @@ -29,12 +30,9 @@ enum BrewSwitchState { enum BrewState { kBrewIdle = 10, kPreinfusion = 20, - kWaitPreinfusion = 21, kPreinfusionPause = 30, - kWaitPreinfusionPause = 31, kBrewRunning = 40, - kWaitBrew = 41, - kBrewFinished = 42, + kBrewFinished = 50, }; enum ManualFlushState { @@ -60,14 +58,30 @@ uint8_t brewSwitchReading = LOW; uint8_t currReadingBrewSwitch = LOW; boolean brewSwitchWasOff = false; -int brewOn = 0; // flag is set if brew was detected -int manualFlushOn = 0; // flag is set if manual flush is detected double totalBrewTime = 0; // total brewtime set in software double timeBrewed = 0; // total brewed time double lastBrewTimeMillis = 0; // for shottimer delay after brew is finished unsigned long startingTime = 0; // start time of brew boolean brewPIDDisabled = false; // is PID disabled for delay after brew has started? +// brew state as string for logging +const char* brewStateEnumToString(BrewState brewState) { + switch (brewState) { + case kBrewIdle: + return "Brew idle"; + case kPreinfusion: + return "Preinfusion running"; + case kPreinfusionPause: + return "Preinfusion pause running"; + case kBrewRunning: + return "Brew running"; + case kBrewFinished: + return "Brew finished"; + default: + return "Unknown"; + } +} + // Shot timer with or without scale #if FEATURE_SCALE == 1 boolean scaleCalibrationOn = 0; @@ -157,148 +171,42 @@ void checkbrewswitch() { } } -#if (FEATURE_BREWCONTROL == 0) /** - * @brief Brew timer + * @brief Brew process handeling including timer and state machine for brew-by-time and brew-by-weight + * @return true if brew is running, false otherwise */ -void brewTimer() { +bool brew() { unsigned long currentMillisTemp = millis(); checkbrewswitch(); + static BrewState lastBrewState = kBrewIdle; - // Start the timer when the brew switch is turned on - if (currBrewSwitchState == kBrewSwitchShortPressed && currBrewState == kBrewIdle) { - brewOn = 1; - startingTime = currentMillisTemp; - timeBrewed = 0; // reset timeBrewed, last brew is still stored - LOG(INFO, "Brew timer started"); - currBrewState = kBrewRunning; + // abort function for state machine from every state + if (currBrewSwitchState == kBrewSwitchIdle && currBrewState > kBrewIdle && currBrewState < kBrewFinished) { + if (currBrewState != kBrewFinished) { + LOG(INFO, "Brew stopped manually"); + } + currBrewState = kBrewFinished; } - - // Update the brewed time if the brew switch is still on - if (currBrewSwitchState == kBrewSwitchShortPressed && currBrewState == kBrewRunning) { + // calculated brew time while brew is running + if (currBrewState > kBrewIdle && currBrewState < kBrewFinished) { timeBrewed = currentMillisTemp - startingTime; } - // Stop the timer when the brew switch is turned off - if (currBrewSwitchState == kBrewSwitchIdle && currBrewState == kBrewRunning) { - brewOn = 0; - lastBrewTimeMillis = millis(); // time brew finished for shottimer delay - LOG(INFO, "Brew timer stopped"); - LOGF(INFO, "Shot time: %4.1f s", timeBrewed / 1000); - currBrewState = kBrewIdle; - } -} -#endif - -#if (FEATURE_BREWCONTROL == 1) -/** - * @brief Backflush - */ -void backflush() { - if (backflushState != kBackflushWaitBrewswitchOn && backflushOn == 0) { - backflushState = kBackflushWaitBrewswitchOff; // Force reset in case backflushOn is reset during backflush! - LOG(INFO, "Backflush: Disabled via Webinterface"); - } - else if (offlineMode == 1 || currBrewState > kBrewIdle || backflushCycles <= 0 || backflushOn == 0) { - return; - } - - if (bPID.GetMode() == 1) { // Deactivate PID - bPID.SetMode(0); - pidOutput = 0; - } - - heaterRelay.off(); // Stop heating - - checkbrewswitch(); - - if (currBrewSwitchState == kBrewSwitchIdle && backflushState != kBackflushWaitBrewswitchOn) { // Abort function for state machine from every state - backflushState = kBackflushWaitBrewswitchOff; - } - - // State machine for backflush - switch (backflushState) { - case kBackflushWaitBrewswitchOn: - if (currBrewSwitchState == kBrewSwitchShortPressed && backflushOn && machineState != kWaterEmpty) { - startingTime = millis(); - backflushState = kBackflushFillingStart; - } - - break; - - case kBackflushFillingStart: - LOG(INFO, "Backflush: Portafilter filling..."); - valveRelay.on(); - pumpRelay.on(); - backflushState = kBackflushFilling; - - break; - - case kBackflushFilling: - if (millis() - startingTime > (backflushFillTime * 1000)) { - startingTime = millis(); - backflushState = kBackflushFlushingStart; - } - - break; - - case kBackflushFlushingStart: - LOG(INFO, "Backflush: Flushing to drip tray..."); - valveRelay.off(); - pumpRelay.off(); - currBackflushCycles++; - backflushState = kBackflushFlushing; - - break; - - case kBackflushFlushing: - if (millis() - startingTime > (backflushFlushTime * 1000) && currBackflushCycles < backflushCycles) { - startingTime = millis(); - backflushState = kBackflushFillingStart; - } - else if (currBackflushCycles >= backflushCycles) { - backflushState = kBackflushWaitBrewswitchOff; - } - - break; - - case kBackflushWaitBrewswitchOff: - if (currBrewSwitchState == kBrewSwitchIdle) { - LOG(INFO, "Backflush: Finished!"); - valveRelay.off(); - pumpRelay.off(); - currBackflushCycles = 0; - backflushState = kBackflushWaitBrewswitchOn; - } - - break; - } -} - -/** - * @brief Time or weight based brew mode - */ -void brew() { - unsigned long currentMillisTemp = millis(); - checkbrewswitch(); - - if (currBrewSwitchState == kBrewSwitchIdle && currBrewState > kBrewIdle && currBrewState < kBrewFinished) { - // abort function for state machine from every state - LOG(INFO, "Brew stopped manually"); - currBrewState = kBrewFinished; + // Log output if currBrewState changed + if (currBrewState != lastBrewState) { + LOGF(INFO, "%s", brewStateEnumToString(currBrewState)); + lastBrewState = currBrewState; } +#if (FEATURE_BREWCONTROL == 1) // brew-by-time and brew-by-weight + // check if brewswitch was turned off after a brew; Brew only runs once even brewswitch is still pressed if (currBrewSwitchState == kBrewSwitchIdle) { - // check if brewswitch was turned off at least once, last time, brewSwitchWasOff = true; } - if (currBrewState > kBrewIdle && currBrewState < kBrewFinished) { - timeBrewed = currentMillisTemp - startingTime; - } - + // set brew time every cycle, in case changes are done during brew if (brewTime > 0) { - totalBrewTime = (preinfusion * 1000) + (preinfusionPause * 1000) + (brewTime * 1000); // running every cycle, in case changes are done during brew + totalBrewTime = (preinfusion * 1000) + (preinfusionPause * 1000) + (brewTime * 1000); } else { // Stop by time deactivated --> brewTime = 0 @@ -307,66 +215,40 @@ void brew() { // state machine for brew switch (currBrewState) { - case kBrewIdle: // waiting step for brew switch turning on - if (currBrewSwitchState == kBrewSwitchShortPressed && backflushState == 10 && backflushOn == 0 && brewSwitchWasOff && machineState != kWaterEmpty) { + case kBrewIdle: // waiting step for brew switch turning on + if (currBrewSwitchState == kBrewSwitchShortPressed && brewSwitchWasOff && backflushOn == 0 && machineState != kWaterEmpty && machineState != kBackflush) { startingTime = millis(); - timeBrewed = 0; + timeBrewed = 0; // reset timeBrewed, last brew is still stored LOG(INFO, "Brew started"); - if (preinfusionPause == 0 || preinfusion == 0) { - brewOn = 1; - currBrewState = kBrewRunning; - } - else { - brewOn = 1; - currBrewState = kPreinfusion; - } - } - else { - backflush(); + currBrewState = (preinfusion > 0) ? kPreinfusion : kBrewRunning; } break; - case kPreinfusion: // preinfusioon + case kPreinfusion: valveRelay.on(); pumpRelay.on(); - LOG(INFO, "Preinfusion"); - currBrewState = kWaitPreinfusion; - - break; - case kWaitPreinfusion: // waiting time preinfusion if (timeBrewed > (preinfusion * 1000)) { currBrewState = kPreinfusionPause; } break; - case kPreinfusionPause: // preinfusion pause + case kPreinfusionPause: valveRelay.on(); pumpRelay.off(); - LOG(INFO, "Preinfusion pause"); - currBrewState = kWaitPreinfusionPause; - break; - - case kWaitPreinfusionPause: // waiting time preinfusion pause - if (timeBrewed > ((preinfusion * 1000) + (preinfusionPause * 1000))) { - currBrewState = kBrewRunning; + if (timeBrewed > ((preinfusion + preinfusionPause) * 1000)) { + currBrewState = kBrewRunning; // Move to brewing state } break; - case kBrewRunning: // brew running + case kBrewRunning: valveRelay.on(); pumpRelay.on(); - LOG(INFO, "Brew running"); - currBrewState = kWaitBrew; - - break; - - case kWaitBrew: // waiting time or weight brew // stop brew if target-time is reached --> No stop if stop by time is deactivated via Parameter (0) if ((timeBrewed > totalBrewTime) && ((brewTime > 0))) { @@ -383,25 +265,56 @@ void brew() { break; - case kBrewFinished: // brew finished + case kBrewFinished: valveRelay.off(); pumpRelay.off(); - brewOn = 0; currentMillisTemp = 0; lastBrewTimeMillis = millis(); // time brew finished for shottimer delay brewSwitchWasOff = false; - LOG(INFO, "Brew finished"); LOGF(INFO, "Shot time: %4.1f s", timeBrewed / 1000); currBrewState = kBrewIdle; break; } +#else // FEATURE_BREWCONTROL == 0, only brew time + + switch (currBrewState) { + case kBrewIdle: // waiting step for brew switch turning on + if (currBrewSwitchState == kBrewSwitchShortPressed && machineState != kWaterEmpty) { + startingTime = millis(); + timeBrewed = 0; // reset timeBrewed, last brew is still stored + LOG(INFO, "Brew timer started"); + currBrewState = kBrewRunning; + } + + break; + + case kBrewRunning: + if (currBrewSwitchState == kBrewSwitchIdle && currBrewState == kBrewRunning) { + currBrewState = kBrewFinished; + } + + break; + + case kBrewFinished: + currentMillisTemp = 0; + lastBrewTimeMillis = millis(); // time brew finished for shottimer delay + LOGF(INFO, "Shot time: %4.1f s", timeBrewed / 1000); + currBrewState = kBrewIdle; + + break; + } +#endif + + return (currBrewState != kBrewIdle && currBrewState != kBrewFinished); } +#if (FEATURE_BREWCONTROL == 1) /** * @brief manual grouphead flush + * @return true if manual flush is running, false otherwise */ -void manualFlush() { +bool manualFlush() { unsigned long currentMillisTemp = millis(); checkbrewswitch(); if (currManualFlushState == kManualFlushRunning) { @@ -414,7 +327,6 @@ void manualFlush() { startingTime = millis(); valveRelay.on(); pumpRelay.on(); - manualFlushOn = 1; LOG(INFO, "Manual flush started"); currManualFlushState = kManualFlushRunning; } @@ -424,13 +336,96 @@ void manualFlush() { if (currBrewSwitchState != kBrewSwitchLongPressed) { valveRelay.off(); pumpRelay.off(); - manualFlushOn = 0; LOG(INFO, "Manual flush stopped"); LOGF(INFO, "Manual flush time: %4.1f s", timeBrewed / 1000); currManualFlushState = kManualFlushIdle; } break; } + return (currManualFlushState == kManualFlushRunning); } +/** + * @brief Backflush + */ +void backflush() { + if (backflushState != kBackflushWaitBrewswitchOn && backflushOn == 0) { + backflushState = kBackflushWaitBrewswitchOff; // Force reset in case backflushOn is reset during backflush! + LOG(INFO, "Backflush: Disabled via Webinterface"); + } + else if (offlineMode == 1 || currBrewState > kBrewIdle || backflushCycles <= 0 || backflushOn == 0) { + return; + } + + if (bPID.GetMode() == 1) { // Deactivate PID + bPID.SetMode(0); + pidOutput = 0; + } + + heaterRelay.off(); // Stop heating + + checkbrewswitch(); + + if (currBrewSwitchState == kBrewSwitchIdle && backflushState != kBackflushWaitBrewswitchOn) { // Abort function for state machine from every state + backflushState = kBackflushWaitBrewswitchOff; + } + + // State machine for backflush + switch (backflushState) { + case kBackflushWaitBrewswitchOn: + if (currBrewSwitchState == kBrewSwitchShortPressed && backflushOn && machineState != kWaterEmpty) { + startingTime = millis(); + backflushState = kBackflushFillingStart; + } + + break; + + case kBackflushFillingStart: + LOG(INFO, "Backflush: Portafilter filling..."); + valveRelay.on(); + pumpRelay.on(); + backflushState = kBackflushFilling; + + break; + + case kBackflushFilling: + if (millis() - startingTime > (backflushFillTime * 1000)) { + startingTime = millis(); + backflushState = kBackflushFlushingStart; + } + + break; + + case kBackflushFlushingStart: + LOG(INFO, "Backflush: Flushing to drip tray..."); + valveRelay.off(); + pumpRelay.off(); + currBackflushCycles++; + backflushState = kBackflushFlushing; + + break; + + case kBackflushFlushing: + if (millis() - startingTime > (backflushFlushTime * 1000) && currBackflushCycles < backflushCycles) { + startingTime = millis(); + backflushState = kBackflushFillingStart; + } + else if (currBackflushCycles >= backflushCycles) { + backflushState = kBackflushWaitBrewswitchOff; + } + + break; + + case kBackflushWaitBrewswitchOff: + if (currBrewSwitchState == kBrewSwitchIdle) { + LOG(INFO, "Backflush: Finished!"); + valveRelay.off(); + pumpRelay.off(); + currBackflushCycles = 0; + backflushState = kBackflushWaitBrewswitchOn; + } + + break; + } +} #endif diff --git a/src/main.cpp b/src/main.cpp index c8cfaa672..7395c014a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -553,23 +553,24 @@ void handleMachineState() { break; case kPidNormal: - - if (brewOn == 1) { +#if (FEATURE_BREWSWITCH == 1) + if (brew()) { machineState = kBrew; if (standbyModeOn) { resetStandbyTimer(); } } - - if (manualFlushOn == 1) { +#endif +#if (FEATURE_BREWCONTROL == 1) + if (manualFlush()) { machineState = kManualFlush; if (standbyModeOn) { resetStandbyTimer(); } } - +#endif if (steamON == 1) { machineState = kSteam; @@ -608,10 +609,10 @@ void handleMachineState() { } break; - +#if (FEATURE_BREWSWITCH == 1) case kBrew: - if (brewOn == 0) { + if (!brew()) { machineState = kPidNormal; } @@ -631,10 +632,11 @@ void handleMachineState() { machineState = kSensorError; } break; - +#endif +#if (FEATURE_BREWCONTROL == 1) case kManualFlush: - if (manualFlushOn == 0) { + if (!manualFlush()) { machineState = kPidNormal; } @@ -654,7 +656,7 @@ void handleMachineState() { machineState = kSensorError; } break; - +#endif case kSteam: if (steamON == 0) { machineState = kPidNormal; @@ -664,7 +666,7 @@ void handleMachineState() { machineState = kEmergencyStop; } - if (backflushOn || backflushState > kBackflushWaitBrewswitchOn) { + if (backflushOn || backflushState > kBackflushWaitBrewswitchOn) { // if this is possible, any other state change (brew, flush.etc should be possible) machineState = kBackflush; } @@ -680,8 +682,9 @@ void handleMachineState() { machineState = kSensorError; } break; - +#if (FEATURE_BREWCONTROL == 1) case kBackflush: + backflush(); if (backflushOn == 0) { machineState = kPidNormal; } @@ -702,7 +705,7 @@ void handleMachineState() { machineState = kSensorError; } break; - +#endif case kEmergencyStop: if (!emergencyStop) { machineState = kPidNormal; @@ -754,44 +757,59 @@ void handleMachineState() { #endif } - if (pidON || steamON || brewOn || manualFlushOn) { + if (pidON) { pidON = 1; resetStandbyTimer(); #if OLED_DISPLAY != 0 u8g2.setPowerSave(0); #endif + machineState = kPidNormal; + } + if (steamON) { + pidON = 1; + resetStandbyTimer(); +#if OLED_DISPLAY != 0 + u8g2.setPowerSave(0); +#endif + machineState = kSteam; + } - if (steamON) { - machineState = kSteam; - } - else if (brewOn) { - machineState = kBrew; - } - else if (manualFlushOn) { - machineState = kManualFlush; - } - else { - machineState = kPidNormal; +#if (FEATURE_BREWSWITCH == 1) + if (brew()) { + pidON = 1; + resetStandbyTimer(); +#if OLED_DISPLAY != 0 + u8g2.setPowerSave(0); +#endif +#endif +#if (FEATURE_BREWCONTROL == 1) + if (manualFlush()) { + pidON = 1; + resetStandbyTimer(); +#if OLED_DISPLAY != 0 + u8g2.setPowerSave(0); +#endif } - } +#endif - if (tempSensor->hasError()) { - machineState = kSensorError; - } - break; + if (tempSensor->hasError()) { + machineState = kSensorError; + } + break; - case kSensorError: - machineState = kSensorError; - break; + case kSensorError: + machineState = kSensorError; + break; - case kEepromError: - machineState = kEepromError; - break; - } + case kEepromError: + machineState = kEepromError; + break; + } - if (machineState != lastmachinestate) { - printMachineState(); - lastmachinestate = machineState; + if (machineState != lastmachinestate) { + printMachineState(); + lastmachinestate = machineState; + } } } @@ -1575,7 +1593,7 @@ void looppid() { LOGF(TRACE, "Current PID Output: %f", pidOutput); LOGF(TRACE, "Current Machinestate: %s", machinestateEnumToString(machineState)); LOGF(TRACE, "timeBrewed %f", timeBrewed); - LOGF(TRACE, "Brew detected %i", brewOn); + LOGF(TRACE, "Brew detected %i", brew()); } } @@ -1584,10 +1602,6 @@ void looppid() { shottimerscale(); // Calculation of weight of shot while brew is running #endif -#if (FEATURE_BREWSWITCH == 1 && FEATURE_BREWCONTROL == 0) - brewTimer(); -#endif - #if (FEATURE_BREWSWITCH == 1 && FEATURE_BREWCONTROL == 1) brew(); manualFlush();