← Índice del curso

Sensores y Actuadores · Tema 45

Proyecto: control climático de un invernadero

Un invernadero pequeño reúne casi todo lo que se vio en el curso: sensores de temperatura, humedad, luz y suelo; actuadores de potencia (ventilador, calefactor, lámparas, electroválvula); leyes de control todo o nada y proporcionales; tareas sin bloqueos; drivers con interfaces limpias; y un conjunto de protecciones para que una falla no arruine el cultivo ni cause un daño. Este tema recorre el proyecto de punta a punta, desde los requisitos hasta las pruebas, con números de un invernadero de 6 m².

01 · Punto de partida

Qué vamos a construir

El proyecto es un invernadero de 6 m² de cultivo (un bancal de 4 m² de tomates con riego por goteo y un pasillo) que debe mantenerse solo durante días: calentar de noche, ventilar de día, evitar la condensación, completar la luz en invierno y regar cuando el suelo lo pida. Todo con un microcontrolador, sin conexión obligatoria, y de manera que ninguna falla individual cause un desastre. Los requisitos (valores de ejemplo para tomate: cada cultivo tiene los suyos, y conviene consultarlos) son:

Requisitos del proyecto y la ley de control de cada variable.
VariableObjetivoSensorActuadorLey
Temperatura mínima≥ 15 °C de noche (consigna de 16 °C)SHT31 y DS18B20 (redundantes)Calefactor (SSR)Todo o nada, histéresis ±1 °C
Temperatura máxima24 a 28 °C de día; alarma a 30 °CLos mismosVentilador (PWM)Proporcional, banda de 4 °C
Humedad del aire60 a 85 %; alarma < 40 %SHT31Ventilador y calefactorUmbral con histéresis 85 / 80 %
LuzIntegral diaria (DLI) de 17 mol/m²/díaBH1750 (lux)Lámparas LEDUmbral 8000 / 12 000 lx, ventana horaria y DLI
Humedad del suelo35 a 40 %Capacitivo (ADC)ElectroválvulaRiego por pulsos con remojo y verificación

La estrategia general: cada lazo es simple (todos son los de los temas 42 y 43, sin sorpresas), y la dificultad está en la coordinación (el calefactor y el ventilador no pueden pelear, el riego sube la humedad, las lámparas calientan), en la robustez (sensores que fallan, el aire saturado de humedad, el agua y la electricidad en el mismo espacio) y en la seguridad (el calefactor funciona con tensión de red).

02 · Componentes

Hardware y alimentación

Lista de componentes, interfaz y consumo.
ComponenteFunciónInterfazConsumo
ESP32 (placa de desarrollo)Control, reloj, Wi-Fi opcional—~ 0,25 A a 5 V
SHT31Temperatura y humedad relativa (±0,3 °C, ±2 %)I2C, 0x44mA
DS18B20 (sonda impermeable)Segunda temperatura, tecnología distintaOneWiremA
BH1750Iluminancia (lux)I2C, 0x23mA
Sensor capacitivo de humedad del sueloHumedad volumétricaADC1 (GPIO 34)mA
Interruptor de flotadorNivel del tanqueDigital—
DS3231 (reloj de tiempo real)Hora del día (±2 ppm: 0,17 s por día)I2C, 0x68mA
OLED SSD1306Estado y alarmasI2C, 0x3C~ 20 mA
Ventilador de 12 VVentilación proporcionalMOSFET + PWM0,5 A
Electroválvula de 12 V (normalmente cerrada)Riego por goteoMOSFET + diodo de rebote0,4 A
Lámparas LED de cultivo (12 V)Luz suplementariaMOSFET (encendido o PWM)2,0 A
Calefactor de 1500 W (230 V)Calefacción nocturnaSSR + contactor + termostato de seguridad6,5 A de red
Zumbador y LEDAlarmasDigitalmA

Cuatro dispositivos comparten el bus I2C con direcciones distintas (0x44, 0x23, 0x3C y 0x68), sin conflicto. La alimentación de 12 V debe sostener las cargas que pueden coincidir: ventilador 0,50 A, electroválvula 0,40 A, lámparas 2,00 A y el microcontrolador (0,25 A a 5 V desde un conversor, unos 0,12 A en el lado de 12 V), un total de 3,02 A; con un 20 % de margen son 3,6 A, y se elige una fuente de 12 V y 5 A.

  • Pines del ESP32: los sensores analógicos van a pines de ADC1 (GPIO 32 a 39); el ADC2 no funciona mientras el Wi-Fi está activo. Los módulos de 5 V requieren adaptadores de nivel (el ESP32 es de 3,3 V).
  • Etapas de potencia: un MOSFET de nivel lógico por carga de 12 V (tema 27), con diodo de rebote en la electroválvula (tema 29). Para el ventilador, PWM de 25 kHz (el valor que aceptan los ventiladores de cuatro hilos de PC y que no se oye).
  • Tensión de red: el calefactor va por un SSR con un contactor electromecánico y un termostato de seguridad en serie (tema 44), en una caja aislada, con fusible y conexión a tierra; nunca se mezcla con el cableado de señal.
  • Un ambiente hostil: humedad cercana al 100 %, salpicaduras, polvo y sol. El sensor de aire va en una pantalla de radiación ventilada, a la altura del follaje y sin sol directo (un sensor al sol lee varios grados de más); los circuitos, en una caja estanca; los sensores del suelo capacitivos, con sus bordes sellados para que no se corroan. El SHT31 tiene un calentador interno que ayuda a eliminar la condensación sobre el sensor.

03 · Estructura

Arquitectura de software

El programa sigue la arquitectura de los temas 40 y 41: drivers detrás de interfaces (SensorTemperatura, SensorHumedad, SensorLuz, Salida), decoradores de validación y redundancia (tema 44), un planificador cooperativo con tareas cortas y una máquina de modos. Las tareas, con su período y su duración:

Tareas periódicas del invernadero.
TareaPeríodoDuraciónQué hace
Sensores2 s3 msLectura por etapas, validación, redundancia
Clima10 s1 msCalefactor, ventilador, humedad alta, interbloqueos
Luz60 s1 msIntegra la DLI y decide las lámparas
Riego5 s0,5 msMáquina de estados de la válvula
Pantalla1 s26 msOLED por I2C a 400 kHz, solo lo que cambió
Registro10 mindecenas de msUna línea con los valores y los estados

