Ejemplo de ESP32 WebSlider - Tutorial de la Interfaz de Control de Dos Deslizadores

Visión general

El ejemplo WebSlider proporciona dos controles deslizantes independientes accesibles a través de un navegador web. Plataforma educativa diseñada para ESP32 con capacidades analógicas mejoradas, características de control de precisión y módulos educativos integrados para aprender PWM y electrónica analógica. Cada control deslizante ofrece valores de 0-255, lo que los hace perfectos para el control PWM, el ajuste de brillo, el control de velocidad del motor y cualquier aplicación que requiera valores de control analógicos.

Ejemplo de Arduino WebSlider - Tutorial de la interfaz de control de dos deslizadores

Características

  • Deslizadores Dobles: Dos controles deslizantes independientes (rango 0-255 cada uno)
  • Valores en Tiempo Real: Actualizaciones de valores en tiempo real a través de WebSocket
  • Compatibles con PWM: Valores de 8 bits (0-255), perfectos para las funciones analogWrite()
  • Retroalimentación Visual: Visualización de valores en tiempo real para cada control deslizante
  • Botones Predefinidos: Valores rápidos para configuraciones comunes
  • Soporte Táctil y con Ratón: Funciona en computadoras de escritorio, tabletas y dispositivos móviles
  • Diseño Adaptable: Se adapta a diferentes tamaños de pantalla
  • Persistencia de Valores: Los deslizadores recuerdan la última posición cuando se recarga la página

Hardware Requerido

1×Módulo de Desarrollo ESP32 ESP-WROOM-32
1×Cable USB Tipo-A a Tipo-C (para PC USB-A)
1×Cable USB Tipo-C a Tipo-C (para PC USB-C)
1×(Recomendado) Placa de Expansión de Terminales de Tornillo para ESP32
1×(Recomendado) Breakout Expansion Board for ESP32
1×(Recomendado) Divisor de Alimentación para ESP32

Or you can buy the following kits:

1×DIYables ESP32 Starter Kit (ESP32 included)
1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)
Divulgación: Algunos de los enlaces proporcionados en esta sección son enlaces de afiliado de Amazon. Podemos recibir una comisión por las compras realizadas a través de estos enlaces sin costo adicional para usted. Apreciamos su apoyo.

Instrucciones de configuración

Pasos rápidos

Sigue estas instrucciones paso a paso:

  • Si es la primera vez que usas el ESP32, consulta el tutorial sobre configurar el entorno para ESP32 en el IDE de Arduino.
  • Conecta la placa ESP32 a tu computadora usando un cable USB.
  • Inicia el IDE de Arduino en tu computadora.
  • Selecciona la placa ESP32 adecuada (p. ej. ESP32 Dev Module) y el puerto COM.
  • Navega hasta el icono Bibliotecas en la barra izquierda del IDE de Arduino.
  • Busca "DIYables ESP32 WebApps", luego encuentra la DIYables ESP32 WebApps Library de DIYables.
  • Haz clic en el botón Instalar para instalar la biblioteca.
Biblioteca de WebApps para ESP32 de DIYables
  • Se le pedirá instalar algunas otras dependencias de la biblioteca.
  • Haga clic en el botón Instalar todo para instalar todas las dependencias de la biblioteca.
Dependencia de DIYables ESP32 WebApps
  • En el IDE de Arduino, vaya a Archivo Ejemplos DIYables ESP32 WebApps WebSlider ejemplo, o copie el código anterior y péguelo en el editor de Arduino IDE
