Herramientas de usuario

Herramientas del sitio


control_de_un_jardin_con_piscina_con_esp32

Control de un jardín con piscina con ESP32

#include <WiFi.h>
#include <WiFiMulti.h>
#include <WebServer.h>
#include <ESP32Servo.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <ESPmDNS.h>
#include <time.h>
 
// --- CONFIGURACIÓN DE REDES ---
WiFiMulti wifiMulti;
const char* ssid1 = "Nombre del WiFi Principal";
const char* pass1 = "Clave del WiFi principal";
const char* ssid2 = "Nombre del WiFi secundario";
const char* pass2 = "Clave del WiFi secundario";
const char* usuarioSeguro = "admin"; // Usuario
const char* passwordSegura = "1234"; // Contraseña
 
// --- CONFIGURACIÓN NTP (Hora de Internet) ---
const char* ntpServer = "pool.ntp.org";
const char* timeZone = "CET-1CEST,M3.5.0,M10.5.0/3"; 
 
// --- ASIGNACIÓN DE PINES ---
const int pinesCanales[] = {13, 14, 27, 26, 16, 33}; 
const int pinValvulaMaestra = 32;
const int pinLuces = 23;             
const int pinDepuradora = 19;
const int pinServo = 18;
const int pinLDR = 35;           
const int pinRelayPresion = 4;      
const int pinSensorPresion = 34;    
 
// --- CONFIGURACIÓN DEL DISPLAY Y SERVO ---
LiquidCrystal_I2C lcd(0x27, 16, 2); 
Servo miServo;
const int posReposo = 0;   
const int posPresion = 20; 
unsigned long tiempoServoPulsado = 0;
bool servoEnMovimiento = false;
 
// Variables para clonar el texto del LCD a la Web
String lcdLinea1 = "";
String lcdLinea2 = "";
 
// --- VARIABLES DE ESTADO ---
bool estados[8] = {false, false, false, false, false, false, false, false}; 
bool hayLuz = false; 
bool riegoEnProgreso = false;
unsigned long tiempoFinAccesorios[2] = {0, 0}; 
int canalesParaRegar[6], totalCanalesRiego = 0, indiceRiegoActual = -1;
unsigned long tiempoInicioZona = 0, duracionZonaMs = 0;
 