La utilización de la CPU es del 2,8 % y, en el peor caso, un botón espera 31,5 ms: sobra margen. El perro guardián (tema 44) se alimenta en un solo lugar, solo si todas las tareas respondieron. La hora del día proviene del DS3231 (la deriva de millis() de un resonador cerámico podría ser de minutos por día, tema 41), y los modos son los de la sección 8 del tema anterior: AUTO (control normal), MANUAL (un botón fuerza el ventilador o una válvula, con las seguridades siempre activas), SEGURO y FALLA.

La conexión de red (MQTT, una página web local) es un extra que no debe afectar al control: si el Wi-Fi se cae, el invernadero sigue funcionando con sus reglas locales. Y cualquier orden remota pasa por las mismas validaciones y límites que las locales.

04 · Primer lazo

Temperatura: calefacción y ventilación

El modelo térmico es un balance de energía de un solo estado (el aire y la masa que lo acompaña), con el sol como fuente, el calefactor como control y las pérdidas por la envoltura y por la ventilación:

C · dT/dt = Qsol + Qcalefactor − (UA + u · ṁ·cp) · (T − Text)

Con C = 500 kJ/K, UA = 100 W/K (envoltura y fugas), un calefactor de 1500 W, un sol que llega a 3000 W al mediodía y un ventilador cuyo caudal máximo es Qv, de modo que ṁ·cp = Qv × 1,2 × 1005 J/(m³·K) (301 W/K con 0,25 m³/s). El exterior oscila entre 7 y 23 °C. El control es el de los temas 42 y 43: el calefactor, todo o nada con histéresis alrededor de 16 °C, y el ventilador, proporcional desde 24 °C con banda de 4 °C. Los resultados del último día de una simulación de tres días son:

Simulación del invernadero según el escenario (último día).
EscenarioT mínT máxh > 28 °Ch < 12 °CCalefactorVentilador
Verano despejado, ventilador de 0,25 m³/s15,030,04,506,2 kWh33 %
Sin ventilación15,050,510,505,9 kWh0 %
Ventilador de 0,40 m³/s15,027,9006,2 kWh27 %
Ventilador de 0,10 m³/s15,035,87,906,2 kWh40 %
Invierno nublado (1000 W de sol, 5 °C medios)12,421,70018,5 kWh0 %
Invierno nublado sin calefactor−2,521,6014,600 %

Las cuentas del dimensionamiento salen directamente de estas ecuaciones:

  • El ventilador: en el pico, el sol de 3000 W se evacúa con la conductancia total: ΔT = Qsol / (UA + Gv). Con 0,25 m³/s son 3000 / 401 = 7,5 K sobre el exterior (30,5 °C con 23 °C afuera: 4,5 horas por encima de 28 °C); con 0,40 m³/s son 5,2 K y se queda en 27,9 °C. Sin ventilación, el invernadero llega a 50,5 °C, una temperatura que mata plantas. Una referencia usual es del orden de 0,05 m³/s por metro cuadrado de piso (0,3 m³/s para 6 m²).
  • El calefactor: para sostener 16 °C con −3 °C afuera hacen falta UA × (16 + 3) = 1900 W, más que los 1500 W instalados: en el invierno nublado simulado la temperatura mínima es de 12,4 °C, y sin calefactor baja a −2,5 °C (14,6 horas por debajo de 12 °C, con riesgo de helada). La causa del problema es siempre la envoltura: un mejor aislamiento (menor UA) suele rendir más que más potencia.
  • La energía: 6,2 kWh por noche de verano y 18,5 kWh por día de invierno nublado: un dato para el costo operativo y para elegir la fuente.

Detalles del lazo: el ventilador no se deja a velocidad cero con sobretemperatura; el calefactor tiene tiempos mínimos de encendido y apagado y un termostato de seguridad independiente (tema 44); y el sensor de temperatura se duplica (SHT31 y DS18B20, comparados), porque de su lectura dependen el calefactor, el ventilador y la seguridad.

05 · Segundo lazo

Humedad del aire

La humedad relativa depende de la temperatura: el aire frío admite menos vapor. Con la fórmula de Magnus, la presión de saturación es es(T) = 0,6112 · exp(17,62 T / (243,12 + T)) kPa, la humedad relativa es HR = e / es y el punto de rocío (la temperatura a la que el vapor presente satura el aire) sale de invertirla (tema 12). Un caso típico:

  • Al mediodía, 26 °C y 60 % de HR: presión de vapor de 2,01 kPa, punto de rocío de 17,6 °C y 14,6 g/m³ de vapor.
  • Si de noche el invernadero baja a 20 °C, la humedad sube al 86,3 % (sin condensación). A 17 °C, el aire queda saturado y condensa; a 14 °C el aire solo admite 12,04 g/m³ y se condensan 2,54 g por cada metro cúbico, sobre las hojas y las paredes: el ambiente ideal de los hongos (botritis, mildiu).

La estrategia clásica es deshumidificar ventilando: el aire exterior, aunque sea frío y húmedo, contiene menos vapor absoluto que el interior. Aire de 10 °C y 80 % calentado a 18 °C tiene una HR de 47,6 %; calentado a 14 °C, de 61,5 %; a 26 °C, de 29,2 %. Cambiar el aire interior por aire exterior y calentarlo seca el ambiente, al costo de energía. La regla del proyecto: si la HR supera el 85 % (con una histéresis de 85 / 80 %), se enciende el ventilador a un mínimo del 30 % y se deja actuar al calefactor para que la temperatura no baje de 15 °C. Una HR por debajo del 40 % es una alarma (déficit de presión de vapor alto: la planta transpira de más).

Dos precauciones: un sensor de humedad en un ambiente que llega al 100 % se deriva y se satura, de modo que se protege con una membrana y se verifica contra una referencia de vez en cuando (tema 44); y la humedad no se controla de forma independiente de la temperatura: el ventilador y el calefactor responden a las dos variables a la vez, y por eso la coordinación (sección 8) es la parte más delicada.

06 · Tercer lazo

Luz: la integral diaria

Las plantas no responden a los lux (una unidad hecha para el ojo humano, tema 14), sino a los fotones útiles para la fotosíntesis: la densidad de flujo de fotones (PPFD, en µmol/m²/s). Para la luz solar, 1 µmol/m²/s son unos 54 lux (relación aproximada que cambia con el tipo de fuente): el pleno sol de 100 000 lux son unos 1850 µmol/m²/s. Lo que cuenta para el crecimiento es la integral diaria de luz (DLI, mol/m²/día): los fotones acumulados en todo el día. Un tomate pide unos 20 a 30; el proyecto toma 17 como objetivo mínimo.

