LED parpadeando

OTA con LED parpadeando en el pin 13

#include <WiFi.h>
#include <WebServer.h>
#include <Update.h>

// Config WiFi
const char* ssid = "XXXXXXXX";
const char* password = "XXXXXXXX";

#define RELAY_PIN  13  // usa cualquier pin digital disponible

// IP fija (opcional)
IPAddress ip(192, 168, 1, 112);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);

WebServer server(80);

// HTML para la página OTA
const char* otaForm = R"rawliteral(
<!DOCTYPE html>
<html>
  <head>
    <title>ESP32 OTA Update</title>
    <meta charset="utf-8">
    <style>
      body { font-family: sans-serif; background-color: #f4f4f4; padding: 30px; }
      form { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px #ccc; }
      input[type="submit"] { padding: 10px 20px; }
    </style>
  </head>
  <body>
    <h2>ESP32 OTA Firmware Update</h2>
    <form method="POST" action="/update" enctype="multipart/form-data">
      <input type="file" name="update">
      <input type="submit" value="Subir firmware">
    </form>
  </body>
</html>
)rawliteral";

void handleRoot() {
  server.send(200, "text/html", "<h1>ESP32 OTA disponible en <a href='/update'>/update</a></h1>");
}

void handleUpdateForm() {
  server.sendHeader("Connection", "close");
  server.send(200, "text/html", otaForm);
}

void handleUpdateUpload() {
  HTTPUpload& upload = server.upload();

  if (upload.status == UPLOAD_FILE_START) {
    Serial.printf("\nIniciando actualización: %s\n", upload.filename.c_str());
    if (!Update.begin(UPDATE_SIZE_UNKNOWN)) {
      Update.printError(Serial);
    }
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
      Update.printError(Serial);
    }
    Serial.print(".");
  } else if (upload.status == UPLOAD_FILE_END) {
    if (Update.end(true)) {
      Serial.printf("\nActualización completa: %u bytes\n", upload.totalSize);
    } else {
      Update.printError(Serial);
    }
  }
  yield();
}

void handleUpdateFinished() {
  if (Update.hasError()) {
    server.send(200, "text/html", "<h1>❌ Fallo en la actualización</h1><p>Revisa la consola serie para más detalles.</p>");
  } else {
    server.send(200, "text/html", "<h1>✅ Actualización exitosa</h1><p>Reiniciando en 5 segundos...</p>");
    server.client().stop(); // cerrar conexión limpiamente
    delay(5000);
    ESP.restart();
  }
}

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW); // asegúrate de que esté apagado al inicio
  Serial.begin(115200);
  delay(1000);

  // WiFi
  WiFi.config(ip, gateway, subnet, dns);
  WiFi.begin(ssid, password);
  Serial.print("Conectando a WiFi");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWiFi conectado. IP: ");
  Serial.println(WiFi.localIP());

  // Rutas web
  server.on("/", handleRoot);
  server.on("/update", HTTP_GET, handleUpdateForm);
  server.on("/update", HTTP_POST, handleUpdateFinished, handleUpdateUpload);

  server.begin();
  Serial.println("Servidor web OTA iniciado");
}

void loop() {
  server.handleClient();

  Serial.println("Encendiendo Led");
  digitalWrite(RELAY_PIN, HIGH); // activa el relé
  delay(5000); // bomba encendida 5 segundos

  Serial.println("Apagando Led");
  digitalWrite(RELAY_PIN, LOW);  // desactiva el relé
  delay(5000); // bomba apagada 5 segundos
}

Encender LED desde página WEB

#include <WiFi.h>
#include <WebServer.h>
#include <Update.h>

// =================== HTMLS ===================