// --- CONTADORES DE TIEMPO POR CANAL Y ACCESORIOS (SEGUNDOS DE USO DIARIO) ---
// Índices: 0-5 = Canales C1-C6, 6 = Luz, 7 = Depuradora
unsigned long tiempoUsoSegundos[8] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned long ultimoCalculoUso[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int ultimoDiaMilitar = -1; 
 
float ultimaPresion = 0.0;
bool midiendoPresion = false;
unsigned long tiempoInicioMedida = 0; 
const unsigned long TIEMPO_ESPERA_PRESION = 1500; 
 
unsigned long ultimaRotacion = 0;
int pantallaActual = 0;
const int intervaloRotacion = 5000; 
unsigned long ultimaVezCheckWiFi = 0;
const unsigned long intervaloCheckWiFi = 15000; 
unsigned long ultimaActualizacionLCD = 0;
 
WebServer server(80);
 
// --- FUNCIONES DE HARDWARE Y CONTADORES ---
 
void actualizarHardware() {
  bool algunRiegoActivo = false;
  unsigned long ahora = millis();
 
  for (int i = 0; i < 6; i++) {
    digitalWrite(pinesCanales[i], estados[i] ? LOW : HIGH);
    if (estados[i]) {
      algunRiegoActivo = true;
      if (ultimoCalculoUso[i] == 0) ultimoCalculoUso[i] = ahora; 
    } else {
      if (ultimoCalculoUso[i] > 0) {
        tiempoUsoSegundos[i] += (ahora - ultimoCalculoUso[i]) / 1000;
        ultimoCalculoUso[i] = 0;
      }
    }
  }
 
  digitalWrite(pinValvulaMaestra, (algunRiegoActivo || riegoEnProgreso) ? LOW : HIGH);
 
  // Luz (Índice 6)
  digitalWrite(pinLuces, estados[6] ? LOW : HIGH);
  if (estados[6]) {
    if (ultimoCalculoUso[6] == 0) ultimoCalculoUso[6] = ahora;
  } else {
    if (ultimoCalculoUso[6] > 0) {
      tiempoUsoSegundos[6] += (ahora - ultimoCalculoUso[6]) / 1000;
      ultimoCalculoUso[6] = 0;
    }
  }
 
  // Depuradora (Índice 7)
  digitalWrite(pinDepuradora, estados[7] ? LOW : HIGH);
  if (estados[7]) {
    if (ultimoCalculoUso[7] == 0) ultimoCalculoUso[7] = ahora;
  } else {
    if (ultimoCalculoUso[7] > 0) {
      tiempoUsoSegundos[7] += (ahora - ultimoCalculoUso[7]) / 1000;
      ultimoCalculoUso[7] = 0;
    }
  }
 
  if (midiendoPresion) {
    digitalWrite(pinRelayPresion, LOW); 
  } else {
    digitalWrite(pinRelayPresion, HIGH);
  }
}
 
void actualizarContadoresTiempo() {
  unsigned long ahora = millis();
  for (int i = 0; i < 8; i++) {
    if (estados[i] && ultimoCalculoUso[i] > 0) {
      unsigned long transcurrido = (ahora - ultimoCalculoUso[i]) / 1000;
      if (transcurrido >= 1) {
        tiempoUsoSegundos[i] += transcurrido;
        ultimoCalculoUso[i] = ahora;
      }
    }
  }
 
  struct tm timeinfo;
  if (getLocalTime(&timeinfo)) {
    if (ultimoDiaMilitar == -1) {
      ultimoDiaMilitar = timeinfo.tm_mday;
    } else if (ultimoDiaMilitar != timeinfo.tm_mday) {
      for (int i = 0; i < 8; i++) {
        tiempoUsoSegundos[i] = 0;
        if (estados[i]) ultimoCalculoUso[i] = ahora;
      }
      ultimoDiaMilitar = timeinfo.tm_mday;
      // Serial.println("Contadores reseteados a las 00:00");
    }
  }
}
 
void realizarLecturaPresion() {
  long suma = 0;
  for(int i=0; i<25; i++) {
    suma += analogRead(pinSensorPresion);
    delay(2);
  }
  float promedio = suma / 25.0;
  float voltaje = promedio * (3.3 / 4095.0);
  ultimaPresion = (voltaje - 0.5) * (12.0 / 4.0); 
  if (ultimaPresion < 0) ultimaPresion = 0;
}
 
void imprimirLinea(int fila, String texto) {
  while (texto.length() < 16) texto += " ";
  if (texto.length() > 16) texto = texto.substring(0, 16);
 
  lcd.setCursor(0, fila);
  lcd.print(texto);
 
  if (fila == 0) lcdLinea1 = texto;
  else if (fila == 1) lcdLinea2 = texto;
}
 
String obtenerHoraFormateada() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) return "Sincronizando..";
  char buffer[16];
  strftime(buffer, sizeof(buffer), "%H:%M:%S", &timeinfo);
  return String(buffer);
}
 
String obtenerFechaFormateada() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) return "--/--/----";
  char buffer[16];
  strftime(buffer, sizeof(buffer), "%d/%m/%Y", &timeinfo);
  return String(buffer);
}
 