Integral diaria natural (14 h de luz, pico sinusoidal) y lámparas necesarias.
DíaDLI naturalLámpara para llegar a 17 mol/m²/día
Verano despejado (50 klx de pico)29,7No hacen falta
Nublado (30 % de la luz)8,9—
Invierno nublado (20 klx, 30 %)3,6400 µmol/m²/s: 9,3 h (960 W para 6 m², 9,0 kWh/día); 200 µmol/m²/s: 18,7 h (no entra en el fotoperiodo)

La política de las lámparas resume todo esto:

  • Un umbral con histéresis de 8000 lux (encender) y 12 000 lux (apagar), para que el sensor no haga conmutar las lámparas con cada nube, y tiempos mínimos de encendido y apagado de 10 minutos.
  • Una ventana horaria (de 6 a 22 h) para respetar el fotoperiodo, y un máximo de 16 h de luz total: más no es mejor para la mayoría de los cultivos.
  • Un objetivo de DLI: el programa integra los lux cada minuto (DLI += lux / 54 × 60 / 106) y apaga las lámparas cuando el aporte natural más el de las lámparas alcanza el objetivo del día.
  • La realimentación óptica del tema 16: las propias lámparas iluminan el sensor y lo hacen apagarse. El sensor se coloca de modo que reciba solo luz natural (o se decide por hora y por DLI, no por el valor instantáneo).
  • Sin corrección gamma: a diferencia de un LED de señalización (tema 35), la fotosíntesis es proporcional a los fotones, así que el PWM de las lámparas es lineal.
  • El rango del sensor: el BH1750 satura en 65 535 lux (más a pleno sol, con un tiempo de medición reducido o un difusor); a 100 000 lux hace falta un atenuador.

Las lámparas también son una carga térmica (la parte de la potencia que no se convierte en luz) y consumen: 9 kWh por día de invierno nublado son el mismo orden que el calefactor. El costo energético es una restricción de diseño.

07 · Cuarto lazo

Riego automático

El suelo es un depósito con pérdidas. En el bancal de 4 m² con raíces de 250 mm, cada milímetro de agua por metro cuadrado (1 L/m²) sube la humedad volumétrica 0,4 puntos. Con una evapotranspiración de 5 mm por día, el suelo pierde 2,0 puntos por día y el cultivo consume 20 L por día (4 m² × 5 mm). El sensor capacitivo entrega cuentas de ADC que se pasan a porcentaje con una calibración de dos puntos, en seco al aire y en agua (tema 5): % = (seco − cuentas) / (seco − mojado) × 100.

La ley es un umbral con histéresis: se riega cuando el suelo baja de 35 % y se detiene al llegar a 40 %. Subir 5 puntos exige 0,05 × 250 mm × 4 m² = 50 L, es decir 6,25 minutos a 8 L/min; y ocurre cada 2,5 días (5 puntos / 2 puntos por día). Subir 10 puntos serían 100 L y 12,5 minutos. Esto lleva a la forma real de regar: por pulsos.

  • Pulso y remojo: 3 minutos de riego y 30 de espera. El suelo absorbe el agua con lentitud, y el sensor tarda en verla; regar de corrido empaparía la capa superior y perdería agua por drenaje antes de que el sensor reaccione. Con 50 L son 3 pulsos de 180 s.
  • Verificación de respuesta: tras un pulso y su remojo, la humedad debe haber subido al menos un punto; si no, algo falla (tanque vacío, goteros tapados, válvula que no abre, sensor congelado) y el riego pasa a FALLA y enclava (tema 44), con una alarma.
  • Límites: máximo de 3 pulsos por evento, mínimo de 6 horas entre eventos y un tope diario de volumen estimado (por ejemplo, 150 L, siete veces el consumo normal): un sensor roto no puede inundar el invernadero.
  • El tanque: un flotador que impide regar sin agua y avisa; con la bomba, evitaría funcionar en seco.
  • Válvula normalmente cerrada (tema 29): sin corriente, cierra. Y un tiempo máximo de apertura que ni un programa colgado pueda superar, con un temporizador de hardware, si el riesgo lo justifica.
  • La hora: mejor por la mañana, para que las hojas se sequen antes de la noche (menos hongos), y no durante el pico de calor.

08 · Todo junto

Integración, interbloqueos y seguridad

Los cuatro lazos comparten el mismo espacio y se afectan entre sí. La coordinación es explícita y está en un solo lugar:

Interacciones entre lazos y cómo se resuelven.
InteracciónEfectoRegla
Calefactor y ventiladorCalentar y evacuar el aire a la vez desperdicia energíaInterbloqueo: con ventilación por calor, el calefactor se apaga
Humedad alta de nocheVentilar enfría; no ventilar condensaVentilación mínima del 30 % con calefactor activo para sostener ≥ 15 °C
Riego y humedadEl agua evaporada sube la HRRegar por la mañana, con ventilación disponible
Lámparas y temperaturaLas lámparas aportan calorSe apagan con más de 30 °C o en modo SEGURO
Lámparas y sensor de luzEl sensor ve las lámparasSensor protegido de la luz artificial; decisión por hora y DLI

Las prioridades son: primero la seguridad de las personas y el equipo, luego la supervivencia del cultivo (helada, sobrecalentamiento) y al final el confort y la eficiencia. Eso se traduce en modos (tema 44): con una temperatura inválida o por encima de los 35 °C, el calefactor y las lámparas se apagan, el ventilador va a pleno y la válvula se cierra; con una falla del sensor de suelo o del tanque, solo se bloquea el riego.

Las alarmas usan lo visto en los temas 35 y 39: un LED y un zumbador con patrones distintos (un pitido lento cada segundo para una advertencia como una HR baja, uno rápido para una falla crítica), pantalla con el estado de cada lazo y un registro cada 10 minutos en una tarjeta SD o enviado por red, con los valores, los estados y las fallas; sirve para ajustar el control y diagnosticar. Y el sistema debe seguir siendo seguro sin conexión.

09 · Programación

El programa

