DIYables ESP32 WebApps Biblioteca: Referencia de la API - Documentación completa

Visión general

La biblioteca ESP32 WebApps de DIYables proporciona una solución integral y modular para crear aplicaciones web basadas en WebSocket en ESP32. Incluye varias aplicaciones web preconstruidas y un marco flexible para crear aplicaciones personalizadas.

La biblioteca utiliza una arquitectura modular, en la que solo incluyes las aplicaciones web que necesitas, ahorrando memoria y mejorando el rendimiento.

Características

  • Arquitectura modular: Añade solo las aplicaciones web que necesites para optimizar el uso de la memoria
  • Uso eficiente de la memoria: Cada aplicación web puede habilitarse/deshabilitarse de forma independiente
  • Más de 11 aplicaciones web listas para usar: Control completo del ESP32 sin conocimientos de programación web
  • Framework de aplicaciones web personalizadas: Crea tus propias aplicaciones utilizando el sistema de clases base
  • Comunicación en tiempo real: Basada en WebSocket para actualizaciones instantáneas
  • Diseño responsivo: Funciona en ordenadores de escritorio, tabletas y dispositivos móviles
  • Integración fácil: API simple basada en callbacks
  • Soporte para múltiples aplicaciones: Permite añadir varias aplicaciones web de forma simultánea

Clases centrales

Servidor de Aplicación Web DIYables

La clase principal del servidor que gestiona las aplicaciones web, las solicitudes HTTP y la comunicación WebSocket.

Constructor

DIYablesWebAppServer(int httpPort = 80, int websocketPort = 81)

Crea una instancia de servidor de una aplicación web.

  • httpPort: Puerto del servidor HTTP (predeterminado: 80)
  • websocketPort: Puerto del servidor WebSocket (predeterminado: 81)

Métodos

Configuración y Conexión
bool begin()

Inicializa la conexión de red (para Ethernet o conexiones preconfiguradas) y inicia el servidor web.

  • Devuelve: verdadero si tiene éxito, falso si falla
  • Caso de uso: para soporte Ethernet en el futuro o cuando las credenciales de WiFi estén preconfiguradas
bool begin(const char* ssid, const char* password)

Inicializa la conexión WiFi y inicia el servidor web.

  • ssid: nombre de la red WiFi
  • password: contraseña de WiFi
  • Devuelve: true si tiene éxito, false si falla
  • Caso de uso: Conexión WiFi estándar con credenciales
void loop()

Gestiona las solicitudes HTTP y la comunicación WebSocket. Debe ser llamado en el bucle principal.

bool isConnected()

Devuelve verdadero si el WiFi está conectado.

String getIPAddress()

Devuelve la dirección IP del Arduino como una cadena.

Gestión de Aplicaciones
void addApp(DIYablesWebAppPageBase* app)

Agrega una aplicación web al servidor.

  • app: puntero a una instancia de una aplicación web
void removeApp(const String& path)

Elimina una aplicación web por su ruta URL.

  • ruta: ruta de la URL de la aplicación (p. ej., "/chat")
DIYablesWebAppPageBase* getApp(const String& path)

Obtiene una aplicación web por su ruta de URL.

  • ruta: ruta URL de la aplicación
  • Devuelve: puntero a la aplicación o nullptr si no se encuentra
void setNotFoundPage(const DIYablesNotFoundPage& page)

Configura la página de error 404 (opcional).

  • página: instancia de página 404
Acceso a Aplicaciones Especializadas
DIYablesWebDigitalPinsPage* getWebDigitalPinsPage()

Obtiene la instancia de la página de pines digitales si se ha agregado.

  • Devuelve: Puntero a la página de pines digitales o nullptr
DIYablesWebSliderPage* getWebSliderPage()

Obtiene la instancia de la página del slider si se ha agregado.

  • Devuelve: puntero a la página del control deslizante o nullptr
DIYablesWebJoystickPage* getWebJoystickPage()

Obtiene la instancia de la página del joystick si se ha añadido.

  • Devuelve: puntero a la página del joystick o nullptr

Clases base

Base de la página de la aplicación web DIYables

Clase base abstracta de la que heredan todas las aplicaciones web. Proporciona funcionalidades comunes para el manejo de HTTP, la comunicación por WebSocket y la gestión de páginas.

Constructor

DIYablesWebAppPageBase(const String& pagePath)

