diff --git a/Pinouts/D1-mini-pinout.png b/Pinouts/D1-mini-pinout.png new file mode 100644 index 0000000..4bca4a3 Binary files /dev/null and b/Pinouts/D1-mini-pinout.png differ diff --git a/Pinouts/LCD and buttons interface.jpg b/Pinouts/LCD and buttons interface.jpg new file mode 100644 index 0000000..15cd0b6 Binary files /dev/null and b/Pinouts/LCD and buttons interface.jpg differ diff --git a/Pinouts/Machine Pinout.jpg b/Pinouts/Machine Pinout.jpg new file mode 100644 index 0000000..0ef5cb7 Binary files /dev/null and b/Pinouts/Machine Pinout.jpg differ diff --git a/Pinouts/config.coffee b/Pinouts/config.coffee new file mode 100644 index 0000000..4e6732e --- /dev/null +++ b/Pinouts/config.coffee @@ -0,0 +1,31 @@ +generalConfig = + serialDevice: '/dev/coffee' + logFilename: 'coffee.log' + tempTimeout: 50 + pumpCoefficient: 1.35 + +hardwareConfig = + coffeeTemp: 0.758 + coffeeTemp2: 0.758 + 0.1 + + grinderPin: 9 + pumpPin: 8 + boilerPin: 6 + powderPin: 7 + wheelPin: 10 + invertWheelPin: 11 + + powderSensorPin: 2 + vaporSensorPin: 5 + tempSensorPin: 7 + + wheelStartSensorPin: 4 + wheelEndSensorPin: 3 + +accountingConfig = + coffeePrice: 20 + +exports.general = generalConfig +exports.hardware = hardwareConfig +exports.accounting = accountingConfig + diff --git a/Pinouts/lcd_pinout.jpg b/Pinouts/lcd_pinout.jpg new file mode 100644 index 0000000..f2379b4 Binary files /dev/null and b/Pinouts/lcd_pinout.jpg differ diff --git a/Pinouts/pinoutLCD.png b/Pinouts/pinoutLCD.png new file mode 100644 index 0000000..26b94cb Binary files /dev/null and b/Pinouts/pinoutLCD.png differ diff --git a/PyCoffeeESP8266/PyCoffeeESP8266.ino b/PyCoffeeESP8266/PyCoffeeESP8266.ino new file mode 100644 index 0000000..513f3b3 --- /dev/null +++ b/PyCoffeeESP8266/PyCoffeeESP8266.ino @@ -0,0 +1,420 @@ +#include +#include +#include +#include +#include +#include +#include + +AsyncWebServer server(80); + +// This next variable is used to get current "time" in ms and break out of while cycles that need a time limit safeguard +unsigned long startTime; + +// WiFi settings +const char* ssid = "LILiK_WiFi"; //replace with your SSID +const char* password = "pippopippo"; //password +//const char* ssid = "AulaStud"; //replace with your SSID +//const char* password = "cinimerda"; //password +String hostname = "PyCoffee"; + +// string to store coffee style from HTML +String input_field = "espr"; + + +// HTML WEB interface +const char index_html[] PROGMEM = R"rawliteral( + + PyCoffee HTML interface + + + + + + Ciao! Sono la macchina del caffe' della 117bis!
+ Seleziona il tipo di caffe' e conferma

+ +
+

+ +
+

+ + Clicca qui sotto per aggiornare il firmware:
+ ⬆️ OTA Firmware_Update ⬆️

+ Codice sorgente (su LILiK projects):
+ ☕Gitea☕