La configuración reunida en un archivo, la histéresis genérica, la decisión del clima (temperatura y humedad juntas, con interbloqueo), las lámparas con DLI, la máquina de estados del riego con pulsos y verificación y el lazo principal. Los drivers, los decoradores de validación, el perro guardián y los modos son los de los temas 40 a 44.

// ---------- config.h: todo lo que cambia con el montaje o con el cultivo ----------
namespace Config {
    // ESP32: los sensores analógicos van a pines de ADC1 (el ADC2 no funciona con Wi-Fi)
    constexpr uint8_t PIN_ONEWIRE = 4, PIN_VENTILADOR = 16, PIN_VALVULA = 17, PIN_CALEFACTOR = 18,
                      PIN_LAMPARA = 19, PIN_BUZZER = 23, PIN_NIVEL = 27, PIN_SUELO = 34;
    constexpr float T_CALEFACCION = 16.0f, H_CALEFACCION = 1.0f;       // enciende < 15 °C y apaga > 17 °C
    constexpr float T_VENTILACION = 24.0f, BANDA_VENT = 4.0f;          // ventilador de 0 % a 24 °C a 100 % a 28 °C
    constexpr float T_ALARMA = 30.0f, T_LIMITE_SW = 35.0f;             // alarma y corte por software
    constexpr float HR_ALTA = 85.0f, HR_NORMAL = 80.0f;                // deshumidificar por encima de 85 %
    constexpr float LUX_ENCENDER = 8000.0f, LUX_APAGAR = 12000.0f;     // lámparas, con histéresis
    constexpr float DLI_OBJETIVO = 17.0f;                              // mol/m²/día
    constexpr float SUELO_BAJO = 35.0f, SUELO_ALTO = 40.0f;            // humedad del suelo, %
    constexpr uint32_t PULSO_MS = 180000UL, REMOJO_MS = 1800000UL, ENTRE_RIEGOS_MS = 21600000UL;   // 3 min, 30 min, 6 h
    constexpr uint8_t PULSOS_MAX = 3;
}

// ---------- Umbral con histéresis: sirve para humedad alta, lámparas, etc. ----------
class Umbral {
public:
    Umbral(float enciende, float apaga) : on_(enciende), off_(apaga) {}
    bool actualizar(float x) {                                        // si on_ > off_: se activa por encima de on_
        if (on_ > off_) { if (x > on_) activo_ = true; else if (x < off_) activo_ = false; }
        else            { if (x < on_) activo_ = true; else if (x > off_) activo_ = false; }
        return activo_;
    }
private:
    float on_, off_; bool activo_ = false;
};
Umbral humedadAlta(Config::HR_ALTA, Config::HR_NORMAL);
Umbral luzBaja(Config::LUX_ENCENDER, Config::LUX_APAGAR);            // activa con poca luz

// ---------- Clima: temperatura y humedad deciden juntas sobre ventilador y calefactor ----------
struct Orden { float ventilador; bool calefactor; };

Orden climatizar(float temp, float hr, bool calefactorEncendido) {
    float vTemp = constrain((temp - Config::T_VENTILACION) / Config::BANDA_VENT, 0.0f, 1.0f);   // proporcional
    float vHum  = humedadAlta.actualizar(hr) ? 0.30f : 0.0f;          // deshumidificar: ventilación mínima del 30 %
    bool calor = calefactorEncendido;
    if (temp < Config::T_CALEFACCION - Config::H_CALEFACCION) calor = true;
    else if (temp > Config::T_CALEFACCION + Config::H_CALEFACCION) calor = false;
    if (vTemp > 0.1f) calor = false;                                  // interbloqueo: nunca calentar y ventilar por calor a la vez
    return { max(vTemp, vHum), calor };                               // con aire frío y húmedo, el calefactor compensa la pérdida
}

// ---------- Luz: lámparas por falta de luz, dentro de una ventana horaria y hasta cumplir la DLI ----------
float dli = 0;                                                         // mol/m² acumulados en el día
void integrarLuz(float lux) { dli += lux / 54.0f * 60.0f / 1e6f; }     // cada minuto; 54 lux ≈ 1 µmol/m²/s de luz solar

bool lamparas(float lux, int hora, float ppfdLampara, uint32_t minutosEncendida) {
    bool poca = luzBaja.actualizar(lux);
    bool ventana = hora >= 6 && hora < 22;                             // fotoperiodo permitido
    float aporte = ppfdLampara * minutosEncendida * 60.0f / 1e6f;      // la lámpara también suma a la DLI
    return poca && ventana && (dli + aporte) < Config::DLI_OBJETIVO;
}

// ---------- Riego: máquina de estados con pulsos, remojo y verificación de respuesta ----------
enum class Riego : uint8_t { REPOSO, REGANDO, REMOJO, FALLA };
Riego riego = Riego::REPOSO;
uint32_t tRiego = 0, tUltimoEvento = 0; uint8_t pulsos = 0; float sueloAntes = 0;
bool hayEventoPrevio = false;

bool electrovalvula(float suelo, bool tanqueConAgua, bool sensorOk) {   // devuelve si la válvula debe estar abierta
    uint32_t ahora = millis();
    if (!sensorOk) { riego = Riego::FALLA; }                           // sin dato fiable, la válvula cierra
    switch (riego) {
        case Riego::REPOSO:
            if (suelo < Config::SUELO_BAJO && tanqueConAgua &&
                (!hayEventoPrevio || (uint32_t)(ahora - tUltimoEvento) >= Config::ENTRE_RIEGOS_MS)) {
                riego = Riego::REGANDO; tRiego = ahora; pulsos = 0; sueloAntes = suelo; hayEventoPrevio = true;
            }
            break;
        case Riego::REGANDO:                                           // pulso de 3 minutos como máximo
            if (!tanqueConAgua || (uint32_t)(ahora - tRiego) >= Config::PULSO_MS) { riego = Riego::REMOJO; tRiego = ahora; pulsos++; }
            break;
        case Riego::REMOJO:                                            // el agua tarda en llegar al sensor
            if ((uint32_t)(ahora - tRiego) >= Config::REMOJO_MS) {
                if (suelo >= Config::SUELO_ALTO) { riego = Riego::REPOSO; tUltimoEvento = ahora; }
                else if (suelo - sueloAntes < 1.0f && pulsos >= 1) riego = Riego::FALLA;   // regó y no subió: sin agua, obstrucción o sensor
                else if (pulsos >= Config::PULSOS_MAX) { riego = Riego::REPOSO; tUltimoEvento = ahora; }
                else { riego = Riego::REGANDO; tRiego = ahora; }
            }
            break;
        case Riego::FALLA:
            break;                                                      // enclavado hasta un reinicio manual (tema 44)
    }
    return riego == Riego::REGANDO;
}

