// Importa la librería para controlar tiras de LED tipo WS2812 (Neopixel)
#include <Adafruit_NeoPixel.h>
// Librerías para habilitar funciones WiFi y servidor web en ESP32
#include <WiFi.h>
#include <WebServer.h>
// Define el pin de datos para la tira LED
#define PIN_LED 13
// Número de LEDs que tiene la tira conectada
#define NUM_LEDS 8
// Pin donde está conectado el botón físico
#define PIN_BOTON 14
// Crea un objeto para controlar la tira LED
Adafruit_NeoPixel strip(NUM_LEDS, PIN_LED, NEO_GRB + NEO_KHZ800);
// Crea un servidor web en el puerto 80 (por defecto en navegadores)
WebServer server(80);
// Variables de estado del botón
bool ultimoEstadoBoton = HIGH;
int escena = 0; // Variable que indica qué escena se está mostrando
// Variables para controlar animaciones y temporización
unsigned long tiempoAnterior = 0;
int arcoirisHue = 0;
int nivelBrillo = 0;
bool subirBrillo = true;
int indiceEscalera = 0;
int posicionRebote = 0;
int direccionRebote = 1;
void setup() {
// Configura el pin del botón como entrada con resistencia pull-up interna
pinMode(PIN_BOTON, INPUT_PULLUP);
// Inicializa la tira de LEDs
strip.begin();
strip.show(); // Apaga todos los LEDs al inicio
// Activa modo Access Point (crea su propia red WiFi)
WiFi.softAP("BarraLED", "12345678"); // Nombre de red y contraseña
// Define qué función ejecuta el servidor cuando se accede al raíz "/"
server.on("/", mostrarWeb);
// Define la ruta para cambiar de escena manualmente desde el navegador
server.on("/escena", cambiarEscena);
// Inicia el servidor web
server.begin();
}
void loop() {
// Atiende las solicitudes HTTP al servidor web
server.handleClient();
// Lee si el botón fue presionado
leerBoton();
// Ejecuta la escena seleccionada
ejecutarEscena(escena);
}
// Lee el estado del botón físico y cambia de escena si fue presionado
void leerBoton() {
bool estadoBoton = digitalRead(PIN_BOTON); // Lee el estado actual del botón
// Detecta flanco descendente (cuando se presiona)
if (ultimoEstadoBoton == HIGH && estadoBoton == LOW) {
escena++; // Avanza a la siguiente escena
if (escena > 16) escena = 0; // Vuelve a 0 si pasa el último valor
delay(200); // Pequeño retardo para evitar rebote
}
// Actualiza el estado del botón para la próxima lectura
ultimoEstadoBoton = estadoBoton;
}
// Ejecuta el efecto LED asociado a cada número de escena
void ejecutarEscena(int e) {
switch (e) {
case 0: apagarLeds(); break;
case 1: llenarColor(255, 0, 0); break; // Rojo
case 2: llenarColor(0, 255, 0); break; // Verde
case 3: llenarColor(0, 0, 255); break; // Azul
case 4: llenarColor(255, 255, 0); break; // Amarillo
case 5: llenarColor(0, 255, 255); break; // Cian
case 6: llenarColor(255, 0, 255); break; // Magenta
case 7: llenarColor(255, 255, 255); break; // Blanco
case 8: efectoArcoiris(); break;
case 9: efectoEscalera(); break;
case 10: efectoFade(); break;
case 11: efectoRebote(); break;
case 12: efectoLlamas(); break;
case 13: efectoColorWipe(); break;
case 14: efectoEstrobo(); break;
case 15: efectoAleatorio(); break;
case 16: apagarLeds(); break;
}
}
// Genera la página web con botones para cada escena
void mostrarWeb() {
String html = "<html><body><h1>Barra LED Mexicana</h1>";
for (int i = 0; i <= 16; i++) {
html += "<a href='/escena?valor=" + String(i) + "'><button>Escena " + String(i) + "</button></a><br>";
}
html += "</body></html>";
// Envía la respuesta HTML al navegador
server.send(200, "text/html", html);
}
// Cambia la escena desde el navegador si se recibe el argumento 'valor'
void cambiarEscena() {
if (server.hasArg("valor")) {
escena = server.arg("valor").toInt(); // Convierte el valor a entero
server.send(200, "text/plain", "Escena cambiada a " + String(escena));
} else {
server.send(400, "text/plain", "Falta argumento 'valor'");
}
}
// Apaga todos los LEDs
void apagarLeds() {
strip.clear();
strip.show();
}
// Llena todos los LEDs con un color específico
void llenarColor(uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
// Efecto de arcoíris animado
void efectoArcoiris() {
if (millis() - tiempoAnterior > 30) {
for (int i = 0; i < NUM_LEDS; i++) {
int pixelHue = (arcoirisHue + (i * 360 / NUM_LEDS)) % 360;
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue * 182)));
}
strip.show();
arcoirisHue = (arcoirisHue + 5) % 360;
tiempoAnterior = millis();
}
}
// Efecto de escalera azul que avanza
void efectoEscalera() {
if (millis() - tiempoAnterior > 150) {
strip.clear();
for (int i = 0; i <= indiceEscalera; i++) {
strip.setPixelColor(i, strip.Color(0, 0, 255));
}
strip.show();
indiceEscalera++;
if (indiceEscalera >= NUM_LEDS) indiceEscalera = 0;
tiempoAnterior = millis();
}
}
// Efecto de respiración azul (sube y baja brillo)
void efectoFade() {
if (millis() - tiempoAnterior > 20) {
strip.fill(strip.Color(0, 0, nivelBrillo));
strip.show();
if (subirBrillo) {
nivelBrillo += 5;
if (nivelBrillo >= 255) subirBrillo = false;
} else {
nivelBrillo -= 5;
if (nivelBrillo <= 0) subirBrillo = true;
}
tiempoAnterior = millis();
}
}
// Rebote de un punto rojo en la tira LED
void efectoRebote() {
if (millis() - tiempoAnterior > 100) {
strip.clear();
strip.setPixelColor(posicionRebote, strip.Color(255, 0, 0));
strip.show();
posicionRebote += direccionRebote;
if (posicionRebote == NUM_LEDS - 1 || posicionRebote == 0) {
direccionRebote *= -1;
}
tiempoAnterior = millis();
}
}
// Wipe azul, encendiendo LEDs uno a uno
void efectoColorWipe() {
static int pos = 0;
if (millis() - tiempoAnterior > 100) {
strip.setPixelColor(pos, strip.Color(0, 0, 255));
strip.show();
pos++;
if (pos >= NUM_LEDS) pos = 0;
tiempoAnterior = millis();
}
}
// Estrobo blanco que parpadea
void efectoEstrobo() {
if (millis() - tiempoAnterior > 100) {
static bool on = false;
uint32_t color = on ? strip.Color(255, 255, 255) : strip.Color(0, 0, 0);
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, color);
}
strip.show();
on = !on;
tiempoAnterior = millis();
}
}
// Efecto con colores completamente aleatorios
void efectoAleatorio() {
if (millis() - tiempoAnterior > 1000) {
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t r = random(0, 256);
uint8_t g = random(0, 256);
uint8_t b = random(0, 256);
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
tiempoAnterior = millis();
}
}
// Simulación de efecto llama (colores cálidos aleatorios)
void efectoLlamas() {
if (millis() - tiempoAnterior > 80) {
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t r = random(180, 255);
uint8_t g = random(50, 120);
uint8_t b = random(0, 30);
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
tiempoAnterior = millis();
}
}