// LAST UPDATE: NOVEMBER 2024 #include #include #include #include #include #include #include #include // to store number of coffees made and pumped water AsyncWebServer server(80); // coffee times (in seconds) and temperature (in C) settings: // Warning! these are currently hard-coded in the arduino nano //int rist = 10; //int espr = 15; //int lung = 20; //int amer = 60; //int desiredTemp = 70; // support variables used by checktraywater() to interact with EEPROM int mem0 = 0; int mem1 = 0; // 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 String hostname = "PyCoffee"; int wifiStatus = 0; // variable to store status (connected/disconnected, used by LCDprint) // string to store coffee style from HTML String input_field = ""; // string for coffee type String input_field2 = ""; // string for serial commands // 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





Puoi mandare comandi a Arduino via seriale
usa 'exit' per uscire dall'ultimo comando seriale





Consulta la pagina Gitea per maggiori informazioni

Aggiornamento firmware:
⬆️ OTA Firmware_Update ⬆️

Codice sorgente (su LILiK projects):
☕Gitea☕

)rawliteral"; // input parameter for html server const char* input_paramter1 = "coffee_input"; const char* input_paramter2 = "serial_input"; // enable http coffee making on server request int httpCoffee = 0; int serialCommand = 0; // button pins const int sel = 0, enter = 2; // Global string, allows serial in String readString; // coffee type variable String type = "Espresso"; // number of coffees made and seconds of pumped water since last tray empty/water refill // used by checkTrayWater() function int coffeesDone = 0; int pumpedS = 0; const int MaxCoffees = 10; const int MaxPumped = 500; // 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 = ""; // only refresh LCD when needed int printed = 0; // 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}; // Custom character matrix (WiFi connected/disconnected) byte wifiok[8] = {0b00000,0b01110,0b10001,0b00100,0b01010,0b00000,0b00000,0b00100}; byte wifino[8] = {0b00000,0b10001,0b01010,0b00100,0b01010,0b10001,0b00000,0b00100}; 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) { // check how many coffees were done and seconds of pumped water from EEPROM mem0 = (EEPROM.read(0)); mem1 = (EEPROM.read(1)); // protect against under/over-flow due to errors or memory location never having been used if (mem0 < 0 or mem0 > MaxCoffees + 1) { EEPROM.write(0, 0); mem0 = 0; } if (mem1 < 0 or mem1 > MaxPumped + 50) { EEPROM.write(1, 0); mem1 = 0; } coffeesDone = mem0; pumpedS = mem1; // 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.createChar(6, wifiok); lcd.createChar(7, wifino); 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 // coffee 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! }); // serial commands server.on("/serial", HTTP_GET, [] (AsyncWebServerRequest *request) { if (request->hasParam(input_paramter2)) { if (serialOUTbuffer != "") { serialOUTbuffer = request->getParam(input_paramter2)->value(); serialCommand = 1; httpCoffee = 0; } } 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 printed = 1; // tell the Arduino we're ready serialOUTbuffer = "read"; delay(100); writeSerial(); type = "Espresso"; line1 = "Selection"; line2 = type; LCDprint(); delay(500); } //_____________________________________________________________________________ void loop() { // the loop function runs over and over again forever delay(10); serialFromHTTP(); // 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 = "Americano"; line1 = "Selection"; line2 = type; LCDprint(); delay(500); } else if (digitalRead(sel) == LOW && type == "Americano") { 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); } else 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); // are we heating the boiler to vapor temperature? if (incomingData == "Vapo") { line1 = "Heating"; line2 = "Vapor"; LCDprint(); delay(1000); } if (incomingData == "reac") { line1 = "Vapor"; line2 = "ok"; LCDprint(); delay(1000); printed = 1; delay(10000); serialOUTbuffer = "unpr"; writeSerial(); delay(100); } } refreshMenu(); delay(100); // 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 = "Release 1.1e"; LCDprint(); delay(1000); line1 = "JIMBO"; line2 = ""; LCDprint(); delay(1000); lcd.setCursor(11,0); //print coffee cup top using uint8 method lcd.write((uint8_t)0); delay(10); lcd.write((uint8_t)1); delay(10); lcd.write((uint8_t)2); delay(10); lcd.setCursor(11,1); //print coffee cup bottom using uint8 method lcd.write((uint8_t)3); delay(10); lcd.write((uint8_t)4); delay(10); 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(); delay(10000); break; } else { wifiStatus = 1; } } 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(); delay(10); lcd.setCursor(0, 1); // move cursor to (0, 1) lcd.print(WiFi.localIP()); // re-print line2 or IP won't print delay(2000); } //_____________________________________________________________________________ void refreshMenu() { if (line1 == "Selection" && printed == 1) { lcd.clear(); lcd.setCursor(0, 0); // move cursor to (0, 0) lcd.print(line1); // print line1 delay(10); lcd.setCursor(15, 0); // move cursor to (14, 0) // print wifi logo depending on connection starus if (wifiStatus == 1) { lcd.write((uint8_t)6); delay(10); } else if (wifiStatus == 0) { lcd.write((uint8_t)7); delay(10); } lcd.setCursor(0, 1); // move cursor to (0, 1) lcd.print(line2); // print line2 delay(10); printed = 0; } } //_____________________________________________________________________________ void LCDprint() { lcd.clear(); lcd.setCursor(0, 0); // move cursor to (0, 0) lcd.print(line1); // print line1 delay(10); lcd.setCursor(15, 0); // move cursor to (14, 0) // print wifi logo depending on connection starus if (wifiStatus == 1) { lcd.write((uint8_t)6); delay(10); } else if (wifiStatus == 0) { lcd.write((uint8_t)7); delay(10); } lcd.setCursor(0, 1); // move cursor to (0, 1) lcd.print(line2); // print line2 delay(10); } //_____________________________________________________________________________ void writeSerial() { Serial.println(serialOUTbuffer); } //_____________________________________________________________________________ void serialFromHTTP() { if (serialCommand == 1){ serialCommand = 0; line1 = "serialCom"; line2 = serialOUTbuffer; LCDprint(); delay(1000); writeSerial(); while (serialOUTbuffer != "exit" && digitalRead(sel) == HIGH ) { 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,16); Serial.print("serial put from Arduino:\n"); Serial.print(incomingData); Serial.print("\n"); if (serialOUTbuffer != "none") { line1 = serialOUTbuffer; } line2 = incomingData; LCDprint(); delay(100); serialOUTbuffer = "none"; writeSerial(); } } line1 = "Selection"; line2 = type; LCDprint(); delay(500); } } //_____________________________________________________________________________ void checkTrayWater() { // section dedicated to empty tray and refill water messages if (coffeesDone == MaxCoffees) { lcd.clear(); while (digitalRead(enter) == HIGH) { line1 = "Empty Tray"; line2 = "Then hold Make"; delay(500); LCDprint(); } coffeesDone = 0; EEPROM.write(0, 0); line1 = "Tray emptied"; line2 = "continuing..."; delay(1000); LCDprint(); } if (pumpedS > MaxPumped) { lcd.clear(); while (digitalRead(enter) == HIGH) { line1 = "Refill Water"; line1 = "Then hold Make"; delay(500); LCDprint(); } pumpedS = 0; EEPROM.write(1, 0); line1 = "Water Refilled"; line2 = "continuing..."; delay(1000); LCDprint(); } delay(500); printed = 1; EEPROM.commit(); line1 = "Selection"; line2 = type; } //_____________________________________________________________________________ void serialCoffeeCommandLCDInterface() { if (digitalRead(enter) == LOW or httpCoffee == 1) { httpCoffee = 0; if (type == "Espresso") { serialOUTbuffer = "espr"; pumpedS = pumpedS + 20; } else if (type == "Lungo") { serialOUTbuffer = "long"; pumpedS = pumpedS + 25; } else if (type == "Ristretto") { serialOUTbuffer = "rist"; pumpedS = pumpedS + 15; } else if (type == "Americano") { serialOUTbuffer = "amer"; pumpedS = pumpedS + 60; } 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(); delay(10); lcd.setCursor(11,0); //print coffee cup top using uint8 method lcd.write((uint8_t)0); delay(10); lcd.write((uint8_t)1); delay(10); lcd.write((uint8_t)2); delay(10); lcd.setCursor(11,1); //print coffee cup bottom using uint8 method lcd.write((uint8_t)3); delay(10); lcd.write((uint8_t)4); delay(10); lcd.write((uint8_t)5); delay(10); } 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") { coffeesDone++; Serial.print("Made coffee\n"); line1 = "Coffee Done :)"; line2 = "Enjoy!"; LCDprint(); delay(5000); line1 = "Selection"; delay(500); } } }