// ---------- Lazo principal: tareas periódicas y salidas con sus protecciones ----------
void loop() {
    ejecutar(tareaSensores);                                           // 2 s, por etapas (tema 41)
    ejecutar(tareaClima);                                              // 10 s
    ejecutar(tareaLuz);                                                // 60 s
    ejecutar(tareaRiego);                                              // 5 s
    ejecutar(tareaPantalla);                                           // 1 s, solo lo que cambió
    if (vivas == TODAS) { wdt_reset(); vivas = 0; }                    // perro guardián: solo si todas las tareas respondieron
}

void tareaClima() {
    Lectura t = sensorTemperatura.leer();                              // SensorRedundante(SHT31, DS18B20): tema 44
    Lectura h = sensorHumedad.leer();
    if (t.estado != Estado::OK || t.valor > Config::T_LIMITE_SW) {     // dato inválido o límite: estado seguro
        calefactor.apagar(); ventilador.establecer(1.0f); modo = Modo::SEGURO;
    } else {
        float hr = (h.estado == Estado::OK) ? h.valor : 0.0f;          // sin humedad fiable: solo se controla la temperatura
        Orden o = climatizar(t.valor, hr, calefactorEncendido);
        ventilador.establecer(o.ventilador);
        calefactorEncendido = o.calefactor;
        calefactor.establecer(o.calefactor ? 1.0f : 0.0f);
    }
    vivas |= T_CONTROL;
}

Cada decisión está en una función corta y probable: climatizar, lamparas y electrovalvula se pueden ejecutar en un PC con sensores simulados (tema 40) y un reloj ficticio, con las series de un día real, y comprobar lo que harían sin tocar una planta.

10 · Puesta en marcha

Puesta en marcha y pruebas

Se prueba de a una etapa, de lo seguro a lo peligroso:

  1. Banco, sin cargas: el microcontrolador con sensores y los drivers de salida con LEDs en lugar de las cargas. Se verifican las tareas, los tiempos (máximo del lazo, tema 41) y los modos con sensores simulados y fallas inyectadas.
  2. Sensores contra una referencia: el sensor de aire junto a un termómetro y un higrómetro de calidad; el de suelo calibrado en seco y en agua; el de luz, contra un luxómetro.
  3. Cargas de 12 V una por una: ventilador, electroválvula (con el agua) y lámparas, midiendo la corriente y la temperatura de los MOSFET.
  4. Interbloqueos y seguridades: forzar temperaturas con el sensor desconectado, humedad alta simulada, tanque vacío, apagón y vuelta de la luz (arranque seguro), perro guardián con un bucle de prueba.
  5. El calefactor de red, por último, con las protecciones independientes en su lugar y con la supervisión de alguien capacitado; se prueba el termostato de seguridad por separado.
  6. Un ensayo de 72 horas con registro, revisando las curvas contra el modelo y buscando oscilaciones, ciclos cortos y falsas alarmas.
Problemas típicos del proyecto.
SíntomaCausa probableSolución
Lecturas de temperatura altas al mediodíaSensor al sol sin pantalla de radiaciónPantalla ventilada, a la sombra, a la altura del follaje
HR que se queda en 100 % o saltaCondensación sobre el sensor, derivaMembrana, calentador del sensor, verificación contra una referencia
Las lámparas se encienden y apaganEl sensor de luz ve las lámparasSensor aislado de la luz artificial; histéresis y tiempos mínimos
El ESP32 no lee el sensor del suelo con el Wi-Fi activoEl sensor está en un pin de ADC2Mover a un pin de ADC1
El ventilador zumbaPWM en frecuencia audiblePWM de 25 kHz
El calefactor conmuta cada pocos minutosHistéresis chica o sensor ruidoso±1 °C, filtrar, tiempos mínimos
Riego que nunca termina o nunca empiezaSensor del suelo mal calibrado o sueltoCalibrar; verificación de respuesta; límites
Reinicios aleatorios al arrancar el ventiladorCaída de tensión o ruido de las cargas de 12 VCapacitores, diodos de rebote, buena masa, fuente con margen

11 · Analogía con programación

El invernadero simulado, el aire húmedo, la luz y el riego

Simulamos el balance térmico del invernadero con los controles del proyecto en distintos escenarios, calculamos con la fórmula de Magnus el punto de rocío y la deshumidificación por ventilación, integramos la luz del día, planificamos el riego y sumamos la corriente de 12 V y la utilización de la CPU.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

import math

# ---- 1. Modelo térmico del invernadero (un solo estado, pasos de 10 s) ----
C_TERM, UA, P_CALEF = 500_000.0, 100.0, 1500.0          # J/K, W/K (envolvente y fugas), W
CP_AIRE = 1.2 * 1005.0                                  # J/(m³·K)


def invernadero(q_sol=3000.0, caudal=0.25, tv=24.0, banda=4.0, th=16.0, calefactor=True, ventilar=True, t_med=15.0, horas=72):
    g_max = caudal * CP_AIRE                            # W/K con el ventilador a pleno
    temp, encendido, hist = 12.0, False, []
    for k in range(horas * 360):
        h = (k * 10 / 3600) % 24
        t_ext = t_med + 8 * math.sin(2 * math.pi * (h - 9) / 24)
        sol = q_sol * math.sin(math.pi * (h - 6) / 14) if 6 <= h <= 20 else 0.0
        if calefactor:
            if temp < th - 1:
                encendido = True
            elif temp > th + 1:
                encendido = False
        u = min(1.0, max(0.0, (temp - tv) / banda)) if ventilar else 0.0
        q = sol + (P_CALEF if encendido else 0.0) - (UA + u * g_max) * (temp - t_ext)
        temp += q * 10 / C_TERM
        hist.append((temp, t_ext, u, encendido))
    return hist


def resumen(hist):
    dia = hist[-8640:]
    temps = [t for t, _, _, _ in dia]
    horas_calor = sum(1 for t in temps if t > 28) * 10 / 3600
    horas_frio = sum(1 for t in temps if t < 12) * 10 / 3600
    energia = sum(1 for _, _, _, e in dia if e) * 10 * P_CALEF / 3600 / 1000
    ventilador = sum(u for _, _, u, _ in dia) / len(dia)
    return min(temps), max(temps), horas_calor, horas_frio, energia, ventilador