Crea una instancia de página base con la ruta URL especificada.

  • pagePath: ruta URL de la página (p. ej., "/web-joystick")

Métodos virtuales (Deben ser implementados por las clases derivadas)

virtual void handleHTTPRequest(IWebClient& client) = 0

Gestiona las solicitudes HTTP para esta página. Método virtual puro.

  • cliente: Interfaz de cliente web para enviar la respuesta
virtual void handleWebSocketMessage(IWebSocket& ws, const char* message, uint16_t length) = 0

Gestiona los mensajes de WebSocket para esta página. Método virtual puro.

  • ws: Interfaz de conexión WebSocket
  • message: Contenido del mensaje recibido
  • length: Longitud del mensaje
virtual const char* getPageInfo() const = 0

Devuelve la cadena de identificación de la página utilizada en la visualización de la información de la conexión. Método virtual puro.

  • Devuelve: Cadena de información de la página (p. ej., "🕹️ Joystick web: ")
virtual String getNavigationInfo() const = 0

Devuelve HTML para el botón de navegación de la página de inicio. Método virtual puro.

  • Devuelve: cadena HTML para la tarjeta de navegación

Métodos virtuales (sobrescrituras opcionales)

virtual void onWebSocketConnection(IWebSocket& ws)

Se llama cuando se establece una nueva conexión WebSocket.

  • ws: Nueva conexión WebSocket
virtual void onWebSocketClose(IWebSocket& ws)

Llamado cuando se cierra una conexión WebSocket.

  • ws: Conexión WebSocket cerrada

Métodos comunes

const char* getPagePath() const

Obtiene la ruta de la URL de esta página.

  • Devuelve: Cadena de la ruta de la página
bool isEnabled() const

Comprueba si la página está actualmente habilitada.

  • Devuelve: verdadero si está habilitado, falso si está deshabilitado
void setEnabled(bool enable)

Habilita o deshabilita la página.

  • habilitar: verdadero para habilitar, falso para deshabilitar

Métodos utilitarios

void sendHTTPHeader(IWebClient& client, const char* contentType = "text/html")

Envía cabeceras HTTP estándar al cliente.

  • cliente: Interfaz de cliente web
  • tipo de contenido: tipo MIME (predeterminado: "text/html")
void sendWebSocketMessage(IWebSocket& ws, const char* message)

Envía un mensaje a un cliente WebSocket específico.

  • ws: Conexión WebSocket de destino
  • message: Mensaje a enviar
void broadcastToAllClients(const char* message)

Transmite un mensaje a todos los clientes WebSocket conectados.

  • mensaje: Mensaje para difundir
void sendLargeHTML(IWebClient& client, const char* html)

Envía contenido HTML grande utilizando la codificación de transferencia por trozos.

  • cliente: Interfaz de cliente web
  • html: Contenido HTML para enviar

Ejemplo de uso

class CustomPage : public DIYablesWebAppPageBase { public: CustomPage() : DIYablesWebAppPageBase("/custom") {} void handleHTTPRequest(IWebClient& client) override { sendHTTPHeader(client); client.println("<html><body>Custom Page</body></html>"); } void handleWebSocketMessage(IWebSocket& ws, const char* message, uint16_t length) override { // Handle WebSocket messages sendWebSocketMessage(ws, "Response: " + String(message)); } const char* getPageInfo() const override { return " 🔧 Custom Page: "; } String getNavigationInfo() const override { return "<a href=\"/custom\" class=\"app-card custom\">" "<h3>🔧 Custom</h3><p>Custom functionality</p></a>"; } };

Clases de aplicaciones web

Página de inicio de DIYables

Centro de navegación central que ofrece enlaces a todas las aplicaciones habilitadas.

Constructor

DIYablesHomePage()

Ruta URL

  • Ruta: / (raíz)

Página de chat web de DIYables

Interfaz de chat interactiva para la comunicación bidireccional con Arduino.

Constructor

DIYablesWebChatPage()

Ruta URL

  • Ruta: /webchat

Métodos

void onWebChatMessage(std::function<void(const String&)> callback)

Establece la función de devolución de llamada para los mensajes de chat entrantes.

void sendToWebChat(const String& message)

Envía un mensaje a la interfaz de chat web.

Página de monitoreo web de DIYables

Monitor serial basado en la web para salida en tiempo real y entrada de comandos.

Constructor

DIYablesWebMonitorPage()

Ruta de la URL

