Arquitectura‐de‐la‐Solucion.md - Carvaa-7/Challenge1_IoT GitHub Wiki
flowchart LR
subgraph Sensado
BME[BME280<br/>Temp/Humedad/Presión]
BH[BH1750<br/>Luz]
HC[HC-SR04<br/>Nivel]
HX[HX711 + Celda de carga<br/>Peso]
end
subgraph Procesamiento["ESP32 (Dual Core)"]
C0["Core 0<br/>Tarea FreeRTOS de sensores"]
C1["Core 1<br/>Fusión + Servidor Web + Alarma"]
MUT[(Mutex / Struct compartido)]
C0 --> MUT --> C1
end
subgraph Salida
LCD[LCD 16x2 paralelo]
LEDS[4 LEDs semáforo]
BUZ[Buzzer no bloqueante]
WEB[Servidor Web embebido<br/>WiFi Station + Auth]
end
subgraph Actuacion
RELE[Módulo Relé]
BOMBA[Bomba sumergible]
RELE --> BOMBA
end
BME --> C0
BH --> C0
HC --> C0
HX --> C0
C1 --> LCD
C1 --> LEDS
C1 --> BUZ
C1 --> WEB
C1 --> RELE
WEB -. control remoto .-> RELE
flowchart TD
M1["Módulo 1<br/>Lectura de sensores (FreeRTOS, core 0)"]
M2["Módulo 2<br/>Lógica de fusión (riesgo base + IEE)"]
M3["Módulo 3<br/>Evapotranspiración (Hargreaves-Samani)"]
M4["Módulo 4<br/>Servidor Web (Station, Auth, Histórico)"]
M5["Módulo 5<br/>Alarma física (LEDs + Buzzer) y LCD"]
M1 -->|SensorData protegido por mutex| M2
M2 --> M5
M1 --> M3
M3 -->|validación cruzada por balance de masa| M2
M2 --> M4
M3 --> M4
M1 --> M4
M4 -->|control remoto de bomba| M1
El loop() principal nunca usa delay() bloqueante (salvo una única espera intencional de hasta 15s al conectar WiFi en setup(), documentada explícitamente en el código). Todo se programa con temporización basada en millis() (cooperative multitasking), porque el servidor web necesita atender peticiones (server.handleClient()) constantemente — un delay() largo en el loop congelaría el tablero web cada vez que se ejecutara.
La lectura de sensores corre en una tarea FreeRTOS separada, anclada al core 0 (xTaskCreatePinnedToCore), mientras el core 1 atiende el servidor web y la lógica de fusión. El intercambio de datos entre ambos cores se hace mediante un struct compartido protegido por mutex (SemaphoreHandle_t), evitando condiciones de carrera.
- La tarea de sensores lee BME280, BH1750, HC-SR04 y HX711 cada 1s, y escribe el resultado (protegido por mutex) en la estructura compartida
SensorData. - Cada 2s, el loop principal toma una copia de esos datos y ejecuta
calcularFusion(), obteniendo el riesgo base, el Índice de Estrés Evaporativo (IEE) y el estado final (Normal/Preventivo/Alto/Crítico). - Cada hora (configurable), se cierra la "ventana de evaporación": se calcula el ET0 (Hargreaves-Samani) y se contrasta contra el descenso real de nivel medido, generando un porcentaje de error de validación cruzada.
- El resultado de la fusión actualiza en paralelo: los 4 LEDs, el buzzer (patrón según severidad), el LCD (ciclo de 3 pantallas, con salto prioritario a la pantalla de riesgo si el estado es Alto/Crítico), el histórico circular, y queda disponible vía HTTP (
/api/data,/api/historico) para el tablero web. - El operador puede, desde el tablero web autenticado, silenciar la alarma (10 min) o encender/apagar la bomba de recirculación.
Ver el detalle de cada módulo en Diseño de Hardware, Variables Ambientales y Lógica de Fusión y Servidor Web Embebido.