print("escenario                                  T mín    T máx   h > 28 °C  h < 12 °C  calefactor  ventilador")
for nombre, kwargs in (("verano despejado, diseño base (0,25 m³/s)", dict()),
                       ("sin ventilación", dict(ventilar=False)),
                       ("ventilador de 0,40 m³/s", dict(caudal=0.40)),
                       ("ventilador de 0,10 m³/s", dict(caudal=0.10)),
                       ("invierno nublado (1000 W, 5 °C medios)", dict(q_sol=1000, t_med=5)),
                       ("invierno nublado sin calefactor", dict(q_sol=1000, t_med=5, calefactor=False))):
    tmin, tmax, hc, hf, e, v = resumen(invernadero(**kwargs))
    print(f"{nombre:42s} {tmin:6.1f}  {tmax:6.1f}   {hc:6.1f}     {hf:6.1f}     {e:5.1f} kWh   {v * 100:5.1f} %")

# ---- 2. Psicrometría (fórmula de Magnus) ----
print()


def pres_sat(t):
    return 0.6112 * math.exp(17.62 * t / (243.12 + t))   # kPa


def punto_rocio(t, hr):
    g = math.log(pres_sat(t) * hr / 100 / 0.6112)
    return 243.12 * g / (17.62 - g)


def hum_abs(t, hr):
    return 216.7 * (pres_sat(t) * hr / 100 * 10) / (t + 273.15)   # g/m³


print(f"26 °C y 60 %: presión de vapor {pres_sat(26) * 0.6:.2f} kPa, punto de rocío {punto_rocio(26, 60):.1f} °C, humedad absoluta {hum_abs(26, 60):.1f} g/m³")
e_vapor = pres_sat(26) * 0.60
for t_noche in (20, 17, 14):
    hr = e_vapor / pres_sat(t_noche) * 100
    estado = "condensa" if hr >= 100 else "sin condensación"
    print(f"  si de noche baja a {t_noche} °C: HR {min(hr, 100):5.1f} % ({hr:5.1f} % teórico) -> {estado}")
print(f"  a 14 °C el aire solo admite {hum_abs(14, 100):.2f} g/m³: se condensan {hum_abs(26, 60) - hum_abs(14, 100):.2f} g por m³")
e_ext = pres_sat(10) * 0.80
for t_int in (14, 18, 26):
    print(f"ventilar con aire de 10 °C y 80 %, calentado a {t_int} °C: HR {e_ext / pres_sat(t_int) * 100:5.1f} %")

# ---- 3. Luz: integral diaria (DLI) ----
print()
K_LUX = 54.0                                            # lux por µmol/m²/s de luz solar (aproximado)


def dli_natural(pico_lux, nubosidad=1.0):
    media = pico_lux * 2 / math.pi * nubosidad          # media de un seno sobre 14 h de luz
    return media * 14 * 3600 / K_LUX / 1e6


for nombre, pico, nub in (("verano despejado (50 klx de pico)", 50000, 1.0), ("día nublado (30 % de la luz)", 50000, 0.3), ("invierno nublado (20 klx, 30 %)", 20000, 0.3)):
    print(f"{nombre:36s}: DLI natural {dli_natural(pico, nub):5.1f} mol/m²/día")
natural = dli_natural(20000, 0.3)
for ppfd in (200, 400):
    horas = (17 - natural) * 1e6 / (ppfd * 3600)
    potencia = ppfd * 6 / 2.5
    print(f"objetivo de 17 mol/m²/día en invierno nublado: lámpara de {ppfd} µmol/m²/s -> {horas:4.1f} h por día; {potencia:.0f} W para 6 m² (2,5 µmol/J) -> {potencia * horas / 1000:.1f} kWh/día")
print(f"pleno sol de 100 klx = {100000 / K_LUX:.0f} µmol/m²/s")

# ---- 4. Riego ----
print()
area, prof, caudal, et = 4.0, 250.0, 8.0, 5.0            # m², mm de raíces, L/min, mm/día
perdida = et / prof * 100
for delta in (5, 10):
    litros = delta / 100 * prof * area
    minutos = litros / caudal
    pulsos = math.ceil(minutos * 60 / 180)
    print(f"subir la humedad del suelo {delta:2d} puntos: {litros:5.1f} L, {minutos:5.2f} min de riego, {pulsos} pulsos de 180 s; cada {delta / perdida:.1f} días")
print(f"consumo diario: {et * area:.0f} L ({et * area / caudal:.1f} min por día); pérdida por evapotranspiración: {perdida:.1f} puntos por día")

# ---- 5. Alimentación de 12 V ----
print()
cargas = (("ventilador", 0.5), ("electroválvula", 0.4), ("lámparas LED", 2.0), ("microcontrolador (5 V, 0,25 A) vía conversor", 0.12))
total = sum(a for _, a in cargas)
print("corriente máxima de 12 V:", ", ".join(f"{n} {a:.2f} A" for n, a in cargas), f"-> total {total:.2f} A; con 20 % de margen {total * 1.2:.1f} A")

# ---- 6. Tareas del microcontrolador: utilización y respuesta en el peor caso ----
print()
tareas = (("sensores (por etapas)", 3.0, 2000), ("clima", 1.0, 10_000), ("luz", 1.0, 60_000), ("riego", 0.5, 5_000), ("pantalla OLED por I2C a 400 kHz", 26.0, 1000))
u = sum(c / t for _, c, t in tareas)
print("tareas:", "; ".join(f"{n} {c:g} ms cada {t / 1000:g} s" for n, c, t in tareas))
print(f"utilización de la CPU: {u * 100:.1f} %; respuesta del botón en el peor caso: {sum(c for _, c, _ in tareas):.1f} ms")