  • Ruta: /webmonitor

Métodos

void onWebMonitorMessage(std::function<void(const String&)> callback)

Configura la función de devolución de llamada para los mensajes entrantes del monitor.

void sendToWebMonitor(const String& message)

Envía un mensaje a la interfaz de monitoreo web.

DIYablesWebDigitalPinsPage

Controlar y monitorear los pines digitales del 0 al 13 a través de una interfaz web.

Constructor

DIYablesWebDigitalPinsPage()

Ruta de la URL

  • Ruta: /webdigitalpins

Métodos

void enablePin(int pin, int mode)

Habilita un PIN para el control web.

  • pin: Número de pin (0-13)
  • mode: WEB_PIN_OUTPUT o WEB_PIN_INPUT
void onPinWrite(std::function<void(int, int)> callback)

Configura una función de devolución de llamada para las operaciones de escritura de pines (pines de salida).

void onPinRead(std::function<int(int)> callback)

Establece una función de devolución de llamada para las operaciones de lectura de pines (pines de entrada).

void onPinModeChange(std::function<void(int, int)> callback)

Establece una función de devolución de llamada para cambios en el modo del pin.

void updatePinState(int pin, int state)

Actualiza el estado del pin en tiempo real para clientes web.

Página de deslizador web de DIYables

Control deslizante dual para aplicaciones analógicas y PWM.

Constructor

DIYablesWebSliderPage()

Ruta de la URL

  • Ruta: /webslider

Métodos

void onSliderValueFromWeb(std::function<void(int, int)> callback)

Establece la función de devolución de llamada para los cambios en el valor del deslizador desde la web.

  • Parámetros: slider1 (0-255), slider2 (0-255)
void onSliderValueToWeb(std::function<void()> callback)

Configura una devolución de llamada para el cliente web que solicita valores actuales.

void sendToWebSlider(int slider1, int slider2)

Envía los valores del deslizador a la interfaz web.

Página web del joystick de DIYables

Control de joystick 2D para robótica y aplicaciones de posicionamiento.

Constructor

DIYablesWebJoystickPage(bool autoReturn = true, float sensitivity = 10.0)
  • autoReturn: Si el joystick vuelve al centro automáticamente
  • sensitivity: Porcentaje mínimo de movimiento para activar actualizaciones

Ruta de la URL

  • Ruta: /webjoystick

Métodos

void onJoystickValueFromWeb(std::function<void(int, int)> callback)

Establece la función de devolución de llamada para el movimiento del joystick desde la web.

  • Parámetros: x (-100 a 100), y (-100 a 100)
void onJoystickValueToWeb(std::function<void()> callback)

Configura la función de devolución de llamada para el cliente web que solicita la posición actual.

void sendToWebJoystick(int x, int y)

Envía la posición del joystick a la interfaz web.

void setAutoReturn(bool autoReturn)

Establece el comportamiento de retorno automático.

void setSensitivity(float sensitivity)

Establece la sensibilidad de movimiento (porcentaje).

Página del Plotter Web de DIYables

Visualización de datos en tiempo real con soporte para múltiples series de datos.

Constructor

DIYablesWebPlotterPage()

Ruta de la URL

  • Ruta: /webplotter

Métodos

void setPlotTitle(const String& title)

Establece el título del gráfico.

void setAxisLabels(const String& xLabel, const String& yLabel)

Establece las etiquetas de los ejes.

void enableAutoScale(bool enable)

Activa o desactiva la escala automática del eje Y.

void setMaxSamples(int maxSamples)

Establece el número máximo de puntos de datos que se mostrarán.

void addDataPoint(const String& seriesName, float x, float y)

Añade un punto de datos a una serie.

void clearPlot()

Borra todos los datos del gráfico.

Página no encontrada de DIYables

Página de error 404 opcional para una mejor experiencia de usuario.

Constructor

DIYablesNotFoundPage()

Ejemplo de uso básico

#include <DIYablesWebApps.h> // WiFi credentials const char* ssid = "YOUR_WIFI_SSID"; const char* password = "YOUR_WIFI_PASSWORD"; // Create server and web applications DIYablesWebAppServer webAppsServer(80, 81); DIYablesHomePage homePage; DIYablesWebChatPage chatPage; DIYablesWebMonitorPage monitorPage; void setup() { Serial.begin(9600); // Add only the applications you need webAppsServer.addApp(&homePage); webAppsServer.addApp(&chatPage); webAppsServer.addApp(&monitorPage); // Optional: Add 404 page webAppsServer.setNotFoundPage(DIYablesNotFoundPage()); // Start server if (webAppsServer.begin(ssid, password)) { Serial.println("Server started successfully"); Serial.print("IP: "); Serial.println(webAppsServer.getIPAddress()); } // Setup callbacks chatPage.onWebChatMessage([](const String& message) { Serial.println("Chat: " + message); chatPage.sendToWebChat("Arduino received: " + message); }); } void loop() { webAppsServer.loop(); delay(10); }

Visión general de las aplicaciones web

Página de Inicio

