#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <EEPROM.h>
// Pines de servomotores
#define SERVO1_PIN 14
#define SERVO2_PIN 27
// Configuración EEPROM (almacenamiento de parámetros)
#define EEPROM_SIZE 128
struct Config {
char ssid[32];
char password[32];
int hora1[3]; // hh, mm, ss
int hora2[3];
int hora3[3];
int servo1_abierto; // Ángulo en grados
int servo1_cerrado;
int servo2_abierto;
int servo2_cerrado;
int tiempo_espera; // Segundos entre movimientos
} config;
// Objetos
#include <Servo.h>
Servo servo1;
Servo servo2;
WebServer server(80);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", -18000, 60000); // GMT-5 para México
// Estado WiFi
bool modoAP = false;
const char* apSSID = "AlimentadorESP32";
const char* apPassword = "alimentador123";
// Función para leer configuración de EEPROM
void leerConfig() {
EEPROM.begin(EEPROM_SIZE);
EEPROM.get(0, config);
EEPROM.end();
// Valores por defecto si la configuración es inválida
if (strlen(config.ssid) == 0) {
strcpy(config.ssid, "");
strcpy(config.password, "");
config.hora1[0] = 8; config.hora1[1] = 0; config.hora1[2] = 0;
config.hora2[0] = 14; config.hora2[1] = 0; config.hora2[2] = 0;
config.hora3[0] = 20; config.hora3[1] = 0; config.hora3[2] = 0;
config.servo1_abierto = 90; config.servo1_cerrado = 0;
config.servo2_abierto = 90; config.servo2_cerrado = 0;
config.tiempo_espera = 5;
}
}
// Función para guardar configuración en EEPROM
void guardarConfig() {
EEPROM.begin(EEPROM_SIZE);
EEPROM.put(0, config);
EEPROM.commit();
EEPROM.end();
}
// Función para conectarse a WiFi
void conectarWiFi() {
if (strlen(config.ssid) == 0) {
modoAP = true;
return;
}
WiFi.begin(config.ssid, config.password);
int intentos = 0;
while (WiFi.status() != WL_CONNECTED && intentos < 20) {
delay(500);
intentos++;
}
if (WiFi.status() != WL_CONNECTED) {
modoAP = true;
} else {
modoAP = false;
timeClient.begin();
timeClient.update();
}
}
// Función para iniciar modo AP
void iniciarAP() {
WiFi.softAP(apSSID, apPassword);
IPAddress ip = WiFi.softAPIP();
}
// Secuencia de alimentación
void secuenciaAlimentacion() {
// Cerrar ambos servos inicialmente
servo1.write(config.servo1_cerrado);
servo2.write(config.servo2_cerrado);
delay(1000);
// Abrir servo 1, cerrar después de tiempo de espera
servo1.write(config.servo1_abierto);
delay(config.tiempo_espera * 1000);
servo1.write(config.servo1_cerrado);
delay(1000);
// Abrir servo 2, cerrar después de tiempo de espera
servo2.write(config.servo2_abierto);
delay(config.tiempo_espera * 1000);
servo2.write(config.servo2_cerrado);
delay(1000);
}
// Página web principal/configuración
String paginaWeb() {
String html = "<html><head><title>Config Alimentador</title></head><body>";
html += "<h1>Configuración Alimentador</h1>";
// Configuración WiFi
html += "<h2>Red WiFi</h2>";
html += "<form method='POST' action='/guardar'>";
html += "SSID: <input type='text' name='ssid' value='" + String(config.ssid) + "'><br>";
html += "Contraseña: <input type='password' name='password' value='" + String(config.password) + "'><br>";
// Horarios
html += "<h2>Horarios de Comida</h2>";
html += "Hora 1 (hh:mm:ss): <input type='number' name='h1' min='0' max='23' value='" + String(config.hora1[0]) + "'>:";
html += "<input type='number' name='m1' min='0' max='59' value='" + String(config.hora1[1]) + "'>:";
html += "<input type='number' name='s1' min='0' max='59' value='" + String(config.hora1[2]) + "'><br>";
html += "Hora 2 (hh:mm:ss): <input type='number' name='h2' min='0' max='23' value='" + String(config.hora2[0]) + "'>:";
html += "<input type='number' name='m2' min='0' max='59' value='" + String(config.hora2[1]) + "'>:";
html += "<input type='number' name='s2' min='0' max='59' value='" + String(config.hora2[2]) + "'><br>";
html += "Hora 3 (hh:mm:ss): <input type='number' name='h3' min='0' max='23' value='" + String(config.hora3[0]) + "'>:";
html += "<input type='number' name='m3' min='0' max='59' value='" + String(config.hora3[1]) + "'>:";
html += "<input type='number' name='s3' min='0' max='59' value='" + String(config.hora3[2]) + "'><br>";
// Configuración servos
html += "<h2>Ajustes de Servomotores</h2>";
html += "Servo 1 - Ángulo Abierto: <input type='number' name='s1a' min='0' max='180' value='" + String(config.servo1_abierto) + "'><br>";
html += "Servo 1 - Ángulo Cerrado: <input type='number' name='s1c' min='0' max='180' value='" + String(config.servo1_cerrado) + "'><br>";
html += "Servo 2 - Ángulo Abierto: <input type='number' name='s2a' min='0' max='180' value='" + String(config.servo2_abierto) + "'><br>";
html += "Servo 2 - Ángulo Cerrado: <input type='number' name='s2c' min='0' max='180' value='" + String(config.servo2_cerrado) + "'><br>";
html += "Tiempo de Espera (seg): <input type='number' name='espera' min='1' max='30' value='" + String(config.tiempo_espera) + "'><br>";
// Botones
html += "<input type='submit' value='Guardar Configuración'>";
html += "<input type='submit' formaction='/probar' value='Probar Secuencia'>";
html += "</form>";
// Estado actual
html += "<h2>Estado Actual</h2>";
html += "Hora actual: " + String(timeClient.getHours()) + ":" + String(timeClient.getMinutes()) + ":" + String(timeClient.getSeconds()) + "<br>";
html += "WiFi conectado: " + String(WiFi.status() == WL_CONNECTED ? "Sí" : "No (Modo AP activado)") + "<br>";
html += "IP: " + String(WiFi.status() == WL_CONNECTED ? WiFi.localIP().toString() : WiFi.softAPIP().toString()) + "<br>";
html += "</body></html>";
return html;
}
// Manejadores web
void manejarRaiz() {
server.send(200, "text/html", paginaWeb());
}
void manejarGuardar() {
// Leer datos del formulario
strcpy(config.ssid, server.arg("ssid").c_str());
strcpy(config.password, server.arg("password").c_str());
config.hora1[0] = server.arg("h1").toInt();
config.hora1[1] = server.arg("m1").toInt();
config.hora1[2] = server.arg("s1").toInt();
config.hora2[0] = server.arg("h2").toInt();
config.hora2[1] = server.arg("m2").toInt();
config.hora2[2] = server.arg("s2").toInt();
config.hora3[0] = server.arg("h3").toInt();
config.hora3[1] = server.arg("m3").toInt();
config.hora3[2] = server.arg("s3").toInt();
config.servo1_abierto = server.arg("s1a").toInt();
config.servo1_cerrado = server.arg("s1c").toInt();
config.servo2_abierto = server.arg("s2a").toInt();
config.servo2_cerrado = server.arg("s2c").toInt();
config.tiempo_espera = server.arg("espera").toInt();
guardarConfig();
server.send(200, "text/html", "Configuración guardada!<br><a href='/'>Volver</a><br>Reiniciando en 5 segundos...");
delay(5000);
ESP.restart();
}
void manejarProbar() {
secuenciaAlimentacion();
server.send(200, "text/html", "Secuencia probada!<br><a href='/'>Volver</a>");
}
void configurarServidores() {
server.on("/", manejarRaiz);
server.on("/guardar", manejarGuardar);
server.on("/probar", manejarProbar);
server.begin();
}
// Setup inicial
void setup() {
Serial.begin(115200);
leerConfig();
// Inicializar servos
servo1.attach(SERVO1_PIN);
servo2.attach(SERVO2_PIN);
servo1.write(config.servo1_cerrado);
servo2.write(config.servo2_cerrado);
// Conectar a WiFi o iniciar AP
conectarWiFi();
if (modoAP) iniciarAP();
configurarServidores();
// Iniciar mDNS para acceso por nombre
if (!MDNS.begin("alimentador")) {
Serial.println("Error al iniciar mDNS");
}
}
// Loop principal
void loop() {
server.handleClient();
// Actualizar hora cada segundo
if (WiFi.status() == WL_CONNECTED) {
timeClient.update();
}
// Obtener hora actual
int h = timeClient.getHours();
int m = timeClient.getMinutes();
int s = timeClient.getSeconds();
// Verificar horarios
static bool ejecutado1 = false, ejecutado2 = false, ejecutado3 = false;
if (h == config.hora1[0] && m == config.hora1[1] && s == config.hora1[2] && !ejecutado1) {
secuenciaAlimentacion();
ejecutado1 = true;
} else if (s != config.hora1[2]) {
ejecutado1 = false;
}
if (h == config.hora2[0] && m == config.hora2[1] && s == config.hora2[2] && !ejecutado2) {
secuenciaAlimentacion();
ejecutado2 = true;
} else if (s != config.hora2[2]) {
ejecutado2 = false;
}
if (h == config.hora3[0] && m == config.hora3[1] && s == config.hora3[2] && !ejecutado3) {
secuenciaAlimentacion();
ejecutado3 = true;
} else if (s != config.hora3[2]) {
ejecutado3 = false;
}
delay(100);
}