Resultado: con un ventilador de 0,25 m³/s el invernadero llega a 30,0 °C (4,5 h por encima de 28 °C), con 0,40 m³/s a 27,9 °C, con 0,10 m³/s a 35,8 °C y sin ventilar a 50,5 °C; la noche de verano gasta 6,2 kWh de calefactor y el día de invierno nublado, 18,5 kWh con un mínimo de 12,4 °C (sin calefactor, −2,5 °C). A 26 °C y 60 % el punto de rocío es de 17,6 °C: a 20 °C de noche la HR es de 86,3 %, a 14 °C se condensan 2,54 g/m³; aire exterior de 10 °C y 80 % calentado a 18 °C da 47,6 %. La DLI natural es de 29,7 (verano despejado), 8,9 (nublado) y 3,6 mol/m²/día (invierno nublado), y para llegar a 17 hacen falta 9,3 h de una lámpara de 400 µmol/m²/s (9,0 kWh) o 18,7 h con una de 200. Subir el suelo 5 puntos son 50 L y 6,25 min (3 pulsos de 180 s, cada 2,5 días) y 10 puntos, 100 L y 12,5 min (5 pulsos). La fuente de 12 V debe dar 3,02 A (3,6 A con margen) y la CPU trabaja al 2,8 % con 31,5 ms de respuesta en el peor caso.

12 · Exploración interactiva

Clima, humedad, luz y riego

El primer instrumento simula tres días del invernadero con el mismo modelo del programa de Python y muestra el último día. El segundo calcula el punto de rocío, la condensación nocturna y la deshumidificación por ventilación. El tercero planifica las lámparas con la integral diaria de luz. El cuarto dimensiona el riego por pulsos.

Instrumento 1: el clima del invernadero

Temperatura mínima · máxima (último día)—
Horas > 28 °C · horas < 12 °C—
Energía del calefactor · ventilador medio—
Estado
—

Instrumento 2: humedad, punto de rocío y condensación

Punto de rocío · vapor interior—
HR a la temperatura nocturna—
HR al renovar con aire exterior calentado a la T interior—
Estado
—

Instrumento 3: luz y lámparas (DLI)

DLI natural · déficit—
Horas de lámpara por día—
Potencia · energía por día—
Estado
—

Instrumento 4: riego por pulsos

Pérdida · consumo diario—
Por evento: agua · tiempo · pulsos de 180 s—
Se riega cada—
Estado
—

Recorrido guiado

  1. Con 3000 W de sol, ventilador de 0,40 m³/s y calefactor de 16 °C: máxima de 27,9 °C, ninguna hora por encima de 28 °C y 6,2 kWh de calefactor. Bajá el ventilador a 0,25 m³/s: 30,0 °C y 4,5 horas sobre 28 °C. A 0,10 m³/s: 35,8 °C y el estado avisa del límite de seguridad.
  2. Desmarcá el ventilador: el invernadero llega a 50,5 °C. Volvé a marcarlo y desmarcá el calefactor con un exterior medio de 5 °C y 1000 W de sol: la temperatura baja a −2,5 °C y pasan unas 14,6 horas por debajo de 12 °C.
  3. Con 1000 W de sol, 5 °C de media y el calefactor: la mínima es de 12,4 °C y se gastan 18,5 kWh. El calefactor de 1500 W no alcanza para sostener 16 °C con −3 °C afuera (hacen falta 1900 W).
  4. En el aire húmedo, con 26 °C y 60 %: punto de rocío de 17,6 °C; a la temperatura nocturna de 14 °C la HR teórica es del 126 %: condensa. Con 20 °C de noche, 86,3 %. Con 17 °C de noche, 100 %.
  5. Con aire exterior de 10 °C y 80 %: al calentarlo a 26 °C, la HR queda en 29,2 %; a 18 °C, en 47,6 %. Renovar y calentar seca el invernadero: por eso la regla de deshumidificación.
  6. En la luz, con 20 klx de pico, 30 % de nubosidad y objetivo de 17: DLI natural de 3,6 mol/m²/día, déficit de 13,4 y 9,3 horas de lámpara de 400 µmol/m²/s (960 W, 9,0 kWh). Con 200 µmol/m²/s hacen falta 18,7 horas: no entra en el fotoperiodo.
  7. Subí la luz natural a 50 klx con 100 % de nubosidad (día despejado): la DLI natural pasa de 29 y las lámparas no hacen falta.
  8. En el riego, con 5 mm/día, 4 m², 250 mm y 8 L/min: pérdida de 2 puntos por día y 20 L diarios; subir 5 puntos son 50 L, 6,25 min y 3 pulsos, cada 2,5 días. Con 10 puntos: 100 L y 5 pulsos, más que el máximo de 3.
Desafío: ampliar el invernadero a 12 m²

Se duplica la superficie y la envoltura (UA = 200 W/K, C = 1 MJ/K) con el mismo clima. ¿Qué hay que revisar? Ventilación: el sol se duplica (6000 W) y la conductancia de la envoltura también: el ΔT = 6000 / (200 + Gv); para quedar por debajo de 5,2 K hace falta Gv ≈ 950 W/K, es decir 0,79 m³/s: más que el doble del ventilador de 0,40, o dos ventiladores. Calefactor: UA × 19 K = 3800 W para −3 °C afuera: el calefactor de 1500 W es insuficiente; se necesita más potencia o aislar. Fuente de 12 V: los ventiladores y las lámparas se duplican: unos 5,5 A (6,6 A con margen); mejor repartir en dos fuentes. Riego: el consumo diario pasa a 40 L si se duplica el bancal; una electroválvula por zona. Sensores: con dos zonas térmicas distintas (extremos del invernadero) hace falta más de un sensor de temperatura y de humedad. Seguridad: el calefactor mayor requiere una protección independiente dimensionada para esa potencia. Casi todo escala con el área, pero la lista de lo que hay que volver a calcular es el verdadero resultado del ejercicio.

13 · Método de trabajo

Cómo encarar un proyecto de este tipo

  1. Escribí los requisitos con valores y tolerancias para cada variable, y qué falla es la más grave.
  2. Hacé las cuentas antes de comprar: balance térmico, caudal del ventilador, potencia del calefactor, DLI, consumo de agua, corriente de la fuente.
  3. Elegí los sensores por el ambiente (humedad, sol, agua) y duplicá los críticos con tecnología distinta.
  4. Diseñá el software por capas: drivers, interfaces, lazos simples, planificador sin bloqueos, máquina de modos.
  5. Coordiná los lazos con interbloqueos y prioridades explícitas, en un solo lugar.
  6. Armá las protecciones independientes (termostato, flotador, perro guardián, válvula normalmente cerrada) y probalas una por una.
  7. Probá de lo seguro a lo peligroso, con fallas inyectadas, y terminá con un ensayo largo con registro.
  8. Ajustá con los datos del registro y documentá consignas, calibraciones y cambios.