  • URL: http://[esp32-ip]/
  • Propósito: Centro de navegación central
  • Características: Enlaces a todas las aplicaciones habilitadas, estado de conexión

Aplicación de WebChat

  • URL: http://[esp32-ip]/webchat
  • Propósito: Interfaz de comunicación bidireccional
  • Características: Mensajería en tiempo real, historial de mensajes, estado de WebSocket

Monitor web

  • URL: http://[esp32-ip]/webmonitor
  • Propósito: Reemplazo del monitor serial
  • Características: Salida serial en tiempo real, entrada de comandos, tema oscuro

Control de pines digitales en la web

  • URL: http://[esp32-ip]/webdigitalpins
  • Propósito: Control de pines digitales 0-13
  • Características: Control individual de pines, operaciones en lote, estado en tiempo real

Control deslizante web

  • URL: http://[esp32-ip]/webslider
  • Propósito: Control analógico/PWM dual
  • Características: Dos deslizadores independientes (0-255), valores predefinidos, retroalimentación en tiempo real

Control de Joystick Web

  • URL: http://[esp32-ip]/webjoystick
  • Propósito: control de posición 2D para robots/vehículos
  • Características: control táctil y de ratón, visualización de coordenadas, ajuste de sensibilidad

Trazador Web

  • URL: http://[esp32-ip]/webplotter
  • Propósito: Visualización de datos en tiempo real
  • Características: Varias series de datos, autoescalado, títulos y ejes configurables

Comunicación WebSocket

Todas las aplicaciones utilizan WebSocket en el puerto 81 para la comunicación en tiempo real:

  • URL de WebSocket: ws://[esp32-ip]:81
  • Conexión: Reconexión automática ante la desconexión
  • Protocolo: Formato de mensaje basado en texto

Formatos de mensajes

Mensajes de WebChat

  • Desde la web: mensaje de texto directo
  • A la web: mensaje de texto directo

Mensajes del Monitor Web

  • Desde la Web: Mensaje de texto directo
  • Para la Web: Mensaje de texto directo

Mensajes PIN Digital de la Web

  • Desde la web: Formato JSON: {"pin": 13, "state": 1}
  • A la web: Formato JSON: {"pin": 13, "state": 1}

Mensajes del control deslizante web

  • Desde la Web: formato JSON: {"slider1": 128, "slider2": 255}
  • A la Web: formato JSON: {"slider1": 128, "slider2": 255}

Mensajes del Joystick Web

  • Desde la web: Formato JSON: {"x": 50, "y": -25}
  • Para la web: Formato JSON: {"x": 50, "y": -25}

Mensajes del Plotter Web

  • Desde la Web: No aplica (solo visualización)
  • Para la Web: Formato JSON: {"series": "temp", "x": 10.5, "y": 23.4}

Manejo de errores

La biblioteca incluye manejo automático de errores para:

  • Fallos de la conexión WiFi
  • Desconexiones de WebSocket
  • Formatos de mensajes no válidos
  • Límites de conexión de clientes

Uso de memoria

Beneficios de la Arquitectura Modular: Incluya solo las aplicaciones web que necesite para optimizar el uso de la memoria.

Uso de memoria aproximado por componente:

