|
|
- // LAST UPDATE: NOVEMBER 2024
-
- #include <Arduino.h>
- #include <ESP8266WiFi.h>
- #include <ESPAsyncTCP.h>
- #include <ESPAsyncWebServer.h>
- #include <AsyncElegantOTA.h>
- #include <Wire.h>
- #include <LiquidCrystal.h>
- #include <EEPROM.h> // 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(
- <!DOCTYPE HTML><html><head>
- <title>PyCoffee HTML interface</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
-
- <style>
- html {display: inline-block; text-align: center;}
- </style>
-
- </head><body>
- <a>Ciao! Sono la macchina del caffe' della 117bis!</a><br>
- <a>Seleziona il tipo di caffe' e conferma</a><br><br>
-
- <form action="/get">
- <select name="coffee_input">
- <option value="Ristretto">Ristretto</option>
- <option value="Espresso">Espresso</option>
- <option value="Lungo">Lungo</option>
- <option value="Americano">Americano</option>
- </select><br><br>
- <input type="submit" value="Conferma">
- </form>
- <br><br>
-
- <a>Puoi mandare comandi a Arduino via seriale</a><br>
- <a>usa 'exit' per uscire dall'ultimo comando seriale</a><br><br>
-
- <form action="/serial">
- <select name="serial_input">
- <option value="exit">Exit Command</option>
- <option value="dryr">PerformDryRun</option>
- <option value="noco">NoCoffeeRun</option>
- <option value="clea">Self-Clean</option>
- <option value="make">Make Coffee</option>
- <option value="pump">pumpWater</option>
- <option value="pres">Press</option>
- <option value="unpr">un-Press</option>
- <option value="f-pr">Force-Press</option>
- <option value="f-un">Force-unpress</option>
- <option value="heat">Heat Boiler</option>
- <option value="grin">GrindPowder</option>
- <option value="drop">Drop Powder</option>
- <option value="rist">setRistretto-15s</option>
- <option value="espr">setEspresso-20s</option>
- <option value="long">setLungo-25s</option>
- <option value="amer">setAmericano-60s</option>
- </select><br><br>
- <input type="submit" value="Invia Comando">
- </form>
- <br><br>
-
- <a>Consulta la pagina Gitea per maggiori informazioni</a><br><br>
-
- <a>Aggiornamento firmware:</a> <br>
- <a href='/update'>⬆️ OTA Firmware_Update ⬆️</a><br><br>
- <a>Codice sorgente (su LILiK projects):</a> <br>
- <a href='https://projects.lilik.it/LILiK/PyCoffee_ESP8266'>☕Gitea☕</a><br><br>
-
- </body></html>)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);
- }
- }
- }
|