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:
| Variable | Objetivo | Sensor | Actuador | Ley |
|---|---|---|---|---|
| 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áxima | 24 a 28 °C de día; alarma a 30 °C | Los mismos | Ventilador (PWM) | Proporcional, banda de 4 °C |
| Humedad del aire | 60 a 85 %; alarma < 40 % | SHT31 | Ventilador y calefactor | Umbral con histéresis 85 / 80 % |
| Luz | Integral diaria (DLI) de 17 mol/m²/día | BH1750 (lux) | Lámparas LED | Umbral 8000 / 12 000 lx, ventana horaria y DLI |
| Humedad del suelo | 35 a 40 % | Capacitivo (ADC) | Electroválvula | Riego 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
| Componente | Función | Interfaz | Consumo |
|---|---|---|---|
| ESP32 (placa de desarrollo) | Control, reloj, Wi-Fi opcional | — | ~ 0,25 A a 5 V |
| SHT31 | Temperatura y humedad relativa (±0,3 °C, ±2 %) | I2C, 0x44 | mA |
| DS18B20 (sonda impermeable) | Segunda temperatura, tecnología distinta | OneWire | mA |
| BH1750 | Iluminancia (lux) | I2C, 0x23 | mA |
| Sensor capacitivo de humedad del suelo | Humedad volumétrica | ADC1 (GPIO 34) | mA |
| Interruptor de flotador | Nivel del tanque | Digital | — |
| DS3231 (reloj de tiempo real) | Hora del día (±2 ppm: 0,17 s por día) | I2C, 0x68 | mA |
| OLED SSD1306 | Estado y alarmas | I2C, 0x3C | ~ 20 mA |
| Ventilador de 12 V | Ventilación proporcional | MOSFET + PWM | 0,5 A |
| Electroválvula de 12 V (normalmente cerrada) | Riego por goteo | MOSFET + diodo de rebote | 0,4 A |
| Lámparas LED de cultivo (12 V) | Luz suplementaria | MOSFET (encendido o PWM) | 2,0 A |
| Calefactor de 1500 W (230 V) | Calefacción nocturna | SSR + contactor + termostato de seguridad | 6,5 A de red |
| Zumbador y LED | Alarmas | Digital | mA |
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:
| Tarea | Período | Duración | Qué hace |
|---|---|---|---|
| Sensores | 2 s | 3 ms | Lectura por etapas, validación, redundancia |
| Clima | 10 s | 1 ms | Calefactor, ventilador, humedad alta, interbloqueos |
| Luz | 60 s | 1 ms | Integra la DLI y decide las lámparas |
| Riego | 5 s | 0,5 ms | Máquina de estados de la válvula |
| Pantalla | 1 s | 26 ms | OLED por I2C a 400 kHz, solo lo que cambió |
| Registro | 10 min | decenas de ms | Una 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:
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:
| Escenario | T mín | T máx | h > 28 °C | h < 12 °C | Calefactor | Ventilador |
|---|---|---|---|---|---|---|
| Verano despejado, ventilador de 0,25 m³/s | 15,0 | 30,0 | 4,5 | 0 | 6,2 kWh | 33 % |
| Sin ventilación | 15,0 | 50,5 | 10,5 | 0 | 5,9 kWh | 0 % |
| Ventilador de 0,40 m³/s | 15,0 | 27,9 | 0 | 0 | 6,2 kWh | 27 % |
| Ventilador de 0,10 m³/s | 15,0 | 35,8 | 7,9 | 0 | 6,2 kWh | 40 % |
| Invierno nublado (1000 W de sol, 5 °C medios) | 12,4 | 21,7 | 0 | 0 | 18,5 kWh | 0 % |
| Invierno nublado sin calefactor | −2,5 | 21,6 | 0 | 14,6 | 0 | 0 % |
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.
| Día | DLI natural | Lámpara para llegar a 17 mol/m²/día |
|---|---|---|
| Verano despejado (50 klx de pico) | 29,7 | No hacen falta |
| Nublado (30 % de la luz) | 8,9 | — |
| Invierno nublado (20 klx, 30 %) | 3,6 | 400 µ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:
| Interacción | Efecto | Regla |
|---|---|---|
| Calefactor y ventilador | Calentar y evacuar el aire a la vez desperdicia energía | Interbloqueo: con ventilación por calor, el calefactor se apaga |
| Humedad alta de noche | Ventilar enfría; no ventilar condensa | Ventilación mínima del 30 % con calefactor activo para sostener ≥ 15 °C |
| Riego y humedad | El agua evaporada sube la HR | Regar por la mañana, con ventilación disponible |
| Lámparas y temperatura | Las lámparas aportan calor | Se apagan con más de 30 °C o en modo SEGURO |
| Lámparas y sensor de luz | El sensor ve las lámparas | Sensor 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:
- 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.
- 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.
- 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.
- 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.
- 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.
- Un ensayo de 72 horas con registro, revisando las curvas contra el modelo y buscando oscilaciones, ciclos cortos y falsas alarmas.
| Síntoma | Causa probable | Solución |
|---|---|---|
| Lecturas de temperatura altas al mediodía | Sensor al sol sin pantalla de radiación | Pantalla ventilada, a la sombra, a la altura del follaje |
| HR que se queda en 100 % o salta | Condensación sobre el sensor, deriva | Membrana, calentador del sensor, verificación contra una referencia |
| Las lámparas se encienden y apagan | El sensor de luz ve las lámparas | Sensor aislado de la luz artificial; histéresis y tiempos mínimos |
| El ESP32 no lee el sensor del suelo con el Wi-Fi activo | El sensor está en un pin de ADC2 | Mover a un pin de ADC1 |
| El ventilador zumba | PWM en frecuencia audible | PWM de 25 kHz |
| El calefactor conmuta cada pocos minutos | Histéresis chica o sensor ruidoso | ±1 °C, filtrar, tiempos mínimos |
| Riego que nunca termina o nunca empieza | Sensor del suelo mal calibrado o suelto | Calibrar; verificación de respuesta; límites |
| Reinicios aleatorios al arrancar el ventilador | Caída de tensión o ruido de las cargas de 12 V | Capacitores, 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
Instrumento 2: humedad, punto de rocío y condensación
Instrumento 3: luz y lámparas (DLI)
Instrumento 4: riego por pulsos
Recorrido guiado
- 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.
- 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.
- 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).
- 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 %.
- 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.
- 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.
- 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.
- 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
- Escribí los requisitos con valores y tolerancias para cada variable, y qué falla es la más grave.
- Hacé las cuentas antes de comprar: balance térmico, caudal del ventilador, potencia del calefactor, DLI, consumo de agua, corriente de la fuente.
- Elegí los sensores por el ambiente (humedad, sol, agua) y duplicá los críticos con tecnología distinta.
- Diseñá el software por capas: drivers, interfaces, lazos simples, planificador sin bloqueos, máquina de modos.
- Coordiná los lazos con interbloqueos y prioridades explícitas, en un solo lugar.
- Armá las protecciones independientes (termostato, flotador, perro guardián, válvula normalmente cerrada) y probalas una por una.
- Probá de lo seguro a lo peligroso, con fallas inyectadas, y terminá con un ensayo largo con registro.
- 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.