/* * DIYables WebApp Library - Web Slider Example * * This example demonstrates the Web Slider feature: * - Two independent sliders (0-255) * - Real-time value monitoring * - Template for hardware control * * Hardware: ESP32 Boards * * Setup: * 1. Update WiFi credentials below * 2. Upload the sketch to your Arduino * 3. Open Serial Monitor to see the IP address * 4. Navigate to http://[IP_ADDRESS]/webslider */ #include <DIYables_ESP32_Platform.h> #include <DIYablesWebApps.h> // WiFi credentials - UPDATE THESE WITH YOUR NETWORK const char WIFI_SSID[] = "YOUR_WIFI_SSID"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD"; // Create WebApp server and page instances ESP32ServerFactory serverFactory; DIYablesWebAppServer webAppsServer(serverFactory, 80, 81); DIYablesHomePage homePage; DIYablesWebSliderPage webSliderPage; // Current slider values int slider1Value = 64; // Default 25% int slider2Value = 128; // Default 50% void setup() { Serial.begin(9600); delay(1000); // TODO: Initialize your hardware pins here Serial.println("DIYables ESP32 WebApp - Web Slider Example"); // Add home and web slider pages webAppsServer.addApp(&homePage); webAppsServer.addApp(&webSliderPage); // Optional: Add 404 page for better user experience webAppsServer.setNotFoundPage(DIYablesNotFoundPage()); // Start the WebApp server if (!webAppsServer.begin(WIFI_SSID, WIFI_PASSWORD)) { while (1) { Serial.println("Failed to start WebApp server!"); delay(1000); } } // Set up slider callback for value changes webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Store the received values slider1Value = slider1; slider2Value = slider2; // Print slider values (0-255) Serial.println("Slider 1: " + String(slider1) + ", Slider 2: " + String(slider2)); // TODO: Add your control logic here based on slider values // Examples: // - Control PWM: analogWrite(LED_PIN, slider1); // - Control servos: servo.write(map(slider1, 0, 255, 0, 180)); // - Control motor speed: analogWrite(MOTOR_PIN, slider2); // - Control brightness: strip.setBrightness(slider1); // - Send values via Serial, I2C, SPI, etc. }); // Set up callback for config requests (when client requests current values) webSliderPage.onSliderValueToWeb([]() { webSliderPage.sendToWebSlider(slider1Value, slider2Value); Serial.println("Web client requested values - Sent: Slider1=" + String(slider1Value) + ", Slider2=" + String(slider2Value)); }); } void loop() { // Handle WebApp server communications webAppsServer.loop(); // TODO: Add your main application code here delay(10); }
  • Configura las credenciales de WiFi en el código actualizando estas líneas:
const char WIFI_SSID[] = "YOUR_WIFI_NETWORK"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";
  • Haz clic en el botón Subir en el IDE de Arduino para subir el código al ESP32
  • Abre el Monitor Serial
  • Consulta el resultado en el Monitor Serial. Es similar a lo siguiente
COM6
Send
DIYables WebApp - Web Slider Example INFO: Added app / INFO: Added app /web-slider DIYables WebApp Library Platform: ESP32 Network connected! IP address: 192.168.0.2 HTTP server started on port 80 Configuring WebSocket server callbacks... WebSocket server started on port 81 WebSocket URL: ws://192.168.0.2:81 WebSocket server started on port 81 ========================================== DIYables WebApp Ready! ========================================== 📱 Web Interface: http://192.168.0.2 🔗 WebSocket: ws://192.168.0.2:81 📋 Available Applications: 🏠 Home Page: http://192.168.0.2/ 🎚️ Web Slider: http://192.168.0.2/web-slider ==========================================
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  
  • Si no ves nada, reinicia la placa ESP32.
  • Toma nota de la dirección IP mostrada y escribe esta dirección en la barra de direcciones de un navegador web en tu teléfono inteligente o PC.
  • Ejemplo: http://192.168.0.2
  • Verás la página de inicio como en la imagen de abajo.
Página de inicio de la WebApp ESP32 DIYables con la aplicación Web Slider
  • Haga clic en el enlace Web Slider; verá la interfaz de usuario de la aplicación Web Slider como se muestra a continuación:
ESP32 DIYables WebApp aplicación web de deslizadores
  • O también puedes acceder a la página directamente mediante la dirección IP seguida de /web-slider. Por ejemplo: http://192.168.0.2/web-slider
  • Intenta mover los dos deslizadores para controlar valores analógicos (0-255) y observa la retroalimentación en tiempo real en el Monitor Serial.