  • DIYablesWebAppServer: ~8KB de Flash, ~2KB de RAM
  • DIYablesHomePage: ~3KB de Flash, ~1KB de RAM
  • DIYablesWebChatPage: ~6KB de Flash, ~1.5KB de RAM
  • DIYablesWebMonitorPage: ~5KB de Flash, ~1.5KB de RAM
  • DIYablesWebDigitalPinsPage: ~8KB de Flash, ~2KB de RAM
  • DIYablesWebSliderPage: ~6KB de Flash, ~1.5KB de RAM
  • DIYablesWebJoystickPage: ~7KB de Flash, ~1.5KB de RAM
  • DIYablesWebPlotterPage: ~10KB de Flash, ~2KB de RAM
  • WebSocket Buffer: ~1KB de RAM por conexión

Total si se activan todas las apps: ~53KB Flash, ~12KB RAM

Configuración mínima (servidor + hogar + 1 aplicación): ~17KB de Flash, ~4.5KB de RAM

Compatibilidad del navegador

Navegadores compatibles:

  • Chrome 50+
  • Firefox 45+
  • Safari 10+
  • Edge 79+
  • Navegadores móviles (iOS Safari, Chrome Móvil)

Notas de Seguridad

  • No hay autenticación implementada (solo para redes locales)
  • Utilícelo solo en redes de confianza
  • Considere añadir autenticación para implementaciones públicas

Solución de problemas

Problemas comunes

  1. No se puede conectar a Wi-Fi
  • Verificar el SSID y la contraseña
  • Verificar que la red sea de 2,4 GHz (no 5 GHz)
  • Comprobar la intensidad de la señal
  1. La conexión WebSocket falla
  • Verifique que la dirección IP sea correcta
  • Verificar la configuración del cortafuegos.
  • Prueba con otro navegador
  1. Alto consumo de memoria
  • Desactivar las aplicaciones no utilizadas
  • Límite de conexiones simultáneas
  • Reiniciar el ESP32 si se produce fragmentación de la memoria.
  1. Respuesta lenta
  • Ver la intensidad de la señal WiFi
  • Reducir la frecuencia de mensajes de WebSocket
  • Usa funciones de devolución de llamada más cortas

Proyectos de ejemplo

Ejemplos de aplicaciones

La biblioteca ESP32 WebApps de DIYables incluye ejemplos completos diseñados para la plataforma educativa ESP32:

Ejemplos disponibles