const char* mainPage = R"rawliteral(
<!DOCTYPE html>
<html>
  <head>
    <title>Control ESP32</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body { font-family: sans-serif; background-color: #f4f4f4; padding: 30px; max-width: 600px; margin: 0 auto; }
      .card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px #ccc; margin-bottom: 20px; }
      .btn { padding: 10px 20px; border: none; border-radius: 4px; color: white; font-size: 16px; cursor: pointer; transition: background-color 0.3s; }
      .btn-on { background-color: #4CAF50; }
      .btn-on:hover { background-color: #45a049; }
      .btn-off { background-color: #f44336; }
      .btn-off:hover { background-color: #d32f2f; }
      .btn-auto { background-color: #2196F3; }
      .btn-auto:hover { background-color: #0b7dda; }
      .status { padding: 10px; margin: 10px 0; border-radius: 4px; text-align: center; }
      .on { background-color: #dff0d8; color: #3c763d; }
      .off { background-color: #f2dede; color: #a94442; }
    </style>
    <script>
      function toggleLED() {
        fetch("/toggle").then(() => location.reload());
      }
      function toggleAuto() {
        fetch("/auto").then(() => location.reload());
      }
    </script>
  </head>
  <body>
    <h1>Control ESP32</h1>
    <div class="card">
      <h2>Control del LED</h2>
      <div class="status %LED_STATUS%">Estado actual: %LED_STATE%</div>
      <button class="btn %BTN_ON_CLASS%" onclick="toggleLED()">%BTN_TEXT%</button>
      <button class="btn btn-auto" onclick="toggleAuto()">%AUTO_TEXT%</button>
    </div>
    <div class="card">
      <h2>Actualización OTA</h2>
      <form method="POST" action="/update" enctype="multipart/form-data">
        <input type="file" name="update">
        <input type="submit" value="Actualizar firmware">
      </form>
    </div>
  </body>
</html>
)rawliteral";

const char* successPage = R"rawliteral(
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Actualización exitosa</title>
    <meta http-equiv="refresh" content="5;url=/" />
  </head>
  <body style="font-family: sans-serif; background-color: #f4f4f4; padding: 30px;">
    <div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px #ccc;">
      <h1>✅ Actualización exitosa</h1>
      <p>El ESP32 se reiniciará automáticamente en unos segundos...</p>
    </div>
  </body>
</html>
)rawliteral";


// Configuración WiFi
const char* ssid = "XXXXXX";
const char* password = "XXXXXXXX";

// IP estática (opcional)
IPAddress ip(192, 168, 1, 112);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);

#define RELAY_PIN 13

WebServer server(80);

bool ledState = false;
bool autoBlink = true;

unsigned long previousMillis = 0;
const unsigned long interval = 500;

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);

  WiFi.config(ip, gateway, subnet, dns);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(100);
  Serial.print("Conectado: "); Serial.println(WiFi.localIP());

  server.on("/", []() {
    String html = mainPage;
    html.replace("%LED_STATE%", ledState ? "ENCENDIDO" : "APAGADO");
    html.replace("%LED_STATUS%", ledState ? "on" : "off");
    html.replace("%BTN_TEXT%", ledState ? "Apagar" : "Encender");
    html.replace("%BTN_ON_CLASS%", ledState ? "btn-off" : "btn-on");
    html.replace("%AUTO_TEXT%", autoBlink ? "Auto: ON" : "Auto: OFF");
    server.send(200, "text/html; charset=utf-8", html);
  });

  server.on("/toggle", []() {
    ledState = !ledState;
    autoBlink = false;
    digitalWrite(RELAY_PIN, ledState);
    server.send(200, "text/plain", "OK");
  });

  server.on("/auto", []() {
    autoBlink = !autoBlink;
    server.send(200, "text/plain", "OK");
  });

  server.on("/update", HTTP_POST, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html; charset=utf-8", successPage);
    delay(2000);
    ESP.restart();
  }, []() {
    HTTPUpload& upload = server.upload();
    if (upload.status == UPLOAD_FILE_START) {
      Serial.printf("OTA iniciada: %s\n", upload.filename.c_str());
      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) Update.printError(Serial);
    } else if (upload.status == UPLOAD_FILE_WRITE) {
      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) Update.printError(Serial);
    } else if (upload.status == UPLOAD_FILE_END) {
      if (Update.end(true)) Serial.println("OTA finalizada correctamente");
      else Update.printError(Serial);
    }
  });

  server.begin();
}

void loop() {
  server.handleClient();

  if (autoBlink) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      ledState = !ledState;
      digitalWrite(RELAY_PIN, ledState);
    }
  }
}