+ +)rawliteral"; + +// input parameter for html server +const char* input_paramter1 = "coffee_input"; + +// enable http coffee making on server request +int httpCoffee = 0; + +// button pins +const int sel = 0, enter = 2; + +// Global string +String readString; + +// coffee type variable +String type = "Espresso"; + +// Support string to store stuff to be sent over serial +String serialOUTbuffer = "none"; + +// Variables to store lines to be printed on LCD: +String line1 = ""; +String line2 = ""; + +// LCD pins <--> ESP8266 LOLIN D1 pins +const int e_RS = 4, e_EN = 5, e_D6 = 12, e_D7 = 13, e_D5 = 14, e_D8 = 15; +LiquidCrystal lcd(e_RS, e_EN, e_D6, e_D7, e_D5, e_D8); + +// Custom character matrix (coffee cup left side) +byte cupL[8] = {0b00001,0b00010,0b00010,0b00001,0b00001,0b00000,0b00111,0b00100}; +// Custom character matrix (coffee cup center) +byte cupC[8] = {0b00100,0b00101,0b01001,0b01000,0b00100,0b00000,0b11111,0b00000}; +// Custom character matrix (coffee cup right side) +byte cupR[8] = {0b10000,0b00000,0b00000,0b10000,0b10000,0b00000,0b11000,0b01110}; +// Custom character matrix (coffee cup left side line 2) +byte cupL1[8] = {0b00100,0b00100,0b00100,0b00010,0b01111,0b01000,0b00111,0b00000}; +// Custom character matrix (coffee cup center line 2) +byte cupC1[8] = {0b00000,0b00000,0b00000,0b00000,0b11111,0b00000,0b11111,0b00000}; +// Custom character matrix (coffee cup right side line 2) +byte cupR1[8] = {0b01010,0b01010,0b01110,0b10000,0b11100,0b00100,0b11000,0b00000}; + +void notFound(AsyncWebServerRequest *request) { + request->send(404, "text/plain", "Not found"); +} + +//_____________________________________________________________________________ + +// the setup function runs once when you press reset or power the board +void setup(void) { + + // Set buttons as inputs with internal pull-ups + pinMode(enter, INPUT_PULLUP); + pinMode(sel, INPUT_PULLUP); + + // initialize serial: + Serial.begin(9600); + + // Make custom characters available to LCD to paint a cute coffee cup + lcd.createChar(0, cupL); + lcd.createChar(1, cupC); + lcd.createChar(2, cupR); + lcd.createChar(3, cupL1); + lcd.createChar(4, cupC1); + lcd.createChar(5, cupR1); + lcd.begin(16, 2); // set up number of columns and rows + lcd.clear(); // Clear LCD + + // Show boot animation on LCD + bootAnimation(); + + WiFi.mode(WIFI_STA); + // WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(hostname.c_str()); //define hostname + WiFi.begin(ssid, password); + + connectedTo(); + + // Send web page with input fields to client + server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "text/html", index_html); + }); + + // Get data from menu + server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) { + if (request->hasParam(input_paramter1)) { + type = request->getParam(input_paramter1)->value(); + httpCoffee = 1; + } + request->send_P(200, "text/html", index_html); // Re-send main page, with data! + }); + + // in case of error: + server.onNotFound(notFound); + AsyncElegantOTA.begin(&server); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + // Print selection screen + line1 = "Selection"; + line2 = type; + LCDprint(); + // tell the Arduino we're ready + serialOUTbuffer = "read"; + delay(100); + writeSerial(); +} + +//_____________________________________________________________________________ + +void loop() { +// the loop function runs over and over again forever + delay(10); + + // select type of brew by pressing the sel button + if (digitalRead(sel) == LOW && type == "Espresso") { + type = "Lungo"; + line1 = "Selection"; + line2 = type; + LCDprint(); + delay(500); + } + else if (digitalRead(sel) == LOW && type == "Lungo") { + type = "Ristretto"; + line1 = "Selection"; + line2 = type; + LCDprint(); + delay(500); + } + else if (digitalRead(sel) == LOW && type == "Ristretto") { + type = "Espresso"; + line1 = "Selection"; + line2 = type; + LCDprint(); + delay(500); + } + + // check if data has been sent on serial from Arduino, + // send commands to arduino and display corresponding messages on LCD + // this is the main function dedicated to making coffee and reporting errors. + serialCoffeeCommandLCDInterface(); +} + + +//_____________________________________________________________________________ + +// this is how we read the input +void serialRead() { + while (Serial.available()) { + delay(1); + if (Serial.available() > 0) { + char c = Serial.read(); + readString += c;} + } +} + +//_____________________________________________________________________________ + +void bootAnimation() { + + delay(1000); + line1 = "ESP_Coffee"; + line2 = "Beta 1"; + LCDprint(); + delay(1000); + lcd.setCursor(12,0); //print coffee cup top using uint8 method + lcd.write((uint8_t)0); + lcd.write((uint8_t)1); + lcd.write((uint8_t)2); + lcd.setCursor(12,1); //print coffee cup bottom using uint8 method + lcd.write((uint8_t)3); + lcd.write((uint8_t)4); + lcd.write((uint8_t)5); + delay(2000); +} + +//_____________________________________________________________________________ + +void connectedTo() { + + startTime = millis(); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + if (millis() - startTime > 60000) { + Serial.println("WiFi connection timeout"); + line1 = "Timeout at SSID"; + line2 = ssid; + LCDprint(); + break; + } + delay(10000); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); //You can get IP address assigned to ESP + + line1 = "SSID"; + line2 = ssid; + LCDprint(); + delay(2000); + + line1 = "Connected to IP:"; + line2 = ""; + LCDprint(); + lcd.setCursor(0, 1); // move cursor to (0, 0) + lcd.print(WiFi.localIP()); // re-print line2 or IP won't print + delay(2000); +} + +//_____________________________________________________________________________ + +void LCDprint() { + lcd.clear(); + lcd.setCursor(0, 0); // move cursor to (0, 0) + lcd.print(line1); // print line1 + lcd.setCursor(0, 1); // move cursor to (0, 0) + lcd.print(line2); // print line2 +} + +//_____________________________________________________________________________ + +void writeSerial() { + Serial.println(serialOUTbuffer); +} + +//_____________________________________________________________________________ + +void serialCoffeeCommandLCDInterface() { + if (digitalRead(enter) == LOW or httpCoffee == 1) { + httpCoffee = 0; + if (type == "Espresso") { + serialOUTbuffer = "espr"; + } + else if (type == "Lungo") { + serialOUTbuffer = "long"; + } + else if (type == "Ristretto") { + serialOUTbuffer = "rist"; + } + writeSerial(); + delay(500); + serialOUTbuffer = "make"; + writeSerial(); + } + if (Serial.available() > 0) { + // read the incoming data: (we only care about the first few characters, I've chosen 4) + readString = ""; + serialRead(); + String incomingData = readString.substring(0,4); + Serial.print(incomingData); + Serial.print("\n"); + + if (incomingData == "Maki") { + // Display making coffee message + line1 = "Making"; + line2 = type; + LCDprint(); + + lcd.setCursor(12,0); //print coffee cup top using uint8 method + lcd.write((uint8_t)0); + lcd.write((uint8_t)1); + lcd.write((uint8_t)2); + lcd.setCursor(12,1); //print coffee cup bottom using uint8 method + lcd.write((uint8_t)3); + lcd.write((uint8_t)4); + lcd.write((uint8_t)5); + + } + + if (incomingData == "u-Th") { + Serial.print("Thermocouple: unplugged or failed\n"); + while (true) { + // Unrecoverable error has occurred during heating, lock the machine + line1 = "ThermoCouple err"; + line2 = "Unplugged/failed"; + LCDprint(); + delay(10000); + } + } + if (incomingData == "p-Th") { + Serial.print("Thermocouple: positioning or relay fault\n"); + while (true) { + // Unrecoverable error has occurred during heating, lock the machine + line1 = "ThermoCouple err"; + line2 = "Fallen/relayFail"; + LCDprint(); + delay(10000); + } + } + if (incomingData == "Erro") { + Serial.print("Unrecoverable error in Arduino subsystem. Please restart\n"); + while (true) { + // Unrecoverable error has occurred during heating, lock the machine + line1 = "Enrecoverable"; + line2 = "Error. Restart."; + LCDprint(); + delay(10000); + } + } + if (incomingData == "h-ta") { + Serial.print("took too long to warm boiler, this is just a warning. Everything should be fine\n"); + line1 = "Heating too long"; + line2 = "Continuing..."; + LCDprint(); + } + if (incomingData == "p-en") { + Serial.print("Unable to Press. Please restart\n"); + while (true) { + // Unrecoverable error has occurred while pressing, lock the machine + line1 = "Press failed"; + line2 = "Error. Restart."; + LCDprint(); + delay(10000); + } + } + if (incomingData == "u-en") { + Serial.print("Unable to unPress. Please restart\n"); + while (true) { + // Unrecoverable error has occurred while unpressing, lock the machine + line1 = "unPress failed"; + line2 = "Error. Restart."; + LCDprint(); + delay(10000); + } + } + if (incomingData == "refi") { + Serial.print("refill coffee and send cont command\n"); + line1 = "Refill Coffee"; + line2 = "then tap make"; + LCDprint(); + while (true) { + delay(10); + if (digitalRead(enter) == LOW) { + line1 = "Refilled"; + line2 = "continuing"; + LCDprint(); + serialOUTbuffer = "cont"; + writeSerial(); + break; + } + } + } + if (incomingData == "g-fa") { + Serial.print("g-failure: second grinding failure, check grinder!\n"); + while (true) { + // Unrecoverable error has occurred during grinding, lock the machine + line1 = "Grinding failed"; + line2 = "Check Machine"; + LCDprint(); + delay(10000); + } + } + if (incomingData == "Comp") { + Serial.print("Made coffee\n"); + line1 = "Coffee Done :)"; + line2 = "Enjoy!"; + LCDprint(); + delay(5000); + line1 = "Selection"; + line2 = type; + LCDprint(); + delay(500); + } + } +} diff --git a/PyCoffeeESP8266/PyCoffeeESP8266.ino.d1_mini.bin b/PyCoffeeESP8266/PyCoffeeESP8266.ino.d1_mini.bin new file mode 100644 index 0000000..69fbfd5 Binary files /dev/null and b/PyCoffeeESP8266/PyCoffeeESP8266.ino.d1_mini.bin differ diff --git a/PyCoffeeNano/PyCoffeeNano.ino b/PyCoffeeNano/PyCoffeeNano.ino new file mode 100644 index 0000000..f3849a9 --- /dev/null +++ b/PyCoffeeNano/PyCoffeeNano.ino @@ -0,0 +1,443 @@ +// Pinout configuration +const int grinderPin = 9, pumpPin = 8, boilerPin = 6, powderPin = 7, wheelPin = 10, invertWheelPin = 11, powderSensorPin = 2, vaporSensorPin = 5, tempSensorPin = A7, wheelStartSensorPin = 4, wheelEndSensorPin = 3, redLED = 13, greenLED = 12; + +// Global string +String readString; + +// Thermistor config +// WARNING! while the old coffee machine used a PTC thermistor, this was replaced with an NTC one as it was more readily available +// Code must be adjusted accordingly if a PTC resistor is used once more! +int Vo; +float R1 = 10000; // <-- change this value to the resistance of the fixed resistor (so don't change PLS!) +float logR2, R2, T, Tc, Told; +float c1 = 7.9e-04, c2 = 1.85e-04, c3 = 2e-07; // Here's where you can perform actual calibration + +// Variable to store desired Max boiler Temp +int desiredTemp = 70; + +// Variables to Store errors: +int unrecoverableErr = 0; +int warning = 0; + +// Variables for cleaning and other maintenance +int dry = 0; +int noCoffee = 0; + +// Milliseconds to delay between each cycle +const int milliseconds = 10; +int timeratio = 1; +// pumpRatio is = seconds to pump water for and will be updated over serial +int pumpRatio = 15; +// This next variable is used to get current "time" in ms and break out of while cycles that need a time limit safeguard +unsigned long startTime; + +void setup() { + // put your setup code here, to run once: + // first we set pins as I/O and initialize outputs LOW + pinMode(boilerPin, OUTPUT); pinMode(pumpPin, OUTPUT); pinMode(grinderPin, OUTPUT); pinMode(powderPin, OUTPUT); pinMode(wheelPin, OUTPUT); pinMode(invertWheelPin, OUTPUT); pinMode (redLED, OUTPUT); pinMode (greenLED, OUTPUT); + pinMode(powderSensorPin, INPUT); pinMode(vaporSensorPin, INPUT); pinMode(tempSensorPin, INPUT); pinMode(wheelStartSensorPin, INPUT); pinMode(wheelEndSensorPin, INPUT); + digitalWrite(grinderPin, LOW); digitalWrite(pumpPin, LOW); digitalWrite(boilerPin, LOW); digitalWrite(powderPin, LOW); digitalWrite(wheelPin, LOW); digitalWrite(invertWheelPin, LOW); digitalWrite(redLED, LOW); digitalWrite(greenLED, LOW); + // timeratio easily allows to determine how many cycles are required to make 1s pass (ms * ratio = 1s) + timeratio = 1000/milliseconds; + // initialize serial: + Serial.begin(9600); + delay(100); + Serial.write("Arduino running :)\n"); +} + +void loop() { + // put your main code here, to run repeatedly: + + // Check if unrecoverable error has occurred: + if (unrecoverableErr == 1) { + delay(100); + Serial.write("Error has occurred.\n"); delay(100); Serial.write("Check machine and restart\n"); + digitalWrite(greenLED, LOW); + while (true){ + digitalWrite(redLED, HIGH); + delay(1000); + digitalWrite(redLED, LOW); + delay(1000); + } + } + + // check if data has been sent on serial from ESP or PC: + if (Serial.available() > 0) { + // read the incoming data: (we only care about the first few characters, I've chosen 4) + readString = ""; + serialRead(); + String incomingData = readString.substring(0,4); + + if (incomingData == "read") { + digitalWrite(greenLED, HIGH); + } + + if (incomingData == "rist") { + // set parameters for ristretto: + delay(100); + Serial.write("Ristretto\n"); + pumpRatio = 12; + } + + if (incomingData == "espr") { + // set parameters for espresso: + delay(100); + Serial.write("Espresso\n"); + pumpRatio = 15; + } + + if (incomingData == "long") { + // set parameters for lungo: + delay(100); + Serial.write("Lungo\n"); + pumpRatio = 18; + } + + // check if the incoming data is "make": + if (incomingData == "make") { + // run the code to make coffee: + delay(100); + Serial.write("Making some coffee!\n"); + makeCoffee(); + } + + if (incomingData == "dryr") { + // run the code to make a dry run (no powder, no water): + delay(100); + Serial.write("DryRun\n"); + dry = 1; + makeCoffee(); + } + + if (incomingData == "noco") { + // run the code to make a dry run (no powder, nor water): + delay(100); + Serial.write("NoCo\n"); + pumpRatio = 12; + noCoffee = 1; + makeCoffee(); + } + + if (incomingData == "pump") { + // run the code to just pump water: + pumpRatio = 12; + Pump(); + } + + if (incomingData == "pres") { + // only press + Press(); + } + + if (incomingData == "unpr") { + // only unpress + unPress(); + } + + if (incomingData == "heat") { + // only heat + desiredTemp = 85; + Heat(); + } + + if (incomingData == "clea") { + // clean machine + delay(100); + Serial.write("s-clean\n"); + dry = 1; + makeCoffee(); + noCoffee = 1; + makeCoffee(); + delay(100); + Serial.write("S-cleaning done.\n"); + } + } + delay(milliseconds); +} + + +// this is how we read the input +void serialRead() { + while (Serial.available()) { + delay(10); + if (Serial.available() > 0) { + char c = Serial.read(); + readString += c;} + } +} + +void Grind() { + digitalWrite(greenLED, LOW); + delay(100); + Serial.write("grinding...\n"); + digitalWrite(grinderPin, HIGH); + startTime = millis(); + while (true) { + delay(milliseconds); + if (digitalRead(powderSensorPin) == HIGH) { + digitalWrite(grinderPin, LOW); + delay(100); + Serial.write("Grinding Done\n"); + break; + } + if (millis() - startTime > 30000) { + delay(100); + Serial.write("Warning, grinding took too long!\n"); + delay(100); + Serial.write("Out of Coffee?\n"); + warning = 1; + break; + } + } + digitalWrite(greenLED, HIGH); +} + +void Drop() { + digitalWrite(greenLED, LOW); + delay(100); + Serial.write("dropping...\n"); + digitalWrite(powderPin, HIGH); + delay(1000); + digitalWrite(powderPin, LOW); + delay(100); + Serial.write("Dropped\n"); + digitalWrite(greenLED, HIGH); +} + +void Heat() { + digitalWrite(greenLED, LOW); + digitalWrite(redLED, HIGH); + startTime = millis(); + delay(100); + Serial.write("Heating to "); + delay(100); + Serial.print(desiredTemp); + delay(100); + Serial.write(" C\n"); + Tc = 0; + Told = -100; + + // monitor temperature and adjust boilerPin as needed: + while (true) { + + // read temperature from tempSensorPin: + Vo = analogRead(tempSensorPin); + R2 = R1 * (1023.0 / (float)Vo - 1.0); + logR2 = log(R2); + T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); + Tc = (T - 273.15); + + if (millis() - startTime > 1000) { + Told = Tc; // support variable to store temp at beginning, so that we can be sure it's increasing + } + + // check if temperature is within the acceptable range and break out of the loop without error if done heating: + if (Tc > desiredTemp) { + // temperature is within range, so break out of the loop: + digitalWrite(boilerPin, LOW); + delay(100); + Serial.write("reached desired temp\n"); + delay(100); + Serial.print(Tc); + delay(100); + Serial.write(" C\n"); + digitalWrite(redLED, LOW); + break; + } + + if (Tc < -100) { + delay(100); + Serial.write("u-Thermocouple: unplugged or failed\n"); + digitalWrite(boilerPin, LOW); + unrecoverableErr = 1; + break; + } + + if (millis() - startTime > 20000 && Tc - Told < 5) { + delay(100); + Serial.write("p-Thermocouple: positioning or relay fault\n"); + digitalWrite(boilerPin, LOW); + unrecoverableErr = 1; + break; + } + + if (millis() - startTime > 30000) { + delay(100); + Serial.write("h-taking too long, continuing...\n"); + digitalWrite(boilerPin, LOW); + digitalWrite(redLED, LOW); + break; + } + + // We do this at the end so that the relay is not uselessly cycled + digitalWrite(boilerPin, HIGH); + delay(milliseconds); + + } + digitalWrite(greenLED, HIGH); +} + +void Press() { + digitalWrite(greenLED, LOW); + delay(100); + Serial.write("pressing...\n"); + + // Reset Press before every coffee + digitalWrite(invertWheelPin, HIGH); + delay(1000); + digitalWrite(invertWheelPin, LOW); + + digitalWrite(wheelPin, HIGH); + startTime = millis(); + + while (true) { + delay(milliseconds); + if (digitalRead(wheelEndSensorPin) == HIGH) { + digitalWrite(wheelPin, LOW); + delay(100); + Serial.write("Pressed\n"); + break; + } + if (millis() - startTime > 15000) { + delay(100); + Serial.write("p-end of pressing not detected\n"); + digitalWrite(wheelPin, LOW); + unrecoverableErr = 1; + break; + } + } + digitalWrite(greenLED, HIGH); +} + +void unPress() { + digitalWrite(greenLED, LOW); + delay(100); + Serial.write("unPressing...\n"); + + // Reset Press before every coffee + digitalWrite(wheelPin, HIGH); + delay(1000); + digitalWrite(wheelPin, LOW); + + digitalWrite(invertWheelPin, HIGH); + startTime = millis(); + + while (true) { + delay(milliseconds); + if (digitalRead(wheelStartSensorPin) == HIGH) { + delay(1500); + digitalWrite(invertWheelPin, LOW); + delay(100); + Serial.write("UnPressed\n"); + break; + } + if (millis() - startTime > 15000) { + delay(100); + Serial.write("u-end of unPressing not detected\n"); + digitalWrite(invertWheelPin, LOW); + unrecoverableErr = 1; + break; + } + } + digitalWrite(greenLED, HIGH); +} + +void Pump() { + digitalWrite(greenLED, LOW); + delay(100); + Serial.write("pumping Water...\n"); + digitalWrite(pumpPin, HIGH); + delay(1000*pumpRatio); + digitalWrite(pumpPin, LOW); + delay(100); + Serial.write("Pumping water done\n"); + digitalWrite(greenLED, HIGH); +} + +void makeCoffee() { + // code to make coffee goes here... + // It would be much smarter to break down complicated functions into subroutines: press/unpress etc... + // Hence that's what we'll have done by the time the first release goes public ;) + // makeCoffee() can still run all the same, but clean() can use the same press/unpress code! + // care must be taken to place these functions earlier in the code, or the compiler will rightfully freak out + + while (true) { + + desiredTemp = 75; + Heat(); // First we pre-heat the boiler + if (unrecoverableErr == 1) { + break; + } + + if (dry == 0 && noCoffee == 0) { + Grind(); // Grinding some nice roasted coffee beans! + } + + // If grinder won't stop, coffee probably need to be refilled. + if (warning == 1) { + delay(100); + Serial.write("refill coffee and send cont command\n"); + while (true) { + // check if data has been sent on serial from ESP or PC: + if (Serial.available() > 0) { + // read the incoming data: (we only care about the first few characters, I've chosen 4) + readString = ""; + serialRead(); + String incomingData = readString.substring(0,4); + + if (incomingData == "cont") { + // coffee refilled, making is allowed to continue + Serial.write("Refilled\n"); + warning = 0; + Grind(); // Grinding some nice roasted coffee beans! + if (warning == 1) { + unrecoverableErr = 1; + Serial.write("g-failure: second grinding failure, check grinder!\n"); + } + break; + } + } + } + } + + // Stop if grinding failed a second time + if (unrecoverableErr == 1) { + break; + } + + delay(1000); // this delay is mandatory to prevent powder spillage caused by grinder inertia. + unPress(); // unpressing the press to reset the machine + + if (unrecoverableErr == 1) { + break; + } + + Drop(); // Dropping the powder in the press + delay(1000); + + Press(); // Self explainatory + + if (unrecoverableErr == 1) { + break; + } + + if (dry == 0) { + digitalWrite(boilerPin, HIGH); + delay(1000); + Pump(); // Pump ratio (in seconds) will be read from serial input in final release + digitalWrite(boilerPin, LOW); + } + delay(3000); // Allow pressure to wane + + unPress(); // unpressing the press to reset the machine + + if (unrecoverableErr == 1) { + break; + } + delay(100); + Serial.write("Complete!\n"); + dry = 0; + noCoffee = 0; + break; + } +}