  • Ejemplo de chat: Interfaz de comunicación bidireccional
  • Ejemplo de WebMonitor: Reemplazo del monitor serie con características mejoradas
  • Ejemplo de WebDigitalPins: Controlar todos los pines digitales con retroalimentación visual
  • Ejemplo de WebSlider: Control analógico/PWM dual con preajustes
  • Ejemplo de WebJoystick: Control de posición 2D para proyectos de robótica
  • Ejemplo de MultipleWebApps: Todas las aplicaciones funcionando simultáneamente

Consulte la carpeta examples/ para proyectos completos y la carpeta docs/ para instrucciones detalladas de configuración.

Interfaces de Abstracción de Plataforma

La biblioteca DIYables ESP32 WebApps utiliza una capa de abstracción de plataforma con interfaces que permiten soporte para múltiples plataformas de hardware. Estas interfaces separan la funcionalidad central de WebApp de las implementaciones específicas de la plataforma.

Interfaces principales

IWebClient

Interfaz para conexiones de cliente HTTP.

class IWebClient { public: virtual ~IWebClient() = default; // Stream interface methods virtual int available() = 0; virtual int read() = 0; virtual int peek() = 0; virtual size_t write(uint8_t data) = 0; virtual size_t write(const uint8_t* buffer, size_t size) = 0; virtual void flush() = 0; // Connection management virtual bool connected() = 0; virtual void stop() = 0; // Convenience methods virtual void print(const String& str) = 0; virtual void println(const String& str) = 0; };

IWebSocket

Interfaz para conexiones WebSocket con soporte de comunicación bidireccional.

class IWebSocket { public: enum DataType { TEXT = 1, BINARY = 2 }; enum CloseCode { NORMAL_CLOSURE = 1000, GOING_AWAY = 1001, PROTOCOL_ERROR = 1002, UNSUPPORTED_DATA = 1003, POLICY_VIOLATION = 1008, MESSAGE_TOO_BIG = 1009, INTERNAL_ERROR = 1011 }; virtual ~IWebSocket() = default; // Message handling virtual void sendText(const char* message) = 0; virtual void sendBinary(const uint8_t* data, size_t length) = 0; virtual bool isConnected() const = 0; virtual void close(CloseCode code = NORMAL_CLOSURE, const char* reason = nullptr) = 0; // Event callbacks virtual void onMessage(std::function<void(IWebSocket*, DataType, const char*, uint16_t)> callback) = 0; virtual void onClose(std::function<void(IWebSocket*, CloseCode, const char*, uint16_t)> callback) = 0; };

IWebServer

Interfaz para la funcionalidad del servidor HTTP.

class IWebServer { public: virtual ~IWebServer() = default; // Server lifecycle virtual bool begin() = 0; virtual void stop() = 0; virtual IWebClient* available() = 0; // Configuration virtual void setPort(uint16_t port) = 0; virtual uint16_t getPort() const = 0; };

IWebSocketServer

Interfaz para un servidor WebSocket con gestión de conexiones.

class IWebSocketServer { public: using ConnectionCallback = std::function<void(IWebSocket*)>; using MessageCallback = std::function<void(IWebSocket*, IWebSocket::DataType, const char*, uint16_t)>; virtual ~IWebSocketServer() = default; // Server lifecycle virtual bool begin() = 0; virtual void stop() = 0; virtual void listen() = 0; // Event handling virtual void onConnection(ConnectionCallback callback) = 0; virtual void onMessage(MessageCallback callback) = 0; // Broadcasting virtual void broadcastText(const char* message) = 0; virtual void broadcastBinary(const uint8_t* data, size_t length) = 0; // Configuration virtual void setPort(uint16_t port) = 0; virtual uint16_t getPort() const = 0; };

IProveedorDeRed

Interfaz para la gestión de la conectividad de red.

class INetworkProvider { public: virtual ~INetworkProvider() = default; // Network lifecycle virtual bool begin(const char* ssid, const char* password) = 0; virtual void end() = 0; virtual bool isConnected() = 0; // Network information virtual String getLocalIP() = 0; virtual String getSSID() = 0; virtual int32_t getRSSI() = 0; };

IServerFactory

Interfaz de fábrica para crear implementaciones específicas de la plataforma.

class IServerFactory { public: virtual ~IServerFactory() = default; // Factory methods virtual INetworkProvider* createNetworkProvider() = 0; virtual IWebServer* createWebServer(uint16_t port) = 0; virtual IWebSocketServer* createWebSocketServer(uint16_t port) = 0; // Platform information virtual String getPlatformName() const = 0; };

Ejemplo de implementación de la plataforma

Para ESP32, las interfaces están implementadas utilizando la biblioteca DIYables_ESP32_WebServer:

class ESP32ServerFactory : public IServerFactory { public: INetworkProvider* createNetworkProvider() override { return new ESP32NetworkProvider(); } IWebServer* createWebServer(uint16_t port) override { return new ESP32WebServer(port); } IWebSocketServer* createWebSocketServer(uint16_t port) override { return new ESP32WebSocketServer(port); } String getPlatformName() const override { return "ESP32"; } };

Añadiendo Soporte para Nuevas Plataformas

Para añadir soporte a una nueva plataforma (p. ej., ESP32):

  1. Implementa todas las interfaces para la plataforma objetivo
  2. Crea un ServerFactory que instancie tus implementaciones
  3. Gestiona la conectividad de red específica de la plataforma y los protocolos WebSocket
  4. Prueba con las clases WebApp existentes (no se requieren cambios)

Ejemplos de uso con diferentes plataformas:

ESP32ServerFactory factory; DIYablesWebAppServer server(factory, 80, 81); // ESP32 (hypothetical) ESP32ServerFactory esp32Factory; DIYablesWebAppServer esp32Server(esp32Factory, 80, 81);

Beneficios del diseño basado en interfaces

  • Independencia de la plataforma: La lógica central de WebApp funciona en cualquier plataforma
  • Extensibilidad: Es fácil añadir soporte para nuevo hardware
  • Mantenibilidad: El código específico de la plataforma está aislado
  • Testabilidad: Las interfaces pueden ser simuladas para pruebas unitarias
  • Consistencia: La misma API en todas las plataformas compatibles

Soporte actual de la plataforma

  • ESP32: Totalmente implementado y probado
  • 🔄 ESP32: Disponible como extensión independiente - DIYables_WebApps_ESP32
  • 🚀 Plataformas futuras: Se pueden añadir utilizando el mismo patrón de interfaz

※ 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!