Personalización Creativa - Adapte el código a su proyecto

Establecer valores predeterminados del deslizador

Configurar las posiciones iniciales de los deslizadores:

// Current slider values (0-255) int slider1Value = 64; // Default 25% (64/255) int slider2Value = 128; // Default 50% (128/255)

Cómo usar los deslizadores

Controles de la interfaz web

La interfaz deslizante proporciona:

  • Deslizador 1: Primer deslizador de control con visualización del valor (0-255)
  • Deslizador 2: Segundo deslizador de control con visualización del valor (0-255)
  • Visualización del valor: Valores numéricos en tiempo real para ambos deslizadores
  • Botones de preajuste: Acceso rápido a valores comunes (0%, 25%, 50%, 75%, 100%)

Funcionamiento de los deslizadores

Escritorio (Control del Ratón)

  1. Haga clic y arrastre: Haga clic en el manejador del deslizante y arrástrelo para ajustar el valor
  2. Posición de clic: Haga clic en cualquier lugar de la pista deslizante para ir a ese valor
  3. Ajuste fino: Utilice movimientos pequeños del ratón para un ajuste preciso

Móvil/Tableta (Control táctil)

  1. Tocar y Arrastrar: Toca la manija del control deslizante y arrástrala a una nueva posición
  2. Tocar la pista: Toca en la pista del control deslizante para establecer el valor
  3. Control Suave: El arrastre con el dedo proporciona cambios de valor suaves

Rangos de valores

Cada control deslizante ofrece:

  • Valor mínimo: 0 (0% - completamente apagado)
  • Valor máximo: 255 (100% - intensidad máxima)
  • Resolución: 256 pasos discretos (precisión de 8 bits)
  • Compatibilidad PWM: Uso directo con la función analogWrite()

Ejemplos de Programación

Manejador de control deslizante básico