Si el invernadero se sobrecalienta, el ventilador es chico o falta la ventilación por humedad; si no sostiene la mínima, falta aislamiento o potencia; si condensa, la humedad y la temperatura nocturna no se coordinan; si las lámparas parpadean, el sensor las ve; si el riego se desmadra, faltan verificación y límites.

14 · Comprensión

Confusiones frecuentes

«Más potencia de calefactor siempre resuelve el frío»

La potencia necesaria depende de las pérdidas (UA por la diferencia de temperatura): aislar una envoltura mala rinde más que sumar vatios, y cuesta menos de operar.

«Cerrar todo de noche protege del frío y de la humedad»

Cerrar encierra el vapor: al bajar la temperatura, el aire se satura y condensa. Una ventilación mínima con calefacción compensa la humedad sin enfriar demasiado.

«Los lux sirven para saber cuánta luz recibe la planta»

Los lux pesan la luz según el ojo humano; la planta responde a los fotones (PPFD), y a la dosis acumulada del día (DLI). La conversión depende del tipo de luz.

«Regar hasta que el sensor diga 40 % es suficiente»

El agua tarda en llegar al sensor: sin pulsos y remojo, se riega de más y se pierde por drenaje; y sin verificación, un sensor roto o un tanque vacío no se notan.

«El ventilador proporcional y el calefactor todo o nada se pueden ajustar por separado»

Se afectan entre sí y con la humedad: sin interbloqueos pueden pelearse, desperdiciando energía; la coordinación es parte del diseño.

«Con el Wi-Fi conectado puedo controlar desde el celular, no hace falta lógica local»

Una red cae; el invernadero debe seguir seguro y funcionando solo. El control local es la base y la red un extra.

15 · Práctica guiada

Predecí antes de comprobar

1. Ventilación

Con un sol máximo de 2400 W, UA = 100 W/K y un ventilador de 0,30 m³/s a pleno (ṁ·cp = 0,30 × 1,2 × 1005), ¿cuántos grados por encima del exterior queda el invernadero en el pico?

Ver solución

Gv = 0,30 × 1206 = 362 W/K. ΔT = 2400 / (100 + 362) ≈ 5,2 K sobre el exterior.

2. Calefactor

Con UA = 100 W/K, una consigna de 16 °C y un exterior que baja a −6 °C, ¿alcanza un calefactor de 2000 W?

Ver solución

Hacen falta 100 × (16 + 6) = 2200 W, más de los 2000 W: no alcanza para sostener 16 °C (la temperatura bajaría a unos 14 °C).

3. Punto de rocío

Un invernadero está a 22 °C y 70 % de HR y se enfría de noche a 15 °C. ¿Condensa? (Presiones de saturación: 2,64 kPa a 22 °C y 1,70 kPa a 15 °C.)

Ver solución

e = 0,70 × 2,64 = 1,85 kPa, mayor que los 1,70 kPa que admite el aire a 15 °C: la HR teórica sería de 109 %: sí condensa (el punto de rocío es de unos 16,3 °C).

4. Luz

Un día aporta 6 mol/m² de luz natural. Para llegar a 15 mol/m², ¿cuántas horas necesita una lámpara de 300 µmol/m²/s?

Ver solución

Faltan 9 mol = 9 × 106 µmol; a 300 µmol/m²/s: 30 000 s = 8,3 horas.

5. Riego

Un bancal de 3 m² con raíces de 200 mm y un riego de 8 puntos de humedad: ¿cuántos litros hacen falta y cuánto tarda con 6 L/min?

Ver solución

0,08 × 200 mm × 3 m² = 48 L; a 6 L/min: 8 minutos (en pulsos de 3 minutos, 3 pulsos).

6. Diagnóstico

Cada tarde, con sol, el riego se dispara apenas el suelo baja de 35 % y otra vez 40 minutos después; y el sensor muestra un salto de 8 puntos tras cada riego, que luego baja rápido. ¿Qué pasa?

Ver solución

El sensor está muy cerca de un gotero: lee la zona mojada, con un salto rápido que luego se redistribuye. Se mueve el sensor a una zona representativa de las raíces, se alarga el remojo y se aplica el tiempo mínimo de 6 horas entre eventos, que debía impedir el segundo riego tan pronto.

16 · Síntesis

Ideas para recordar

  • Un proyecto completo es la suma de lazos simples (todo o nada, proporcional, umbrales con histéresis) más lo difícil: coordinarlos, hacerlos robustos y seguros.
  • Las cuentas van antes de comprar: balance térmico (ΔT = Q / (UA + Gv)), calefactor (UA × diferencia de temperatura), DLI, consumo de agua y corriente de la fuente (3,02 A en 12 V, 3,6 A con margen).
  • El ventilador es el componente más crítico del verano: con 0,25 m³/s el invernadero llega a 30 °C y sin ventilar a 50,5 °C; con 0,40 m³/s queda en 27,9 °C.
  • La humedad se coordina con la temperatura: al bajar la temperatura el vapor condensa (punto de rocío); renovar con aire exterior y calentarlo deshumidifica.
  • Las plantas responden a los fotones, no a los lux: se planifica la DLI y las lámparas con histéresis, ventana horaria y sin corrección gamma.
  • El riego va por pulsos con remojo y verificación del efecto; con límites de volumen, de tiempo y válvula normalmente cerrada, un sensor o un tanque que fallan no pueden inundar.
  • Los interbloqueos y las prioridades (seguridad, cultivo, confort) están en un solo lugar; sin conexión, el sistema sigue seguro.
  • Se prueba de lo seguro a lo peligroso, con fallas inyectadas y un ensayo largo con registro; la parte de tensión de red, con componentes certificados y protecciones independientes.

¿Listo para el tema 46?

Antes de avanzar, calculá cuántos grados por encima del exterior queda un invernadero con 3000 W de sol, UA = 100 W/K y un ventilador de 0,3 m³/s, explicá por qué conviene regar por pulsos con remojo y decí qué interbloqueo evita que el calefactor y el ventilador desperdicien energía. Si podés justificar las tres respuestas, ya sabés integrar un proyecto de control.

En el próximo tema aplicamos lo mismo a un sistema móvil: el robot con sensores, con ultrasonido, seguidor de línea, motores DC, encoders y evasión de obstáculos.