void actualizarLCD() {
  unsigned long ahora = millis();
  if (servoEnMovimiento) {
    imprimirLinea(0, "EJECUTANDO:");
    imprimirLinea(1, "PULSACION SERVO");
    return;
  }
  if (midiendoPresion) {
    imprimirLinea(0, "MIDIENDO...");
    imprimirLinea(1, "RELE 8 ACTIVO");
    return;
  }
 
  bool mostrarRiego = (riegoEnProgreso && indiceRiegoActual >= 0);
  bool mostrarLuz = estados[6];
  bool mostrarDep = estados[7];
  bool mostrarManual = (!riegoEnProgreso && (estados[0]||estados[1]||estados[2]||estados[3]||estados[4]||estados[5]));
  bool mostrarPresion = (ultimaPresion > 0.05);
 
  int activas = 1; 
  if (mostrarRiego) activas++;
  if (mostrarLuz) activas++;
  if (mostrarDep) activas++;
  if (mostrarManual) activas++;
  if (mostrarPresion) activas++;
 
  if (ahora - ultimaRotacion >= intervaloRotacion) {
    ultimaRotacion = ahora;
    pantallaActual++;
  }
  int vista = pantallaActual % activas;
  int contadorVista = 0;
 
  if (contadorVista == vista) {
    imprimirLinea(0, "HORA: " + obtenerHoraFormateada());
    imprimirLinea(1, "FECHA:" + obtenerFechaFormateada());
    return;
  }
  contadorVista++;
 
  if (mostrarRiego) {
    if (contadorVista == vista) {
      imprimirLinea(0, "RIEGO: Zona C" + String(canalesParaRegar[indiceRiegoActual] + 1));
      unsigned long r = (duracionZonaMs > (ahora - tiempoInicioZona)) ? (duracionZonaMs - (ahora - tiempoInicioZona)) / 1000 : 0;
      imprimirLinea(1, "Restan: " + String(r) + " seg");
      return;
    }
    contadorVista++;
  }
  if (mostrarPresion) {
    if (contadorVista == vista) {
      imprimirLinea(0, "PRESION RED:");
      imprimirLinea(1, String(ultimaPresion, 2) + " BAR");
      return;
    }
    contadorVista++;
  }
  if (mostrarLuz) {
    if (contadorVista == vista) {
      imprimirLinea(0, "ACC: LUZ ON");
      unsigned long rest = (tiempoFinAccesorios[0] > ahora) ? (tiempoFinAccesorios[0] - ahora) / 1000 : 0;
      imprimirLinea(1, "Off: " + String(rest / 60) + "m " + String(rest % 60) + "s");
      return;
    }
    contadorVista++;
  }
  if (mostrarDep) {
    if (contadorVista == vista) {
      imprimirLinea(0, "ACC: DEPURAD. ON");
      unsigned long rest = (tiempoFinAccesorios[1] > ahora) ? (tiempoFinAccesorios[1] - ahora) / 1000 : 0;
      imprimirLinea(1, "Off: " + String(rest / 60) + "m " + String(rest % 60) + "s");
      return;
    }
    contadorVista++;
  }
  if (mostrarManual) {
    if (contadorVista == vista) {
      imprimirLinea(0, "ZONAS MANUALES:");
      String lista = "";
      for(int i=0; i<6; i++) { if(estados[i]) lista += String(i+1) + " "; }
      imprimirLinea(1, lista);
    }
  }
}
 
void detenerTodo() {
  riegoEnProgreso = false;
  indiceRiegoActual = -1;
  midiendoPresion = false;
  digitalWrite(pinRelayPresion, HIGH);
  for (int i = 0; i < 8; i++) estados[i] = false;
  tiempoFinAccesorios[0] = 0;
  tiempoFinAccesorios[1] = 0;
  actualizarHardware();
}
 
