#include <U8g2lib.h>
#include <Wire.h>
#include <EEPROM.h>
// Objects
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); //for WOKWI OLED
//U8G2_SH1107_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, U8X8_PIN_NONE); //for real OLED
// Constants
const int maxSavedTimes = 3; // Maximum number of saved times
const int savedTimesX = 2; //X-Coordinate of Saved Times on Display
const int savedTimesY = 59; //Y-Coordinate of Saved Times on Display
const int switchPin = 2; //Digital pin for connecting brew switch
const int buttonUp = 4; //Digital pin fot button to increase extration time
const int buttonDown = 6; //Digital pin fot button to decrease extration time
const int relaisPin = 8; //Digital pin number used for relais
// Global variables
String savedTimes[maxSavedTimes]; //array to store last extraction times
int savedTimesCount = 0;
unsigned long startTime = 0;
boolean timing = false;
boolean displayChanged = true;
char buffer[10]; //buffer used to store extraction time in decimals plus "s"
int extractionTime;
int seconds; //used to store seconds
int deciSeconds; //used to store 1/10 seconds
bool cycle = false;
// Images
static const unsigned char image_ButtonDown_7x4_bits[] U8X8_PROGMEM = {0x7f, 0x3e, 0x1c, 0x08};
static const unsigned char image_Gaggia_logo_bits[] U8X8_PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xe0, 0x01, 0x00, 0xf8, 0x00, 0x00, 0x1f, 0xe0, 0x03, 0x80, 0x07, 0x00, 0x00, 0x80, 0x3f, 0x00, 0xf0, 0x01, 0x00, 0xfc, 0x00, 0x80, 0x1f, 0xe0, 0x03, 0x80, 0x07, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0xf0, 0x01, 0x00, 0xff, 0x00, 0xe0, 0x1f, 0xe0, 0x03, 0x80, 0x0f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0xf0, 0x01, 0x80, 0xff, 0x00, 0xf0, 0x1f, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf8, 0x03, 0x80, 0x7f, 0x00, 0xf8, 0x0f, 0xe0, 0x03, 0xc0, 0x0f, 0x00, 0x00, 0xf8, 0x03, 0x00, 0xf8, 0x03, 0xc0, 0x1f, 0x00, 0xfc, 0x03, 0xe0, 0x03, 0xc0, 0x1f, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xf8, 0x03, 0xe0, 0x0f, 0x00, 0xfc, 0x01, 0xe0, 0x03, 0xe0, 0x1f, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xf8, 0x07, 0xe0, 0x07, 0x00, 0xfe, 0x00, 0xe0, 0x03, 0xe0, 0x1f, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x07, 0xf0, 0x03, 0x00, 0x7e, 0x00, 0xe0, 0x03, 0xe0, 0x1f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xfc, 0x07, 0xf0, 0x01, 0x00, 0x3e, 0x00, 0xe0, 0x03, 0xe0, 0x3f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xfc, 0x07, 0xf0, 0x01, 0x00, 0x3f, 0x00, 0xe0, 0x03, 0xf0, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xfc, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0xe0, 0x03, 0xf0, 0x3f, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0xe0, 0x03, 0xf0, 0x3f, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xbe, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x00, 0xe0, 0x03, 0xf0, 0x7d, 0x00, 0x00, 0x1f, 0x78, 0x00, 0xbe, 0x0f, 0xf8, 0xe0, 0x03, 0x1f, 0x7c, 0xe0, 0x03, 0xf8, 0x7d, 0x00, 0x00, 0x1f, 0x78, 0x00, 0xbf, 0x1f, 0xf8, 0xe0, 0x03, 0x1f, 0x7c, 0xe0, 0x03, 0xf8, 0x7c, 0x00, 0x00, 0x1f, 0x78, 0x00, 0x1f, 0x1f, 0xf8, 0xe0, 0x03, 0x1f, 0x7c, 0xe0, 0x03, 0xf8, 0xfc, 0x00, 0x00, 0x1f, 0x78, 0x00, 0x1f, 0x1f, 0xf8, 0xe0, 0x03, 0x1f, 0x7c, 0xe0, 0x03, 0xfc, 0xf8, 0x00, 0x00, 0x3e, 0x78, 0x00, 0xff, 0x3f, 0xf8, 0xe1, 0x03, 0x1f, 0x7c, 0xe0, 0x03, 0xfc, 0xff, 0x00, 0x00, 0x3e, 0x78, 0x80, 0xff, 0x3f, 0xf0, 0xe1, 0x03, 0x3f, 0x7c, 0xe0, 0x03, 0xfc, 0xff, 0x00, 0x00, 0x7e, 0x78, 0x80, 0xff, 0x3f, 0xf0, 0xe3, 0x03, 0x3e, 0x7c, 0xe0, 0x03, 0xfc, 0xff, 0x01, 0x00, 0x7e, 0x78, 0x80, 0xff, 0x3f, 0xf0, 0xe3, 0x03, 0x7e, 0x7c, 0xe0, 0x03, 0xfe, 0xff, 0x01, 0x00, 0xfc, 0x78, 0x80, 0xff, 0x7f, 0xe0, 0xe7, 0x03, 0xfc, 0x7c, 0xe0, 0x03, 0xfe, 0xff, 0x01, 0x00, 0xfc, 0x7b, 0xc0, 0x0f, 0x7c, 0xe0, 0xef, 0x03, 0xfc, 0x7d, 0xe0, 0x03, 0x3e, 0xf0, 0x01, 0x00, 0xf8, 0x7f, 0xc0, 0x07, 0x7c, 0xc0, 0xff, 0x03, 0xf8, 0x7f, 0xe0, 0x03, 0x3e, 0xe0, 0x03, 0x00, 0xf0, 0x7f, 0xc0, 0x07, 0x7c, 0x80, 0xff, 0x03, 0xf0, 0x7f, 0xe0, 0x03, 0x3f, 0xe0, 0x03, 0x00, 0xe0, 0x7f, 0xe0, 0x07, 0xfc, 0x00, 0xff, 0x03, 0xf0, 0x7f, 0xe0, 0x03, 0x1f, 0xe0, 0x03, 0x00, 0xc0, 0x7f, 0xe0, 0x03, 0xf8, 0x00, 0xfe, 0x03, 0xc0, 0x7f, 0xe0, 0x03, 0x1f, 0xe0, 0x07, 0x00, 0x00, 0x7f, 0xe0, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0x80, 0x7f, 0xe0, 0x03, 0x1f, 0xc0, 0x07, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x83, 0xe3, 0x00, 0x0c, 0x18, 0x18, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x87, 0xe3, 0x00, 0x1c, 0x38, 0x18, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x87, 0xe3, 0x00, 0x1e, 0x78, 0x18, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x87, 0xe3, 0x00, 0x3e, 0xf8, 0x18, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x87, 0xe3, 0x00, 0x3e, 0xf8, 0x19, 0x07, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x87, 0xe3, 0x00, 0x77, 0xf8, 0x19, 0x07, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0xe3, 0x00, 0x77, 0xb8, 0x1b, 0x07, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x8e, 0xe3, 0x80, 0x7f, 0x38, 0x1f, 0x07, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x8e, 0xe3, 0x80, 0xff, 0x38, 0x1f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x8e, 0xe3, 0xc0, 0xff, 0x38, 0x1e, 0xde, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x8c, 0xe3, 0xcf, 0xc1, 0x39, 0x1c, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x63, 0x8c, 0xe3, 0xcf, 0xc0, 0x39, 0x18, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void setup() {
Serial.begin(9600);
Wire.begin();
u8g2.begin();
u8g2.setBitmapMode(1);
u8g2.clearBuffer(); //Clearing display
u8g2.drawXBMP(-1, 2, 128, 60, image_Gaggia_logo_bits); // Display the logo
u8g2.sendBuffer(); // Update the display
pinMode(switchPin, INPUT_PULLUP);
pinMode(buttonUp, INPUT_PULLUP);
pinMode(buttonDown, INPUT_PULLUP);
pinMode(relaisPin, OUTPUT);
extractionTime = EEPROM.read(0); //reading latest extraction times from EEPROM
delay(2500);
u8g2.clearBuffer();
u8g2.drawLine(21, 30, 108, 30);
u8g2.setFont(u8g2_font_logisoso16_tf);
u8g2.drawStr(27, 23, "hi cutie!");
u8g2.setFont(u8g2_font_helvR10_tf);
u8g2.setCursor(8, 56);
sprintf(buffer, "timer is set to %ds", extractionTime);
u8g2.print(buffer);
u8g2.sendBuffer();
}
void loop() {
//Reset extraction time when both buttons are pressed for 1s
if (digitalRead(buttonUp) == LOW && digitalRead(buttonDown) == LOW) {
delay(1000);
if (digitalRead(buttonUp) == LOW && digitalRead(buttonDown) == LOW) {
extractionTime = 27;
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_logisoso16_tf);
u8g2.drawStr(12, 40, "RESET TIMER");
u8g2.sendBuffer();
delay(500);
}
}
//Increase extration Time by 1s
if (digitalRead(buttonUp) == LOW && digitalRead(switchPin) == HIGH) {
extractionTime ++;
u8g2.clearBuffer();
u8g2.drawLine(32, 26, 97, 26);
u8g2.setFont(u8g2_font_logisoso16_tf);
u8g2.drawStr(42, 21, "TIMER");
u8g2.setCursor(52, 54);
sprintf(buffer, "%ds", extractionTime);
u8g2.print(buffer);
u8g2.sendBuffer();
delay(150);
}
//Decrease extration Time by 1s
if (digitalRead(buttonDown) == LOW && digitalRead(switchPin) == HIGH) {
extractionTime --;
u8g2.clearBuffer();
u8g2.drawLine(32, 26, 97, 26);
u8g2.setFont(u8g2_font_logisoso16_tf);
u8g2.drawStr(42, 21, "TIMER");
u8g2.setCursor(52, 54);
sprintf(buffer, "%ds", extractionTime);
u8g2.print(buffer);
u8g2.sendBuffer();
delay(150);
}
// Start timing when switch is closed
if (digitalRead(switchPin) == HIGH) {
cycle = false;
delay(20);
}
if (digitalRead(switchPin) == LOW && seconds < extractionTime && cycle == false) {
if (!timing) {
startTime = millis();
timing = true;
displayChanged = true; // Flag for display update
}
} else {
if (timing) {
timing = false;
if (seconds >= 8) {
saveTime(buffer); //Saves extraction time if its over 8s, this means short purges are not witten
EEPROM.write(0, extractionTime);
}
displayChanged = true; // Flag for display update
digitalWrite(relaisPin, LOW);
seconds = 0;
cycle = true;
delay(1000); // Delay after stopping the timer to show time
}
}
// Update the display when not timing and displayChanged flag is set
if (!timing && displayChanged) {
if (savedTimesCount > 0) {
u8g2.clearBuffer();
u8g2.drawLine(7, 26, 120, 26);
u8g2.drawXBMP(19, 32, 7, 4, image_ButtonDown_7x4_bits);
u8g2.setFont(u8g2_font_logisoso16_tf);
u8g2.drawStr(11, 21, "EXTRACTIONS");
for (int i = 0; i < savedTimesCount; i++) {
switch (i) {
case 0:
u8g2.setCursor(savedTimesX, savedTimesY);
u8g2.setFont(u8g2_font_logisoso16_tf);
break;
case 1:
u8g2.setCursor(savedTimesX + 51, savedTimesY);
u8g2.setFont(u8g2_font_helvR10_tr);
break;
case 2:
u8g2.setCursor(savedTimesX + 91, savedTimesY);
u8g2.setFont(u8g2_font_helvR10_tr);
break;
}
u8g2.print(savedTimes[savedTimesCount - 1 - i]);
}
u8g2.sendBuffer();
}
displayChanged = false;
} else if (timing) {
// Update the display with the current timing information
digitalWrite(relaisPin, HIGH);
unsigned long currentTime = millis() - startTime;
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_logisoso38_tr);
u8g2.setCursor(10, 50);
seconds = currentTime / 1000;
deciSeconds = currentTime % 1000 / 100;
if (seconds < 10) {
sprintf(buffer, "0%d.%ds", seconds, deciSeconds);// construct a string with the progress variable
} else {
sprintf(buffer, "%d.%ds", seconds, deciSeconds);// construct a string with the progress variable
}
u8g2.print(buffer); // display the string
u8g2.sendBuffer();
displayChanged = true; // Flag for display update
}
}
//Saving last 3 extractions times
void saveTime(char time[6]) {
if (savedTimesCount < maxSavedTimes) {
savedTimes[savedTimesCount] = time;
savedTimesCount++;
} else {
// Shift all saved times to make space for the new time
for (int i = 0; i < maxSavedTimes - 1; i++) {
savedTimes[i] = savedTimes[i + 1];
}
savedTimes[maxSavedTimes - 1] = time;
}
}