void setup() { // Set up slider callback for value changes webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Store the received values slider1Value = slider1; slider2Value = slider2; // Print slider values (0-255) Serial.println("Slider 1: " + String(slider1) + ", Slider 2: " + String(slider2)); // Add your control logic here }); }

Control de Brillo de LED

// Pin definitions for PWM LEDs const int LED1_PIN = 9; // PWM pin for first LED const int LED2_PIN = 10; // PWM pin for second LED void setup() { // Configure LED pins as outputs pinMode(LED1_PIN, OUTPUT); pinMode(LED2_PIN, OUTPUT); // Set initial brightness analogWrite(LED1_PIN, slider1Value); analogWrite(LED2_PIN, slider2Value); webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Store values slider1Value = slider1; slider2Value = slider2; // Control LED brightness directly (0-255 PWM) analogWrite(LED1_PIN, slider1); analogWrite(LED2_PIN, slider2); Serial.println("LED1 Brightness: " + String(slider1) + ", LED2 Brightness: " + String(slider2)); }); }

Control de la posición del servomotor

#include <Servo.h> Servo servo1, servo2; void setup() { // Attach servos to PWM pins servo1.attach(9); servo2.attach(10); // Set initial positions servo1.write(map(slider1Value, 0, 255, 0, 180)); servo2.write(map(slider2Value, 0, 255, 0, 180)); webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Map slider values (0-255) to servo angles (0-180°) int angle1 = map(slider1, 0, 255, 0, 180); int angle2 = map(slider2, 0, 255, 0, 180); // Move servos to calculated positions servo1.write(angle1); servo2.write(angle2); Serial.println("Servo1: " + String(angle1) + "°, Servo2: " + String(angle2) + "°"); }); }

Control de la velocidad del motor

// Motor driver pins const int MOTOR1_PWM = 9; // Motor 1 speed control const int MOTOR1_DIR1 = 2; // Motor 1 direction pin 1 const int MOTOR1_DIR2 = 3; // Motor 1 direction pin 2 const int MOTOR2_PWM = 10; // Motor 2 speed control const int MOTOR2_DIR1 = 4; // Motor 2 direction pin 1 const int MOTOR2_DIR2 = 5; // Motor 2 direction pin 2 void setup() { // Configure motor pins pinMode(MOTOR1_PWM, OUTPUT); pinMode(MOTOR1_DIR1, OUTPUT); pinMode(MOTOR1_DIR2, OUTPUT); pinMode(MOTOR2_PWM, OUTPUT); pinMode(MOTOR2_DIR1, OUTPUT); pinMode(MOTOR2_DIR2, OUTPUT); // Set initial motor directions (forward) digitalWrite(MOTOR1_DIR1, HIGH); digitalWrite(MOTOR1_DIR2, LOW); digitalWrite(MOTOR2_DIR1, HIGH); digitalWrite(MOTOR2_DIR2, LOW); webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Control motor speeds directly analogWrite(MOTOR1_PWM, slider1); analogWrite(MOTOR2_PWM, slider2); // Calculate percentage for display int speed1Percent = map(slider1, 0, 255, 0, 100); int speed2Percent = map(slider2, 0, 255, 0, 100); Serial.println("Motor1: " + String(speed1Percent) + "%, " + "Motor2: " + String(speed2Percent) + "%"); }); }

Control de color de LED RGB

// RGB LED pins const int RED_PIN = 9; const int GREEN_PIN = 10; const int BLUE_PIN = 11; void setup() { pinMode(RED_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); pinMode(BLUE_PIN, OUTPUT); webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Use sliders to control RGB components // Slider 1 controls red intensity // Slider 2 controls blue intensity // Green is calculated based on both sliders int redValue = slider1; int blueValue = slider2; int greenValue = (slider1 + slider2) / 2; // Average of both sliders analogWrite(RED_PIN, redValue); analogWrite(GREEN_PIN, greenValue); analogWrite(BLUE_PIN, blueValue); Serial.println("RGB - R:" + String(redValue) + " G:" + String(greenValue) + " B:" + String(blueValue)); }); }

Técnicas Avanzadas de Programación

Suavizado de valores

class SliderSmoother { private: int currentValue = 0; int targetValue = 0; unsigned long lastUpdate = 0; const int SMOOTH_RATE = 5; // Change per update cycle public: void setTarget(int target) { targetValue = target; } int getCurrentValue() { return currentValue; } bool update() { if (millis() - lastUpdate > 10) { // Update every 10ms bool changed = false; if (currentValue < targetValue) { currentValue = min(currentValue + SMOOTH_RATE, targetValue); changed = true; } else if (currentValue > targetValue) { currentValue = max(currentValue - SMOOTH_RATE, targetValue); changed = true; } lastUpdate = millis(); return changed; } return false; } }; SliderSmoother smoother1, smoother2; void setup() { webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Set target values for smooth transition smoother1.setTarget(slider1); smoother2.setTarget(slider2); }); } void loop() { server.loop(); // Update smoothed values bool changed1 = smoother1.update(); bool changed2 = smoother2.update(); if (changed1 || changed2) { // Apply smoothed values to hardware analogWrite(9, smoother1.getCurrentValue()); analogWrite(10, smoother2.getCurrentValue()); } }

Control basado en umbrales

void setupThresholdControl() { webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Threshold-based control for discrete outputs const int LOW_THRESHOLD = 85; // 33% const int MEDIUM_THRESHOLD = 170; // 66% // Control digital outputs based on slider 1 thresholds if (slider1 < LOW_THRESHOLD) { // Low level: Turn off all outputs digitalWrite(2, LOW); digitalWrite(3, LOW); digitalWrite(4, LOW); } else if (slider1 < MEDIUM_THRESHOLD) { // Medium level: Turn on first output digitalWrite(2, HIGH); digitalWrite(3, LOW); digitalWrite(4, LOW); } else { // High level: Turn on all outputs digitalWrite(2, HIGH); digitalWrite(3, HIGH); digitalWrite(4, HIGH); } // Use slider 2 for analog PWM control analogWrite(9, slider2); }); }

Sistema de Valores Predefinidos

// Predefined preset values const int PRESETS[][2] = { {0, 0}, // Preset 0: Both off {64, 128}, // Preset 1: Low/Medium {128, 128}, // Preset 2: Both medium {255, 128}, // Preset 3: High/Medium {255, 255} // Preset 4: Both maximum }; void applyPreset(int presetNumber) { if (presetNumber >= 0 && presetNumber < 5) { slider1Value = PRESETS[presetNumber][0]; slider2Value = PRESETS[presetNumber][1]; // Update hardware analogWrite(9, slider1Value); analogWrite(10, slider2Value); // Send updated values to web interface webSliderPage.sendToWebSlider(slider1Value, slider2Value); Serial.println("Applied preset " + String(presetNumber) + ": " + String(slider1Value) + ", " + String(slider2Value)); } } void setupPresetSystem() { // You could trigger presets based on other inputs // For example, reading digital pins for preset buttons webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Your normal slider handling analogWrite(9, slider1); analogWrite(10, slider2); }); } void loop() { server.loop(); // Check for preset trigger conditions // Example: Read buttons connected to digital pins static bool lastButton = false; bool currentButton = digitalRead(7); // Preset button on pin 7 if (currentButton && !lastButton) { // Button pressed static int currentPreset = 0; applyPreset(currentPreset); currentPreset = (currentPreset + 1) % 5; // Cycle through presets } lastButton = currentButton; }

Ejemplos de integración de hardware

Control de tiras de LED

// For WS2812B or similar addressable LED strips // (requires additional libraries like FastLED or Adafruit NeoPixel) const int LED_STRIP_PIN = 6; const int NUM_LEDS = 30; void setupLEDStrip() { // Initialize LED strip (depends on library used) webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Slider 1 controls brightness (0-255) // Slider 2 controls color temperature or hue uint8_t brightness = slider1; uint8_t hue = slider2; // Update LED strip (example with conceptual functions) // strip.setBrightness(brightness); // strip.fill(CHSV(hue, 255, 255)); // strip.show(); Serial.println("LED Strip - Brightness: " + String(brightness) + ", Hue: " + String(hue)); }); }

Control de Velocidad del Ventilador

const int FAN1_PIN = 9; const int FAN2_PIN = 10; void setupFanControl() { pinMode(FAN1_PIN, OUTPUT); pinMode(FAN2_PIN, OUTPUT); webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Control fan speeds with minimum threshold for startup int fan1Speed = (slider1 > 50) ? map(slider1, 50, 255, 100, 255) : 0; int fan2Speed = (slider2 > 50) ? map(slider2, 50, 255, 100, 255) : 0; analogWrite(FAN1_PIN, fan1Speed); analogWrite(FAN2_PIN, fan2Speed); Serial.println("Fan1: " + String(map(fan1Speed, 0, 255, 0, 100)) + "%, " + "Fan2: " + String(map(fan2Speed, 0, 255, 0, 100)) + "%"); }); }

Control de volumen de audio

// For controlling audio amplifier or volume IC const int VOLUME1_PIN = 9; // PWM output to volume control const int VOLUME2_PIN = 10; // Second channel or tone control void setupAudioControl() { pinMode(VOLUME1_PIN, OUTPUT); pinMode(VOLUME2_PIN, OUTPUT); webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { slider1Value = slider1; slider2Value = slider2; // Use logarithmic scaling for better audio perception float volume1 = pow(slider1 / 255.0, 2) * 255; // Square law float volume2 = pow(slider2 / 255.0, 2) * 255; analogWrite(VOLUME1_PIN, (int)volume1); analogWrite(VOLUME2_PIN, (int)volume2); Serial.println("Volume1: " + String((int)volume1) + ", Volume2: " + String((int)volume2)); }); }

Solución de problemas

Problemas comunes

1. Deslizadores no responden

  • Verificar la conexión WebSocket en la consola del navegador
  • Verificar la conectividad de red entre el dispositivo y Arduino
  • Recargar la página del navegador para restablecer la conexión
  • Verificar el Monitor Serial para errores de conexión
  1. Valores que no alcanzan el rango completo
  • Verificar la configuración del rango del control deslizante en la interfaz web
  • Comprobar problemas de mapeo de valores en la función de callback
  • Probar con diferentes navegadores o dispositivos
  1. Control entrecortado o inconsistente
  • Implementar suavizado de valores para cambios graduales
  • Verificar problemas de latencia de la red
  • Añadir anti-rebote para cambios rápidos de valor

4. La salida PWM no funciona

  • Verificar que los pines soporten PWM (consultar el pinout del ESP32)
  • Asegúrate de llamar a analogWrite() con los números de pin correctos
  • Verifica las conexiones de hardware y los requisitos de carga

Consejos de depuración

Añadir depuración exhaustiva:

void debugSliderValues(int slider1, int slider2) { Serial.println("=== Slider Debug ==="); Serial.println("Slider 1: " + String(slider1) + " (" + String(map(slider1, 0, 255, 0, 100)) + "%)"); Serial.println("Slider 2: " + String(slider2) + " (" + String(map(slider2, 0, 255, 0, 100)) + "%)"); Serial.println("PWM Pin 9: " + String(slider1)); Serial.println("PWM Pin 10: " + String(slider2)); Serial.println("==================="); }

Ideas de Proyectos

Proyectos de Control de Iluminación

  • Control de brillo de la iluminación de la habitación
  • Interfaz de mezcla de colores RGB
  • Control de la velocidad de animación de la tira de LEDs
  • Control de la intensidad de la iluminación del escenario

Proyectos de control de motores

  • Control de la velocidad del robot
  • Regulación de la velocidad del ventilador
  • Control del caudal de la bomba
  • Velocidad de la cinta transportadora

Proyectos de audio

  • Interfaz de control de volumen
  • Control de tono y ecualizador
  • Intensidad de efectos de sonido
  • Control de visualización de música

Automatización del hogar

  • Control de climatización (intensidad de calefacción/refrigeración)
  • Control de la posición de la persiana
  • Control del caudal del sistema de riego
  • Brillo/volumen del dispositivo inteligente

Integración con otros ejemplos

Combinar con WebJoystick

Utiliza deslizadores para los límites de velocidad y un joystick para la dirección:

// Global speed limit from sliders int maxSpeed = 255; // In WebSlider callback webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { maxSpeed = slider1; // Use slider 1 as global speed limit }); // In WebJoystick callback webJoystickPage.onJoystickValueFromWeb([](int x, int y) { // Scale joystick values by slider-controlled speed limit int scaledX = map(x, -100, 100, -maxSpeed, maxSpeed); int scaledY = map(y, -100, 100, -maxSpeed, maxSpeed); controlRobot(scaledX, scaledY); });

Combinar con WebDigitalPins

Usa deslizadores para controlar la modulación por ancho de pulso (PWM) y pines digitales para encender/apagar:

webSliderPage.onSliderValueFromWeb([](int slider1, int slider2) { // Only apply PWM if corresponding digital pins are ON if (webDigitalPinsPage.getPinState(2)) { analogWrite(9, slider1); } else { analogWrite(9, 0); } if (webDigitalPinsPage.getPinState(3)) { analogWrite(10, slider2); } else { analogWrite(10, 0); } });

Próximos pasos

Después de dominar el ejemplo WebSlider, prueba:

  1. WebJoystick - Para control direccional en 2D
  2. WebDigitalPins - Para control discreto de encendido/apagado
  3. WebMonitor - Para depurar valores de deslizadores
  4. MultipleWebApps - Combinando deslizadores con otros controles

Soporte

Para obtener ayuda adicional:

  • Consulta la documentación de la API
  • Visita los tutoriales de DIYables: https://esp32io.com/tutorials/diyables-esp32-webapps
  • Foros de la comunidad ESP32

※ NUESTROS MENSAJES

  • No dude en compartir el enlace de este tutorial. Sin embargo, por favor no use nuestro contenido en otros sitios web. Hemos invertido mucho esfuerzo y tiempo en crear el contenido, ¡por favor respete nuestro trabajo!