// --- INTERFAZ WEB ---
const char PAGE_HTML[] PROGMEM = R"=====(
<!DOCTYPE html>
<html lang='es'>
<head>
    <meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>
    <title>Control de Riego</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: -apple-system, sans-serif; background: #f0f2f5; padding: 10px; font-size: 14px; }
        h1 { text-align: center; color: #0056b3; font-size: 20px; margin: 10px 0; }
        .card { background: white; padding: 12px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 10px; position: relative; }
        h2 { font-size: 15px; margin-bottom: 8px; color: #0056b3; border-bottom: 1px solid #eee; padding-bottom: 4px; }
        .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
        button { padding: 10px 2px; cursor: pointer; border: 1px solid #ddd; border-radius: 6px; background: #f8f9fa; font-weight: bold; font-size: 11px; }
        button.active { background: #d9534f; color: white; border-color: #c9302c; }
        .special-btn { min-width: 100px; padding: 14px 5px; font-size: 11px; }
        .overlay { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; border-radius: 10px; align-items: center; justify-content: center; font-weight: bold; color: #d9534f; }
        .sensor-container { display: flex; gap: 8px; margin-top: 5px; }
        .btn-servo { width: 66%; background: #6f42c1; color: white; border: none; padding: 14px 5px; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 12px; }
        .sensor-status { width: 34%; pointer-events: none; padding: 14px 5px; border-radius: 6px; border: 1px solid #ddd; font-weight: bold; text-align: center; background: #f8f9fa; color: #6c757d; font-size: 12px; display: flex; align-items: center; justify-content: center; }
        .status-active { background: #28a745; color: white; border-color: #1e7e34; }
        .row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
        .time-label { min-width: 45px; font-size: 12px; font-weight: bold; text-align: right; }
        .riego-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; text-align: left; margin: 5px 0; }
        .riego-item { display: flex; align-items: center; gap: 8px; font-weight: bold; font-size: 13px; padding: 5px 0; }
        input[type="checkbox"] { width: 22px; height: 22px; cursor: pointer; }
        .btn-main { background: #007bff; color: white; border: none; width: 100%; padding: 14px; margin-top: 10px; border-radius: 6px; font-weight: bold; font-size: 14px; }
        .btn-stop { background: #ff0000; color: white; border: none; width: 100%; padding: 16px; border-radius: 6px; font-weight: 800; font-size: 16px; box-shadow: 0 4px #b30000; }
        .btn-presion { background: #17a2b8; color: white; border: none; width: 66%; padding: 14px 5px; border-radius: 6px; font-weight: bold; font-size: 12px; cursor: pointer; }
 
        .lcd-box { background: #222; color: #00ff00; font-family: monospace; padding: 2px 6px; border-radius: 6px; text-align: center; font-size: 11px; font-weight: bold; margin-bottom: 10px; letter-spacing: 0.5px; border: 1px solid #444; white-space: pre; line-height: 1.0; max-height: 38px; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
    </style>
</head>
<body onload="actualizarEstados()">
    <h1>Control de Riego</h1>
 
    <div class='lcd-box'>
        <div id='lcdL1'>---</div>
        <div id='lcdL2'>---</div>
    </div>
 
    <div class='card'>
        <div id='bloqueoManual' class='overlay'>RIEGO EN CURSO</div>
        <h2>Zonas Manuales</h2>
        <div class='grid'>
            <button id="btn0" onclick="toggle(0)">C1 (0s)</button>
            <button id="btn1" onclick="toggle(1)">C2 (0s)</button>
            <button id="btn2" onclick="toggle(2)">C3 (0s)</button>
            <button id="btn3" onclick="toggle(3)">C4 (0s)</button>
            <button id="btn4" onclick="toggle(4)">C5 (0s)</button>
            <button id="btn5" onclick="toggle(5)">C6 (0s)</button>
        </div>
    </div>
 
    <div class='card'>
        <h2>Equipamiento</h2>
        <div class='row'>
            <button id="btn6" class="special-btn" onclick="toggleAcc(6,'tL')">LUZ (0s)</button>
            <input type="range" id="tL" min="1" max="120" value="1" oninput="vL.innerText=this.value">
            <span class="time-label"><span id="vL">1</span>m</span>
        </div>
        <div class='row'>
            <button id="btn7" class="special-btn" onclick="toggleAcc(7,'tD')">DEP (0s)</button>
            <input type="range" id="tD" min="1" max="360" value="1" oninput="vD.innerText=this.value">
            <span class="time-label"><span id="vD">1</span>m</span>
        </div>
    </div>
 
    <div class='card'><h2>Presión de Agua</h2><div class="sensor-container"><button class='btn-presion' id="btnP" onclick="medirP()">MEDIR PRESIÓN</button><div id="valP" class="sensor-status">-- BAR</div></div></div>
    <div class='card'><h2>Control y Sensor Luz</h2><div class="sensor-container"><button class='btn-servo' onclick="pulsar()">EJECUTAR PULSACIÓN</button><div id="ldrStatus" class="sensor-status">...</div></div></div>
 
    <div class='card'>
      <h2>Riego Secuencial</h2>
      <div class='riego-grid'>
        <div class='riego-item'><input type="checkbox" name="mc" value="0"> C1</div>
        <div class='riego-item'><input type="checkbox" name="mc" value="1"> C2</div>
        <div class='riego-item'><input type="checkbox" name="mc" value="2"> C3</div>
        <div class='riego-item'><input type="checkbox" name="mc" value="3"> C4</div>
        <div class='riego-item'><input type="checkbox" name="mc" value="4"> C5</div>
        <div class='riego-item'><input type="checkbox" name="mc" value="5"> C6</div>
      </div>
      <div class='row'>
        <label style="font-size:12px; font-weight:bold;">Tiempo:</label>
        <input type="range" id="dur" min="1" max="15" value="1" oninput="vR.innerText=this.value">
        <span class="time-label"><span id="vR">1</span>m</span>
      </div>
      <button class='btn-main' onclick="sendRiego()">INICIAR RIEGO</button>
    </div>
 
    <div class='card'><button class='btn-stop' onclick="stopAll()">PARADA TOTAL</button></div>
 
    <script>
        function fmtSeg(s) {
            if (s < 60) return s + 's';
            let m = Math.floor(s / 60);
            let seg = s % 60;
            return m + 'm ' + seg + 's';
        }
 
        function actualizarEstados() { 
            fetch('/status').then(res => res.json()).then(data => { 
                data.estados.forEach((st, i) => { 
                    const btn = document.getElementById('btn' + i); 
                    if(btn) st ? btn.classList.add('active') : btn.classList.remove('active'); 
                }); 
 
                document.getElementById('bloqueoManual').style.display = data.riegoActivo ? 'flex' : 'none'; 
 
                const ldr = document.getElementById('ldrStatus');
                if(data.luz) { ldr.innerText = "Encendido"; ldr.classList.add('status-active'); } 
                else { ldr.innerText = "Apagado"; ldr.classList.remove('status-active'); }
 
                const pVal = document.getElementById('valP');
                pVal.innerText = data.presion.toFixed(2) + " BAR";
                if(data.midiendo) { document.getElementById('btnP').innerText = "ESPERANDO..."; document.getElementById('btnP').style.background = "#ffc107"; }
                else { document.getElementById('btnP').innerText = "MEDIR PRESIÓN"; document.getElementById('btnP').style.background = "#17a2b8"; }
 
                if(data.lcd1 !== undefined) document.getElementById('lcdL1').innerText = data.lcd1;
                if(data.lcd2 !== undefined) document.getElementById('lcdL2').innerText = data.lcd2;
 
                if(data.usoSegundos) {
                    // Actualizar etiquetas en botones C1-C6
                    for(let i = 0; i < 6; i++) {
                        const btn = document.getElementById('btn' + i);
                        if(btn) btn.innerText = 'C' + (i + 1) + ' (' + fmtSeg(data.usoSegundos[i]) + ')';
                    }
                    // Actualizar etiqueta Luz
                    const btnLuz = document.getElementById('btn6');
                    if(btnLuz) btnLuz.innerText = 'LUZ (' + fmtSeg(data.usoSegundos[6]) + ')';
 
                    // Actualizar etiqueta Depuradora
                    const btnDep = document.getElementById('btn7');
                    if(btnDep) btnDep.innerText = 'DEP (' + fmtSeg(data.usoSegundos[7]) + ')';
                }
            }); 
        }
 
        function medirP() { fetch('/medirP'); }
        function toggle(id) { fetch('/toggle?id=' + id).then(actualizarEstados); }
        function toggleAcc(id, sId) { fetch(`/acc?id=${id}&t=${document.getElementById(sId).value}`).then(actualizarEstados); }
        function pulsar() { fetch('/pulsar'); }
        function stopAll() { fetch('/stop').then(actualizarEstados); }
        function sendRiego() { let sel = []; document.querySelectorAll('input[name="mc"]:checked').forEach(el => sel.push(el.value)); if(!sel.length) return alert('Selecciona zona'); fetch(`/riego?ids=${sel.join(',')}&t=${document.getElementById('dur').value}`).then(actualizarEstados); }
        setInterval(actualizarEstados, 500);
    </script>
</body>
</html>
)=====";
 
// --- HANDLERS ---
 
void handleStatus() {
  if (!server.authenticate(usuarioSeguro, passwordSegura)) return;
  int lecturaLDR = analogRead(pinLDR);
  hayLuz = (lecturaLDR > 20); 
 
  String json = "{\"riegoActivo\":" + String(riegoEnProgreso ? "true" : "false") + 
                ",\"luz\":" + String(hayLuz ? "true" : "false") + 
                ",\"presion\":" + String(ultimaPresion) + 
                ",\"midiendo\":" + String(midiendoPresion ? "true" : "false") + 
                ",\"lcd1\":\"" + lcdLinea1 + "\"" +
                ",\"lcd2\":\"" + lcdLinea2 + "\"" +
                ",\"usoSegundos\":[";
  for (int i = 0; i < 8; i++) {
    json += String(tiempoUsoSegundos[i]);
    if (i < 7) json += ",";
  }
  json += "],\"estados\":[";
  for (int i = 0; i < 8; i++) { json += estados[i] ? "true" : "false"; if (i < 7) json += ","; }
  json += "]}";
  server.send(200, "application/json", json);
}
 
void setup() {
  Serial.begin(9600); 
  Wire.begin(21, 22); 
  lcd.init(); lcd.backlight();
  imprimirLinea(0, "Sistema Listo");
 
  auto initPinSeguro = [](int p) { 
    digitalWrite(p, HIGH);    
    pinMode(p, OUTPUT);       
    digitalWrite(p, HIGH);    
  };
 
  for(int i=0; i<6; i++) initPinSeguro(pinesCanales[i]);
  initPinSeguro(pinValvulaMaestra); 
  initPinSeguro(pinLuces); 
  initPinSeguro(pinDepuradora);
  initPinSeguro(pinRelayPresion); 
 
  pinMode(pinLDR, INPUT);
  pinMode(pinSensorPresion, INPUT);
 
  miServo.attach(pinServo); miServo.write(posReposo);
  actualizarHardware();
 
  wifiMulti.addAP(ssid1, pass1); wifiMulti.addAP(ssid2, pass2);
  while (wifiMulti.run() != WL_CONNECTED) { delay(500); }
 
  configTzTime(timeZone, ntpServer);
 
  MDNS.begin("riego");
 
  server.on("/", []() { if(server.authenticate(usuarioSeguro, passwordSegura)) server.send(200, "text/html", PAGE_HTML); else server.requestAuthentication(); });
  server.on("/status", handleStatus);
  server.on("/toggle", [](){ if(riegoEnProgreso) return; int id = server.arg("id").toInt(); if (id < 6) { estados[id] = !estados[id]; actualizarHardware(); } server.send(200); });
  server.on("/acc", [](){ int id = server.arg("id").toInt(); unsigned long min = server.arg("t").toInt(); estados[id] = !estados[id]; if (estados[id]) tiempoFinAccesorios[id-6] = millis() + (min * 60000); actualizarHardware(); server.send(200); });
 
  server.on("/medirP", [](){ 
    if(!midiendoPresion) {
      digitalWrite(pinRelayPresion, LOW);
      midiendoPresion = true; 
      tiempoInicioMedida = millis();
    }
    server.send(200); 
  });
 
  server.on("/pulsar", [](){ miServo.write(posPresion); tiempoServoPulsado = millis() + 500; servoEnMovimiento = true; server.send(200); });
  server.on("/stop", [](){ detenerTodo(); server.send(200); });
  server.on("/riego", [](){
    if (riegoEnProgreso) return;
    for (int i = 0; i < 6; i++) estados[i] = false;
    actualizarHardware();
    String ids = server.arg("ids"); duracionZonaMs = (unsigned long)server.arg("t").toInt() * 60000;
    totalCanalesRiego = 0; char str[ids.length() + 1]; strcpy(str, ids.c_str()); char* p = strtok(str, ",");
    while (p != NULL) { canalesParaRegar[totalCanalesRiego++] = atoi(p); p = strtok(NULL, ","); }
    if (totalCanalesRiego > 0) { riegoEnProgreso = true; indiceRiegoActual = -1; }
    server.send(200);
  });
  server.begin();
}
 
void loop() {
  unsigned long ahora = millis();
  server.handleClient();
 
  actualizarContadoresTiempo(); 
 
  if (ahora - ultimaVezCheckWiFi >= intervaloCheckWiFi) { ultimaVezCheckWiFi = ahora; wifiMulti.run(); }
  if (ahora - ultimaActualizacionLCD >= 500) { ultimaActualizacionLCD = ahora; actualizarLCD(); }
 
  if (midiendoPresion) {
    if (millis() - tiempoInicioMedida >= TIEMPO_ESPERA_PRESION) {
      realizarLecturaPresion();         
      digitalWrite(pinRelayPresion, HIGH);
      midiendoPresion = false;
      // Serial.println("Medición terminada, relé apagado.");
    }
  }
 
  if (riegoEnProgreso) {
    if (indiceRiegoActual == -1 || (ahora - tiempoInicioZona >= duracionZonaMs)) {
      if (indiceRiegoActual >= 0) estados[canalesParaRegar[indiceRiegoActual]] = false;
      indiceRiegoActual++;
      if (indiceRiegoActual >= totalCanalesRiego) { riegoEnProgreso = false; indiceRiegoActual = -1; }
      else { estados[canalesParaRegar[indiceRiegoActual]] = true; tiempoInicioZona = ahora; }
      actualizarHardware();
    }
  }
 
  if (estados[6] && ahora >= tiempoFinAccesorios[0]) { estados[6] = false; actualizarHardware(); }
  if (estados[7] && ahora >= tiempoFinAccesorios[1]) { estados[7] = false; actualizarHardware(); }
  if (servoEnMovimiento && ahora >= tiempoServoPulsado) { miServo.write(posReposo); servoEnMovimiento = false; }
}
Este sitio web utiliza cookies. Al utilizar el sitio web, usted acepta almacenar cookies en su computadora. También reconoce que ha leído y entendido nuestra Política de privacidad. Si no está de acuerdo abandone el sitio web.Más información
control_de_un_jardin_con_piscina_con_esp32.txt · Última modificación: por 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki