/*
* Sistema de Llenado - Orlando Quintero 0414-6952502
* Lógica de LEDs:
* IDLE: Rojo ON, Verde OFF
* ESPERANDO_BOTON: Rojo OFF, Verde Parpadea
* LLENANDO: Rojo OFF, Verde ON
* PAUSA (dentro de LLENANDO): Rojo Parpadea, Verde OFF
* COMPLETADO: Rojo ON, Verde OFF
*/
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <WebServer.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
#include <LiquidCrystal_I2C.h>
#include <Preferences.h>
#include <HTTPClient.h>
// --- CONFIGURACIÓN ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
#define BOT_TOKEN "TU_BOT_TOKEN"
#define CHAT_ID "TU_CHAT_ID"
// DIRECCIÓN EXACTA DE TU SHEETS
const String GOOGLE_URL = "https://script.google.com/macros/s/AKfycbwMxenZWvg-dGAuaNjo9BK8myq9_D0YoCIix77XgSjiSoKrZHxkHrKNOvSK2QGU1i_Q/exec";
LiquidCrystal_I2C lcd(0x27, 16, 2);
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
WebServer server(80);
Preferences pref;
// --- PINES ---
const int ledVerdePin = 2, ledRojoPin = 15, botonArranquePin = 4;
const int bombaPin = 5, valvulaPin = 13, sensorFlujoPin = 14;
const int buzzerPin = 12;
// --- VARIABLES ---
enum Estado { IDLE, ESPERANDO_BOTON, LLENANDO, COMPLETADO };
Estado estadoActual = IDLE;
String tokenActual;
bool pausado = false;
int botellonesPendientes = 0, totalVentaSesion = 0;
volatile long pulsosFlujo = 0;
float litrosDispensados = 0;
const float LITROS_OBJETIVO = 20.0, FACTOR_YFS201 = 450.0;
unsigned long ultimaActualizacionLCD = 0;
void sonidoPip(int duracion, int frecuencia) { tone(buzzerPin, frecuencia, duracion); }
void mostrarLCD(String l1, String l2) {
lcd.clear();
lcd.setCursor(0, 0); lcd.print(l1);
lcd.setCursor(0, 1); lcd.print(l2);
}
void registrarEnGoogle(int cantidad) {
WiFiClientSecure clientGS;
clientGS.setInsecure();
HTTPClient http;
String urlFinal = GOOGLE_URL + "?cantidad=" + String(cantidad);
http.setTimeout(15000);
if (http.begin(clientGS, urlFinal)) {
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
int httpCode = http.GET();
Serial.print("Google Sheets Code: "); Serial.println(httpCode);
http.end();
}
}
void handleLlenar() {
if (server.hasArg("token") && server.arg("token") == tokenActual) {
botellonesPendientes = server.arg("botellon").toInt();
totalVentaSesion = botellonesPendientes;
estadoActual = ESPERANDO_BOTON;
sonidoPip(500, 1000);
server.send(200, "text/plain", "Orden OK");
}
}
void setup() {
Serial.begin(115200);
lcd.init(); lcd.backlight();
pref.begin("seguridad", false);
tokenActual = pref.getString("token", "banana");
pinMode(ledVerdePin, OUTPUT); pinMode(ledRojoPin, OUTPUT);
pinMode(bombaPin, OUTPUT); pinMode(valvulaPin, OUTPUT);
pinMode(botonArranquePin, INPUT_PULLUP);
pinMode(buzzerPin, OUTPUT);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
server.on("/llenar", handleLlenar);
server.begin();
mostrarLCD("Sistema Listo", "Esperando Orden");
}
void loop() {
server.handleClient();
// Simulación Serial para pruebas
if (Serial.available()) {
char sim = Serial.read();
if (sim == 't' || sim == 'h' || sim == 'o') {
botellonesPendientes = (sim == 't') ? 1 : (sim == 'h' ? 2 : 3);
totalVentaSesion = botellonesPendientes;
estadoActual = ESPERANDO_BOTON;
sonidoPip(500, 1000);
}
}
if (digitalRead(botonArranquePin) == LOW) {
static unsigned long lastBtn = 0;
if (millis() - lastBtn > 250) {
if (estadoActual == ESPERANDO_BOTON) {
pulsosFlujo = 0; litrosDispensados = 0; pausado = false;
digitalWrite(bombaPin, HIGH); digitalWrite(valvulaPin, HIGH);
estadoActual = LLENANDO;
}
else if (estadoActual == LLENANDO) {
pausado = !pausado;
digitalWrite(bombaPin, !pausado); digitalWrite(valvulaPin, !pausado);
if (pausado) mostrarLCD("Pausa Esperando", "Lts: " + String(litrosDispensados, 1));
}
lastBtn = millis();
}
}
switch (estadoActual) {
case IDLE:
digitalWrite(ledRojoPin, HIGH);
digitalWrite(ledVerdePin, LOW);
break;
case ESPERANDO_BOTON:
digitalWrite(ledRojoPin, LOW);
digitalWrite(ledVerdePin, (millis() / 400) % 2);
if (millis() % 2000 < 50) mostrarLCD("Faltan: " + String(botellonesPendientes), "PULSE BOTON");
break;
case LLENANDO:
if (pausado) {
digitalWrite(ledRojoPin, (millis() / 300) % 2); // Rojo parpadea en pausa
digitalWrite(ledVerdePin, LOW);
} else {
digitalWrite(ledRojoPin, LOW);
digitalWrite(ledVerdePin, HIGH); // Verde fijo llenando
pulsosFlujo += 20; // Simulación
litrosDispensados = pulsosFlujo / FACTOR_YFS201;
if (millis() - ultimaActualizacionLCD > 250) {
mostrarLCD("Llenando: " + String(litrosDispensados, 1) + "L", "Meta: " + String(LITROS_OBJETIVO, 0) + "L");
ultimaActualizacionLCD = millis();
}
if (litrosDispensados >= LITROS_OBJETIVO) {
digitalWrite(bombaPin, LOW); digitalWrite(valvulaPin, LOW);
estadoActual = COMPLETADO;
}
}
break;
case COMPLETADO:
digitalWrite(ledRojoPin, HIGH); // Rojo fijo en COMPLETADO
digitalWrite(ledVerdePin, LOW);
botellonesPendientes--;
if (botellonesPendientes > 0) {
mostrarLCD("Botellon OK!", "Siguiente...");
delay(2000);
estadoActual = ESPERANDO_BOTON;
} else {
for(int i=0; i<3; i++) { sonidoPip(200, 2000); delay(300); }
mostrarLCD("Venta Finalizada", "Muchas Gracias");
registrarEnGoogle(totalVentaSesion);
bot.sendMessage(CHAT_ID, "✅ Venta Finalizada: " + String(totalVentaSesion) + " botellones.", "");
delay(3000);
estadoActual = IDLE;
mostrarLCD("Sistema Listo", "Esperando Orden");
}
break;
}
}