/*
* Sistema de Llenado - Orlando Quintero
* Modificación: LCD 20x4 y Control por Telegram/Serial
* Eliminado: Google AppScript / Sheets
*/
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <WebServer.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
#include <LiquidCrystal_I2C.h>
#include <Preferences.h>
// --- CONFIGURACIÓN ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
#define BOT_TOKEN "8461452157:AAHOY-vynAMIufApsdIVbZDezwEyrFmBv4U"
#define CHAT_ID "1111180487"
LiquidCrystal_I2C lcd(0x27, 20, 4);
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
WebServer server(80);
Preferences pref;
// --- PINES ---
const int ledVerdePin = 2, ledRojoPin = 15, botonArranquePin = 4;
const int bombaPin = 13;
const int valvulaPin = 12;
const int sensorFlujoPin = 14;
const int buzzerPin = 27;
// --- 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;
// FUNCIÓN DE SONIDO (CORE ESP32 v3.0+)
void sonidoPip(int duracion, int frecuencia) {
ledcWriteTone(buzzerPin, frecuencia);
delay(duracion);
ledcWriteTone(buzzerPin, 0);
}
void mostrarLCD(String l1, String l2, String l3 = "", String l4 = "") {
lcd.clear();
lcd.setCursor(0, 0); lcd.print(l1);
lcd.setCursor(0, 1); lcd.print(l2);
lcd.setCursor(0, 2); lcd.print(l3);
lcd.setCursor(0, 3); lcd.print(l4);
}
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();
client.setInsecure();
// Configuración Buzzer
ledcAttach(buzzerPin, 2000, 8);
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);
mostrarLCD("SISTEMA DE LLENADO", "Iniciando...", "WiFi: " + String(ssid));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
mostrarLCD("CONEXION EXITOSA", "Telegram Listo", "Esperando comandos");
bot.sendMessage(CHAT_ID, "🚀 Sistema en línea", "");
server.on("/llenar", handleLlenar);
server.begin();
mostrarLCD("SISTEMA LISTO", "Esperando Orden", "--------------------", "Estado: Standby");
}
void loop() {
server.handleClient();
// Control por Serial (Simulación)
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);
}
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("ORDEN RECIBIDA", "Faltan: " + String(botellonesPendientes), "", ">> PULSE BOTON <<");
}
break;
case LLENANDO:
if (pausado) {
digitalWrite(ledRojoPin, (millis() / 300) % 2);
digitalWrite(ledVerdePin, LOW);
if (millis() % 1000 < 50) mostrarLCD("ESTADO: PAUSA", "Lts: " + String(litrosDispensados, 1), "Pulse para continuar");
} else {
digitalWrite(ledRojoPin, LOW);
digitalWrite(ledVerdePin, HIGH);
pulsosFlujo += 10; // Simulación de flujo
litrosDispensados = pulsosFlujo / FACTOR_YFS201;
if (millis() - ultimaActualizacionLCD > 250) {
mostrarLCD("LLENANDO BOTELLON", "Progreso: " + String(litrosDispensados, 1) + " L", "Meta: " + String(LITROS_OBJETIVO, 0) + " L", "Pendientes: " + String(botellonesPendientes));
ultimaActualizacionLCD = millis();
}
if (litrosDispensados >= LITROS_OBJETIVO) {
digitalWrite(bombaPin, LOW); digitalWrite(valvulaPin, LOW);
estadoActual = COMPLETADO;
}
}
break;
case COMPLETADO:
botellonesPendientes--;
if (botellonesPendientes > 0) {
mostrarLCD("BOTELLON OK!", "Prepare el siguiente", "y pulse boton", "Quedan: " + String(botellonesPendientes));
delay(2000);
estadoActual = ESPERANDO_BOTON;
} else {
mostrarLCD("VENTA FINALIZADA", "Informando al Bot", "Espere un momento...", "");
bot.sendMessage(CHAT_ID, "✅ Venta Finalizada: " + String(totalVentaSesion) + " botellones.", "");
for(int i=0; i<3; i++) { sonidoPip(200, 2000); delay(300); }
mostrarLCD("GRACIAS POR", "SU COMPRA", "Vuelva pronto", "--------------------");
delay(3000);
estadoActual = IDLE;
mostrarLCD("SISTEMA LISTO", "Esperando Orden", "--------------------", "Estado: Standby");
}
break;
}
}