From 24b1986dec784add3b8e28b6e88ff3dbc768cdd6 Mon Sep 17 00:00:00 2001 From: Aleksander Belov Date: Thu, 29 Aug 2024 23:58:25 +0700 Subject: [PATCH] phases displayed across whole screen --- hot_fermentation.ino | 140 ++++++++++++++++++++++++++++--------------- 1 file changed, 91 insertions(+), 49 deletions(-) diff --git a/hot_fermentation.ino b/hot_fermentation.ino index 9a090e4..c5841e1 100644 --- a/hot_fermentation.ino +++ b/hot_fermentation.ino @@ -15,29 +15,30 @@ GyverOLED oled; // SSR pin configuration const int ssrPin = 7; -// Process phases (temperatures in Celsius and duration in minutes) +// Profile structure definition +struct Phase { + int temperature; + int duration; // in minutes +}; -// const int temperatures[] = {49, 51, 55, 45}; -// const int phaseDurations[] = {30, 30, 30, 30}; // Individual durations for each phase in minutes -// const int numPhases = 3; +struct Profile { + const char* name; + Phase phases[7]; // Maximum of 6 phases per profile + int numPhases; +}; +// Profiles definition +Profile profiles[] = { + {"Test", {{49, 1}, {51, 1}, {55, 1}, {45, 1}}, 4}, + {"Пшеница", {{47, 40}, {55, 40}, {65, 20}, {72, 20}, {85, 20}}, 5}, + {"Veggies Sous Vide", {{85, 120}}, 1}, + {"Profile 4", {{47, 120}, {53, 120}, {65, 150}, {72, 60}, {90, 105}, {50, 60}}, 6}, + {"Profile 5", {{55, 60}, {65, 120}, {72, 120}, {80, 120}, {90, 30}, {10, 100}}, 6} +}; -// const int temperatures[] = {47, 55, 65, 72, 85, 0}; -// const int phaseDurations[] = {20, 20, 20, 20, 20, 5}; // Individual durations for each phase in minutes -// const int numPhases = 5; - -// const int temperatures[] = {85, 50}; -// const int phaseDurations[] = {120, 120}; // Individual durations for each phase in minutes -// const int numPhases = 1; - -const int temperatures[] = {47, 53, 65, 72, 90, 50}; -const int phaseDurations[] = {120, 120, 150, 60, 105, 60}; // Individual durations for each phase in minutes -const int numPhases = 5; - -// const int temperatures[] = {55, 65, 72, 80, 90, 10}; -// const int phaseDurations[] = {60, 120, 120, 120, 30, 100}; // Individual durations for each phase in minutes -// const int numPhases = 5; - +// Select active profile (constant at this point) +const int activeProfileIndex = 1; // Index of the active profile, starting from 0 +Profile activeProfile = profiles[activeProfileIndex]; // PID Control variables double Setpoint, Input, Output; @@ -48,8 +49,13 @@ PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); unsigned long phaseStartTime; unsigned long totalStartTime; unsigned long ssrLastSwitchTime; +unsigned long totalElapsedTime; +unsigned long totalProcessTime; const int ssrSwitchInterval = 1000; // SSR switching interval in milliseconds +// Buffer for formatted time strings +char timeBuffer[10]; + void setup() { pinMode(ssrPin, OUTPUT); Serial.begin(9600); @@ -58,12 +64,11 @@ void setup() { oled.setScale(2); // Set text scale to 2 for better visibility oled.print("Starting..."); oled.update(); - delay(2000); - oled.setScale(0); // Set text scale to 2 for better visibility + oled.setScale(1); // Set text scale back to 1 for more detailed information // Begin the first phase phaseStartTime = totalStartTime = millis(); - Setpoint = temperatures[0]; + Setpoint = activeProfile.phases[0].temperature; myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(0, 1); // SSR is either ON or OFF digitalWrite(ssrPin, HIGH); // Start with heater on @@ -84,48 +89,85 @@ void loop() { } // Display time calculations - unsigned long totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds - unsigned long totalProcessTime = 0; - for (int i = 0; i < numPhases; i++) { - totalProcessTime += phaseDurations[i] * 60; + totalElapsedTime = (currentTime - totalStartTime) / 1000; // Total elapsed time in seconds + totalProcessTime = 0; + for (int i = 0; i < activeProfile.numPhases; i++) { + totalProcessTime += activeProfile.phases[i].duration * 60; } // Check if the phase duration is complete - if ((currentTime - phaseStartTime) / 1000 >= phaseDurations[currentPhase] * 60) { + if ((currentTime - phaseStartTime) / 1000 >= activeProfile.phases[currentPhase].duration * 60) { currentPhase++; - if (currentPhase >= numPhases) { + if (currentPhase >= activeProfile.numPhases) { oled.clear(); oled.print("Complete"); digitalWrite(ssrPin, LOW); // Turn off the heater return; // Stop further execution } phaseStartTime = currentTime; // Reset the start time for the new phase - Setpoint = temperatures[currentPhase]; + Setpoint = activeProfile.phases[currentPhase].temperature; } - // Display data on the OLED - oled.clear(); - oled.setCursor(0, 0); - oled.print(formatTime(totalElapsedTime)); - oled.print(" ("); - oled.print(formatTime(totalProcessTime)); - oled.print(")"); - oled.setCursor(0, 1); - oled.print(currentPhase + 1); - oled.print(". "); - oled.print((int)Input); - oled.print("C "); - oled.print((int)Setpoint); - oled.print("C "); - oled.print(formatTime((phaseDurations[currentPhase] * 60) - ((currentTime - phaseStartTime) / 1000))); + // Display all phases and highlight the current one + printPhases(currentPhase, currentTime - phaseStartTime); + oled.update(); delay(1000); // Update every second } -String formatTime(long seconds) { - long mins = seconds / 60; - int secs = seconds % 60; - return (mins < 10 ? "0" : "") + String(mins) + ":" + (secs < 10 ? "0" : "") + String(secs); +void printPhases(int currentPhase, unsigned long phaseElapsedTime) { + oled.clear(); + + oled.setCursor(0, 0); + oled.print(activeProfile.name); + // Display the totals and current state on the OLED + oled.setCursor(18, 1); + formatTime(totalElapsedTime, timeBuffer); + oled.print(timeBuffer); + oled.print(" / "); + formatTime(totalProcessTime, timeBuffer); + oled.print(timeBuffer); + + for (int i = 0; i < activeProfile.numPhases; i++) { + if (i == currentPhase) { + oled.invertText(true); // Invert text for the current phase + + oled.setCursor(0, i + 2); // Set cursor to the row corresponding to the phase + unsigned long timeRemaining = (activeProfile.phases[i].duration * 60) - (phaseElapsedTime / 1000); + formatTime(timeRemaining, timeBuffer); + oled.print(i + 1); + oled.print(". "); + oled.print((int)Input); + oled.print("C "); + oled.print((int)Setpoint); + oled.print("C "); + oled.print(timeBuffer); + } else { + oled.invertText(false); // Normal text for other phases + + oled.setCursor(0, i + 2); // Set cursor to the row corresponding to the phase + formatTime(activeProfile.phases[i].duration * 60, timeBuffer); + oled.print(i + 1); + oled.print(". "); + oled.print(activeProfile.phases[i].temperature); + oled.print("C "); + oled.print(timeBuffer); + } + } + + oled.invertText(false); // Ensure text inversion is off after the loop +} + +void formatTime(long seconds, char* buffer) { + long hours = seconds / 3600; + long mins = (seconds % 3600) / 60; + int secs = seconds % 60; + + if (hours > 0) { + sprintf(buffer, "%ld:%02ld:%02d", hours, mins, secs); + } else { + sprintf(buffer, "%ld:%02d", mins, secs); + } }