Manual del proyecto · Proyecto 03
Sistema de Riego Automatizado
Diseño, construcción y programación de un sistema de riego automatizado que regula el paso de agua con una electroválvula: primero por intervalos de tiempo, luego según la humedad del suelo medida con un higrómetro, y por último con monitoreo remoto por Internet de las Cosas (IoT).
- Dificultad:
- Nivel educativo:
- Secundario. Ciclo Básico.
Contenido del manual
- 01 Materiales y equipamiento
- 02 Regar por intervalos de tiempo Nivel inicial
- 03 Regar según la humedad del suelo Nivel intermedio
- 04 Monitorear el riego con Internet de las Cosas Nivel avanzado
Materiales y equipamiento
Insumos
| Imagen | Insumo | Cantidad | Plataforma |
|---|---|---|---|
| | Módulo relé de 5 V Comanda la electroválvula. Con ESP32, verificá que el módulo se dispare con señal de 3,3 V (los módulos con optoacoplador suelen hacerlo) o alimentalo con 5 V desde el pin VIN. | 1 | Todas |
| | Módulo reloj (RTC) Figura en la ficha de insumos del original, pero el código del proyecto NO lo usa: el riego temporizado se resuelve con delay() (nivel inicial) y millis() (nivel avanzado), no con un reloj de tiempo real. Se conserva en la lista por fidelidad a la ficha de 2019; sería la evolución natural para regar a horas fijas del día (inconsistencia documentada en los desvíos). | 1 | Todas |
| | Higrómetro de suelo (FC-28) Se usa desde el nivel intermedio. Salida analógica: a mayor lectura, suelo más seco. Con ESP32, alimentalo con 3,3 V y leelo por un GPIO del ADC1 (por ejemplo el 34, que es de solo entrada y sigue midiendo con el WiFi encendido). | 1 | Todas |
| Electroválvula de lavarropas (180°) El original la propone de 220 V (tipo lavarropas). Por seguridad, la práctica del aula usa una de baja tensión (12 V) o trabaja la lógica con el simulador; la conexión a 220 V queda como extensión exclusiva del docente, con instalación supervisada (desvío documentado). | 1 | Todas | |
| Mangueras La de entrada va conectada a una canilla; la de salida lleva el agua a las plantas. | según instalación | Todas | |
| | Resistencias Aparecen de forma genérica en la ficha del original. En el circuito básico no son imprescindibles (el módulo higrómetro y el módulo relé ya traen las suyas): quedan como material de reserva para adaptaciones. | varias | Todas |
| | Cable dupont macho-hembra | 20 | Todas |
| | Arduino UNO R3 El original de 2019 sumaba un módulo IoT OBLOQ para el nivel avanzado; ese módulo está discontinuado. Con UNO, el nivel IoT se sigue de manera conceptual y la práctica se realiza con la variante ESP32. | 1 | Arduino UNO R3 |
| | Cable USB tipo B | 1 | Arduino UNO R3 |
| | Fuente de 9 V 1 A (plug centro positivo, 5,5 x 2,1 mm) (opcional) Para alimentar el sistema sin la computadora. El ESP32 se alimenta directamente por USB con una fuente de 5 V. | 1 | Arduino UNO R3 |
| | Placa ESP32 DevKit v1 Reemplaza al conjunto Arduino UNO + módulo OBLOQ del original: el ESP32 trae WiFi integrado, necesario para el nivel avanzado (IoT). | 1 | ESP32 DevKit |
| | Cable micro USB (con línea de datos) | 1 | ESP32 DevKit |
Equipamiento del taller
- Computadora
- Soldador
- Estaño
- Alicate
- Pinza de punta
- Pinza brusela
Plano de conexionado en protoboard
Deslizá horizontalmente para ver el plano completo
| Desde | Hacia | Color de cable |
|---|---|---|
| Arduino UNO · 5V | Bus + de la protoboard | rojo |
| Arduino UNO · GND | Bus − de la protoboard | negro |
| Higrómetro FC-28 · VCC | Bus + de la protoboard | rojo |
| Higrómetro FC-28 · GND | Bus − de la protoboard | negro |
| Higrómetro FC-28 · AO | Arduino UNO · A0 | amarillo |
| Módulo relé · VCC | Bus + de la protoboard | rojo |
| Módulo relé · GND | Bus − de la protoboard | negro |
| Módulo relé · IN | Arduino UNO · 2 | azul |
| Relé · COM | Bus + de la protoboard | rojo |
| Relé · NO | LED de práctica · ánodo (+) | rojo |
| LED de práctica · cátodo (−) | Resistencia 220 Ω | negro |
| Resistencia 220 Ω | Bus − de la protoboard | negro |
Deslizá horizontalmente para ver el plano completo
| Desde | Hacia | Color de cable |
|---|---|---|
| ESP32 DevKit v1 · 3V3 | Bus + de la protoboard | rojo |
| ESP32 DevKit v1 · GND | Bus − de la protoboard | negro |
| Higrómetro FC-28 · VCC | Bus + de la protoboard | rojo |
| Higrómetro FC-28 · GND | Bus − de la protoboard | negro |
| Higrómetro FC-28 · AO | ESP32 DevKit v1 · GPIO34 | amarillo |
| Módulo relé · VCC | Bus + de la protoboard | rojo |
| Módulo relé · GND | Bus − de la protoboard | negro |
| Módulo relé · IN | ESP32 DevKit v1 · GPIO16 | azul |
| Relé · COM | Bus + de la protoboard | rojo |
| Relé · NO | LED de práctica · ánodo (+) | rojo |
| LED de práctica · cátodo (−) | Resistencia 220 Ω | negro |
| Resistencia 220 Ω | Bus − de la protoboard | negro |
Regar por intervalos de tiempo
Conectar la electroválvula
El paso del agua a la manguera del sistema de riego lo regula una electroválvulaElectroválvulaActuador que permite o interrumpe el paso de un fluido. Se acciona a través de su propia alimentación, por lo que tiene únicamente dos pines: sus estados posibles son activada o no, y se puede controlar mediante una salida digital y un relé.: una válvula que se controla eléctricamente, como las que suelen encontrarse en los lavarropas. Cuando no recibe corriente, la válvula está normalmente cerrada; al energizarse, abre y deja pasar el agua.
La electroválvula tiene dos conectores para manguera (uno de entrada y otro de salida de agua) y dos terminales eléctricos tipo pala. Lo primero que haremos es instalar las mangueras correspondientes: la de entrada irá conectada a una canilla y la de salida será la que lleve el agua directamente a las plantas.
Como los terminales de la válvula manejan más tensión de la que entrega la placa, no la conectamos directamente al Arduino: usamos un reléReléDispositivo electromagnético que funciona como un interruptor controlado por un circuito eléctrico: un electroimán abre o cierra contactos de otros circuitos independientes. Permite controlar con bajo voltaje dispositivos que utilizan mayor voltaje. como intermediario. El relé es un interruptor comandado por la placa con una señal chica (5 V en el UNO, 3,3 V en el ESP32), que abre o cierra el circuito de potencia de la válvula. El código que subamos controlará el relé y, en consecuencia, la apertura y el cierre de la electroválvula.
¡Atención! Agua y electricidad no se llevan bien. Todas las conexiones eléctricas van fuera del recorrido del agua y por encima de su nivel, y siempre que manipules el circuito hacelo con las manos secas y con el sistema desenchufado. El original trabajaba directamente con 220 V; en esta reedición la válvula es de 12 V (o se trabaja la lógica con el simulador), pero los hábitos de seguridad se practican igual, porque son los que te protegen cuando la instalación es real.
La conexión tiene dos partes:
- El circuito de potencia: la fuente de baja tensión, el relé y la electroválvula. Conectamos la fuente a la bornera COM del relé, la bornera NO a un terminal de la válvula, y el otro terminal de la válvula de vuelta al otro polo de la fuente. Así, la válvula solo recibe energía cuando el relé cierra el contacto. En el esquema original, esta rama es la que llega al enchufe de 220 V; acá va a la fuente de baja tensión.
- El circuito de control: la señal del relé hacia la placa, con un cable dupont.
En el Arduino UNO seguimos el esquema original: del módulo relé, el pin + va a 5V, el
pin − a GND y el pin de señal S al pin digital 2 (la constante
PIN_RELE_VALVULA del código del paso siguiente).
En el ESP32 el armado es el mismo, pero el pin de señal del relé va a un GPIO de propósito
general (evitamos los GPIO 0, 2, 12 y 15, que intervienen en el arranque de la placa). El
número exacto está en la constante PIN_RELE_VALVULA al comienzo del código del paso
siguiente: conectá el cable al GPIO que indica esa constante. Como el ESP32 trabaja a 3,3 V,
usá un módulo relé cuya entrada acepte esa señal (la mayoría lo hace, aunque se alimenten con
5 V) y nunca inyectes 5 V en un GPIO.
Verificá
Antes de energizar, repasá contra el esquema: la señal del relé al pin correcto, la alimentación del relé (+, −) y el lazo de potencia fuente → COM → NO → válvula → fuente. Las mangueras quedaron firmes en la entrada (desde la canilla) y la salida (al riego). La válvula todavía no se va a mover: falta el programa.
Programar el funcionamiento del dispositivo
La programación la realizaremos directamente en el lenguaje de Arduino (C++), usando el
Arduino IDE en su versión 2.x, que se descarga gratis desde
arduino.cc/en/software. Un programa de Arduino se llama
sketch y tiene dos bloques: setup(), que se ejecuta una sola vez al inicializarse el
dispositivo, y loop(), que se ejecuta repetidamente después. Los comentarios (todo lo que
sigue a //) no tienen efecto en el programa: están para que el código sea más fácil de
interpretar.
Para asegurarnos de que el sistema funcione, empezamos con una prueba simple: mantener la
válvula abierta un rato y luego cerrada otro rato, en un ciclo que se repite. En el código,
al poner la salida del relé en VALVULA_ABIERTA (estado ALTO) enviamos corriente al relé,
que permite el paso de energía a la electroválvula para que se abra y riegue; al ponerla
en VALVULA_CERRADA (estado BAJO) cortamos esa energía y la válvula se cierra.
Los tiempos de cada tramo están en dos constantes al comienzo del programa,
DURACION_RIEGO_MS (cuánto riega) y DURACION_ESPERA_MS (cuánto espera entre riegos),
expresadas en milisegundos. El programa las usa con delay(), que detiene todo hasta que se
cumple el tiempo: en este primer nivel es la herramienta más simple y hace que el código se
lea igual que la secuencia real.
Ver el código completo · riego-temporizado.ino
// Riego por tiempo: una electroválvula, controlada por un relé, se abre
// durante un rato para regar y luego se cierra durante un rato más largo,
// en un ciclo que se repite para siempre. No hay sensores todavía: el
// riego depende solo del reloj interno (los delay).
//
// SEGURIDAD: agua y electricidad no se llevan bien. Todas las conexiones
// eléctricas van fuera y POR ENCIMA del nivel del agua. La electroválvula
// del original es de lavarropas (220 V): en el aula se usa una válvula de
// baja tensión (12 V) o se simula la carga, y la conexión a 220 V queda
// reservada al docente o a una instalación supervisada, nunca sobre la
// protoboard (desvío pedagógico acordado).
//
// Plataforma: Arduino UNO.
// Conexión (la del esquema original): entrada "S" del módulo relé de la
// electroválvula → pin 2.
//
// Basado en: Fragmentos de código 1 y 2 — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: se reemplazó el código generado por mBlock3 (_delay,
// _loop) por C++ idiomático de Arduino con constantes nombradas.
//
// Nota pedagógica: la ficha de insumos del PDF menciona un "módulo reloj"
// (RTC), pero el código del original NO lo usa: temporiza con delay. Un
// RTC sería la evolución natural (regar a horas fijas del día, no cada X
// tiempo desde el encendido), pero queda fuera del alcance de este nivel.
// Relé que controla la electroválvula de entrada de agua.
const int PIN_RELE_VALVULA = 2;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta,
// pasa el agua). Si tu módulo es activo-bajo, invertí solo estas dos.
const int VALVULA_ABIERTA = HIGH; // riega
const int VALVULA_CERRADA = LOW; // corta el agua
// Tiempos del ejemplo del original (Fragmento 2): riega 2 minutos y luego
// espera 1 hora. OJO en el aula: una hora es una eternidad para probar;
// bajá estos valores a segundos (por ejemplo 5000 y 10000) mientras
// verificás el circuito, y recién después poné los tiempos reales de tu
// huerta. En el nivel intermedio, el higrómetro reemplaza este reloj fijo.
const unsigned long DURACION_RIEGO_MS = 120000UL; // 2 minutos regando
const unsigned long DURACION_ESPERA_MS = 3600000UL; // 1 hora sin regar
void setup() {
pinMode(PIN_RELE_VALVULA, OUTPUT);
}
void loop() {
// delay() detiene todo el programa: en este nivel es la herramienta que
// ya conocemos y hace que el código se lea igual que la secuencia real.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
delay(DURACION_RIEGO_MS);
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
delay(DURACION_ESPERA_MS);
} // Riego por tiempo: una electroválvula, controlada por un relé, se abre
// durante un rato para regar y luego se cierra durante un rato más largo,
// en un ciclo que se repite para siempre. No hay sensores todavía: el
// riego depende solo del reloj interno (los delay).
//
// SEGURIDAD: agua y electricidad no se llevan bien. Todas las conexiones
// eléctricas van fuera y POR ENCIMA del nivel del agua. La electroválvula
// del original es de lavarropas (220 V): en el aula se usa una válvula de
// baja tensión (12 V) o se simula la carga, y la conexión a 220 V queda
// reservada al docente o a una instalación supervisada, nunca sobre la
// protoboard (desvío pedagógico acordado).
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: entrada "S" del módulo relé de la electroválvula → GPIO 16.
// Nota eléctrica: el ESP32 trabaja a 3,3 V (no 5 V como el UNO). Elegí un
// módulo relé cuya entrada acepte señal de 3,3 V (la mayoría la aceptan
// aunque se alimenten con 5 V) y nunca inyectes 5 V en un GPIO.
//
// Basado en: Fragmentos de código 1 y 2 — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: se reemplazó el código generado por mBlock3 (_delay,
// _loop) por C++ idiomático con constantes nombradas, y se portó a ESP32
// con un GPIO seguro (el original usaba el pin 2 del UNO).
//
// Nota pedagógica: la ficha de insumos del PDF menciona un "módulo reloj"
// (RTC), pero el código del original NO lo usa: temporiza con delay. Un
// RTC sería la evolución natural (regar a horas fijas del día), pero queda
// fuera del alcance de este nivel.
// Relé que controla la electroválvula de entrada de agua.
const int PIN_RELE_VALVULA = 16;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta,
// pasa el agua). Si tu módulo es activo-bajo, invertí solo estas dos.
const int VALVULA_ABIERTA = HIGH; // riega
const int VALVULA_CERRADA = LOW; // corta el agua
// Tiempos del ejemplo del original (Fragmento 2): riega 2 minutos y luego
// espera 1 hora. OJO en el aula: una hora es una eternidad para probar;
// bajá estos valores a segundos (por ejemplo 5000 y 10000) mientras
// verificás el circuito, y recién después poné los tiempos reales de tu
// huerta. En el nivel intermedio, el higrómetro reemplaza este reloj fijo.
const unsigned long DURACION_RIEGO_MS = 120000UL; // 2 minutos regando
const unsigned long DURACION_ESPERA_MS = 3600000UL; // 1 hora sin regar
void setup() {
pinMode(PIN_RELE_VALVULA, OUTPUT);
}
void loop() {
// delay() detiene todo el programa: en este nivel es la herramienta que
// ya conocemos y hace que el código se lea igual que la secuencia real.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
delay(DURACION_RIEGO_MS);
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
delay(DURACION_ESPERA_MS);
} El programa viene con los tiempos del ejemplo del original (riega 2 minutos y luego espera 1 hora). Para probar en el aula, una hora es una eternidad: bajá provisoriamente esas constantes a segundos (por ejemplo unos pocos miles de milisegundos) mientras verificás el circuito, y recién después cargá los tiempos reales de tu huerta, que vas a definir en el paso 3.
Podés ver el comportamiento —la válvula abriendo y cerrando por intervalos— en el simulador, antes de tocar el agua real:
Simulación del comportamiento
La misma máquina de estados del firmware, portada a TypeScript, maneja el
comportamiento del dispositivo. No se ejecuta el binario real: la ejecución
del .hex con avr8js está en el roadmap.
Simulación lista. Presioná «Iniciar» para arrancar la secuencia.
Para subir el código a la placa, conectala a la computadora con el cable USB, elegí en el Arduino IDE 2.x la placa y el puertoPuerto COMPuerto de comunicaciones por el cual el sistema operativo se comunica con un dispositivo externo, como la placa. Se asigna automáticamente al conectarla por USB y puede cambiar de número; en el IDE hay que indicar cuál usar. (en el IDE 2.x se eligen juntos en el menú desplegable de la barra superior) y apretá el botón Subir (la flecha →). Al terminar, aparece el mensaje de carga completada en la barra inferior.
Para el Arduino UNO: usá el cable USB tipo B, elegí la placa Arduino UNO y el puerto que
se agregó al conectarla (en Windows es un puerto COM numerado; en Linux suele llamarse
/dev/ttyACM0 o similar).
Para el ESP32 hay dos pasos previos que se hacen una sola vez: instalar el soporte de placas ESP32 desde el gestor de placas del IDE (buscá “esp32” e instalá el paquete de Espressif) y, si el puerto no aparece, instalar el driver del conversor USB-serie de tu placa (generalmente CP210x o CH340). Después, elegí la placa ESP32 Dev Module (o “DOIT ESP32 DEVKIT V1”) y el puerto correspondiente. Si al subir el IDE queda esperando en “Connecting…”, mantené apretado el botón BOOT de la placa hasta que empiece la carga.
Para el aula
El material original de 2019 enseñaba este paso con bloques en mBlock3, hoy discontinuado. La
función didáctica de los bloques —bajar la barrera de entrada— la cumple acá la combinación de
un código corto con constantes nombradas, comentado, y el simulador en el navegador. Un buen
disparador: pedir a los grupos que predigan qué pasa si intercambian VALVULA_ABIERTA y
VALVULA_CERRADA, y por qué. Detalle a comentar en clase: la ficha de insumos del original
incluye un módulo reloj (RTC) que este código nunca usa; el riego se temporiza con delay().
Un RTC sería la evolución natural para regar a horas fijas del día, y queda como desafío para
grupos que terminen antes.
Verificá
Probalo en seco, sin agua: al energizar, el LED del módulo relé tiene que encenderse durante el tramo de riego y apagarse durante el de espera, conmutando con un clic. Si redujiste las constantes a segundos, vas a ver el ciclo completo en poco tiempo. Recién después probá con agua: la válvula tiene que dejar pasar el agua durante el riego y cortarla durante la espera.
Determinar tiempos de riego adecuados
En el programa anterior, la válvula regaba y esperaba tiempos de ejemplo. Ahora hay que ajustarlos a la realidad de tus plantas.
La frecuencia de riego necesaria varía según la necesidad de las plantas seleccionadas, las condiciones climáticas, el tipo de suelo y su cobertura (por ejemplo, si tiene hojarasca o no), y la cantidad de agua aportada en cada evento de riego. En este sentido, es interesante que los estudiantes investiguen previamente acerca de las necesidades de las plantas elegidas, mediante la búsqueda de información en distintas fuentes o la realización de entrevistas a personas expertas en el tema.
Una vez determinado el tiempo de riego más adecuado, hay que expresarlo en milisegundos y
cargarlo en las constantes DURACION_RIEGO_MS y DURACION_ESPERA_MS. Por ejemplo, si querés
que riegue 2 minutos y luego espere 1 hora, esos tiempos son 120000 y 3600000
milisegundos, respectivamente (1 segundo son 1000 milisegundos). Volvé a subir el programa
con tus valores.
¿Cada cuánto y cuánto?
Investiguen en grupo las necesidades de riego de las plantas de su huerta o maceta y armen una tabla: planta, frecuencia recomendada y duración de cada riego. Después traduzcan esos valores a las constantes del programa. ¿Qué limitación tiene regar “cada cierto tiempo desde que se enciende la placa” en lugar de regar “a tal hora del día”? (Pista: esa es exactamente la diferencia que resolvería el módulo reloj de la ficha… y la que resuelve el higrómetro del próximo nivel, midiendo la tierra en vez de mirar el reloj.)
Cierre del nivel
Al terminar este nivel, tu sistema riega solo: la placa abre la electroválvula durante el tiempo de riego que definiste y la cierra durante la espera, en un ciclo automático. Además, ya sabés escribir y subir programas desde el Arduino IDE 2.x, una herramienta que te va a acompañar el resto del proyecto. Pero regar “por reloj” tiene un límite: riega llueva o truene, esté la tierra seca o empapada. En el nivel intermedio el sistema va a dejar de mirar el reloj y va a mirar la tierra, con un higrómetro que mide la humedad del suelo y decide cuándo hace falta regar.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- La electroválvula está instalada con sus mangueras (entrada desde la canilla, salida al riego) y conectada al relé, con el circuito de potencia separado del de control y lejos del agua.
- Sabés subir un programa desde el Arduino IDE 2.x: elegir la placa, elegir el puerto y verificar que el código quedó cargado.
- El sistema abre y cierra la válvula por intervalos de tiempo, con los valores DURACION_RIEGO_MS y DURACION_ESPERA_MS ajustados (o reducidos para probar en el aula).
- Investigaste y determinaste una frecuencia de riego adecuada para las plantas elegidas.
Regar según la humedad del suelo
Situación problema
Luego de haber utilizado este sistema de riego por varios meses, de realizar observaciones y registros de lo que sucede con sus plantas, los estudiantes notan que la frecuencia de riego necesaria varía en función de distintos factores que afectan a la humedad del suelo.
Uno de ellos es la temperatura ambiente que, al aumentar, hace que el agua que está en el suelo se evapore más rápido. Por ese motivo, deciden instalar un sensor de humedad del suelo que les permita saber cuándo es necesario regar y, así, evitar el consumo de agua cuando no se necesita.
En esta instancia del proyecto se propone incluir al sistema un higrómetro de suelo (FC-28), que permita medir la humedad del suelo y regular la apertura de la electroválvula en base a los datos obtenidos.
Conectar el higrómetro
En el nivel inicial desarrollamos un programa que controla la frecuencia de riego abriendo y cerrando una electroválvulaElectroválvulaActuador que permite o interrumpe el paso de un fluido. Se acciona a través de su propia alimentación, por lo que tiene únicamente dos pines: sus estados posibles son activada o no, y se puede controlar mediante una salida digital y un relé. por tiempo. Ahora vamos a ajustar ese riego en base a la información que obtengamos midiendo la humedad del suelo: regar cuando la humedad sea baja y dejar de regar cuando alcance un valor que consideremos suficiente.
Para eso usamos un higrómetro de sueloHigrómetro de sueloSensor que estima la humedad del suelo midiendo su conductividad eléctrica. Entrega una salida analógica que se conecta a una entrada A0–A5 del Arduino; sirve para distinguir un suelo seco de uno húmedo, no para una medición precisa. (FC-28), un sensor que mide la humedad de la tierra a partir de su conductividad eléctrica.
El módulo tiene tres pines de conexión: dos para la alimentación (VCC y GND) y un tercero de salida analógica, que entrega un nivel de tensión según la humedad registrada. Por eso se conecta a una entrada analógica de la placa: esas entradas digitalizan la señal y devuelven un número proporcional a la tensión de entrada.
Para obtener una buena medición hay que enterrar la horquilla del sensor en un lugar que represente lo más fielmente posible las condiciones generales de la huerta, cantero o maceta. Una mala ubicación (por ejemplo, fuera de la zona de riego) puede hacer que algunas zonas queden muy secas y otras muy húmedas.
En el Arduino UNO seguimos el esquema original: VCC al pin 5V, GND a GND y la
salida analógica del módulo a la entrada A0 (la constante PIN_HIGROMETRO del código del
paso 5). Las entradas analógicas del UNO (A0 a A5) devuelven un valor entre 0 y 1023.
En el ESP32 la conexión es equivalente, con dos cuidados propios de la placa: alimentá el
módulo con 3,3 V (no 5 V) para que su salida no supere ese nivel, y leelo por un GPIO del
ADC1, que sigue funcionando con el WiFi encendido. El número exacto está en la constante
PIN_HIGROMETRO del código del paso 5 (el GPIO 34, que además es de solo entrada). Su
conversor es de 12 bits, así que devuelve un valor entre 0 y 4095, en lugar del 0 a 1023
del UNO.
Leer el puerto serie
Cuando trabajamos con entradas digitales, que solo tienen dos estados, es fácil reflejar su estado con un LED. Pero el higrómetro es analógico: no da dos valores sino un rango (todos los niveles posibles de humedad de la tierra). Para ver esos datos y tomar decisiones en base a ellos usamos el puerto serie.
El puerto seriePuerto COMPuerto de comunicaciones por el cual el sistema operativo se comunica con un dispositivo externo, como la placa. Se asigna automáticamente al conectarla por USB y puede cambiar de número; en el IDE hay que indicar cuál usar. es un canal de comunicación entre la placa y la computadora. Lo vamos a usar para ver en pantalla los valores que registra el higrómetro. En la placa, el puerto serie está físicamente vinculado al mismo cable USB con el que subimos los programas, así que sirve tanto para cargar el código como para intercambiar mensajes.
En el Arduino UNO ese puerto está conectado a los pines 0 (RX) y 1 (TX): en proyectos que usen el puerto serie, no conectes nada a esos dos pines, porque quedan reservados para la comunicación (por eso el higrómetro va a A0 y no ahí).
En el código, para habilitar el puerto serie se usa Serial.begin() con una velocidad —en
este proyecto, la constante VELOCIDAD_SERIAL, de 115200 baudios— y para enviar un mensaje se
usa Serial.println(). Del lado de la computadora, en el Arduino IDE 2.x abrimos el Monitor
Serie (el ícono de la lupa arriba a la derecha, o desde el menú Herramientas) y
seleccionamos la misma velocidad, 115200 baudios, en su menú desplegable. Si los caracteres
se ven ilegibles, casi siempre es porque la velocidad del Monitor no coincide con la del
programa.
Leer el higrómetro por el puerto serie
Ahora que sabemos comunicarnos con la computadora por el puerto serie, vamos a transmitir los
valores que leemos en la entrada analógica donde está el higrómetro. El programa que armaremos
en el paso 5 hace exactamente eso: en cada vuelta lee el sensor con analogRead(PIN_HIGROMETRO),
guarda el número en una variable y lo envía a la computadora con Serial.println().
Cada vez que subís un programa nuevo, el IDE usa el puerto para la carga, así que puede que el Monitor Serie se corte un instante; una vez terminada la subida, volvés a verlo actualizarse. Deberías empezar a recibir valores dentro del rango de tu placa (0 a 1023 en el UNO, 0 a 4095 en el ESP32) que cambian con la humedad: probá clavar la horquilla en tierra seca y en tierra mojada y observá cómo se mueve el número. Ese “movimiento” es lo que vamos a usar para decidir.
Para el aula
Vale hacer visible acá el hábito que sostiene todo lo que sigue: primero medir, después
programar la decisión. Antes de escribir un solo if, que cada grupo tome nota de qué número
ve con la tierra seca, con la tierra recién regada y en un punto intermedio. Sin esos datos
reales, los umbrales del paso 4 son adivinanza. Un buen registro en el cuaderno acá vale más
que el código.
Determinar los valores de humedad para activar la válvula
El higrómetro nos va a permitir decidir cuándo abrir la válvula (cuando el suelo esté demasiado seco) y cuándo cerrarla (cuando esté suficientemente húmedo). Para eso primero tenemos que fijar dos valores de referencia.
Acá hay un detalle que conviene tener muy claro, porque es fácil equivocarse: en estos módulos resistivos, la lectura es inversa. A mayor valor leído, el suelo está más seco (hay menos agua conduciendo, así que el sensor “ve” más resistencia). No al revés. Por eso:
- El umbral de “seco” es el valor alto: la constante
UMBRAL_SECO. Cuando la lectura lo supera, la tierra está demasiado seca y hay que regar. - El umbral de “húmedo” es el valor bajo: la constante
UMBRAL_HUMEDO. Cuando la lectura cae por debajo de él, la tierra está suficientemente húmeda y hay que cortar.
Ahora que ya podemos ver qué valores arroja el higrómetro por el puerto serie, tomamos
muestras de tierra con distintos grados de humedad en unos recipientes, les colocamos el
sensor y vamos anotando los valores (sin olvidar limpiar y secar bien la horquilla entre una
muestra y la siguiente). Con esos números elegimos tus UMBRAL_SECO y UMBRAL_HUMEDO. El
programa del paso 5 ya viene con los valores del ejemplo del original cargados en esas
constantes, pero son un punto de partida: se miden en tu suelo, no se copian.
La franja del medio
Fijate que UMBRAL_SECO y UMBRAL_HUMEDO no son el mismo número: entre los dos queda una
franja. Discutan en grupo: cuando la lectura está en esa franja intermedia, ¿la válvula debería
abrir o cerrar? ¿Qué pasaría si los dos umbrales fueran el mismo valor y la lectura quedara
bailando justo ahí? Anoten su hipótesis: el código del paso 5 resuelve exactamente ese
problema, y no por casualidad.
Programar la apertura y el cierre de la válvula según la humedad
Con los umbrales definidos, editamos el programa para que el higrómetro comande la válvula. La
lógica, en cada vuelta de loop(), es la que definimos en el paso anterior:
- Leer el higrómetro una vez y guardar el valor (y publicarlo por el puerto serie, para seguir viéndolo).
- Si la lectura supera
UMBRAL_SECO, la tierra está demasiado seca: abrir la válvula (VALVULA_ABIERTA) para regar. - Si la lectura cae por debajo de
UMBRAL_HUMEDO, la tierra está húmeda: cerrar la válvula (VALVULA_CERRADA).
Ver el código completo · riego-por-humedad.ino
// Riego por humedad: un higrómetro de suelo (FC-28) mide qué tan seca está
// la tierra y el programa abre o cierra la electroválvula en función de eso.
// El higrómetro también se imprime por la consola serial para poder
// calibrar los umbrales observando valores reales.
//
// CONVENCIÓN DEL HIGRÓMETRO (¡importante!): en estos módulos resistivos,
// MAYOR lectura = tierra MÁS SECA (más resistencia, menos agua conduciendo).
// Por eso "seco" es el umbral ALTO y "húmedo" el umbral BAJO. El original
// lo confirma: "mayor a 750 => demasiado seco; menor a 380 => húmedo".
//
// HISTÉRESIS NATURAL DEL ORIGINAL (se preserva tal cual): son dos ifs
// independientes con DOS umbrales distintos. Por encima de 750 abre; por
// debajo de 380 cierra; en la franja intermedia (380 a 750) NINGUNO de los
// dos se cumple, así que la válvula conserva su estado anterior. Esa banda
// muerta evita que la válvula traquetee cuando la lectura baila cerca de un
// único umbral: es una solución elegante que ya venía en el original.
//
// SEGURIDAD: agua y electricidad no se llevan bien. Conexiones eléctricas
// fuera y por encima del agua. Electroválvula de baja tensión (12 V) o
// simulación en el aula; 220 V solo docente/instalación supervisada, nunca
// sobre la protoboard (desvío pedagógico acordado).
//
// Plataforma: Arduino UNO.
// Conexión (la del esquema original): señal analógica del higrómetro → A0;
// entrada "S" del módulo relé de la electroválvula → pin 2.
//
// Basado en: Fragmento de código 5 — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: constantes nombradas en lugar del C de mBlock3; el
// original llamaba a analogRead(A0) tres veces por vuelta (una para
// imprimir y una por cada if), lo que podía dar tres valores distintos;
// acá se lee UNA vez a una variable y esa misma lectura se imprime y se
// compara. Es más correcto y hace evidente que se decide sobre un único dato.
const int PIN_HIGROMETRO = A0;
const int PIN_RELE_VALVULA = 2;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int VALVULA_ABIERTA = HIGH;
const int VALVULA_CERRADA = LOW;
// Umbrales del original (escala del UNO: 0 a 1023). NO son mágicos: salen
// de medir muestras de tierra con distintos grados de humedad y anotar los
// valores por la consola (Paso 4 del original). Ajustalos a TU suelo.
const int UMBRAL_SECO = 750; // por encima: tierra demasiado seca → regar
const int UMBRAL_HUMEDO = 380; // por debajo: tierra húmeda → cortar
const long VELOCIDAD_SERIAL = 115200; // la del original
// El original medía una vez por segundo (_delay(1)).
const unsigned long INTERVALO_MEDICION_MS = 1000;
void setup() {
pinMode(PIN_HIGROMETRO, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Estado inicial SEGURO: arrancamos con la válvula cerrada. Sin esta línea
// el pin queda en LOW por defecto; si invertís las constantes para un módulo
// activo-bajo, ese LOW pasaría a ser "abierta" y, si al encender la lectura
// cae en la banda muerta (entre 380 y 750), la válvula regaría sin control.
// Regla de oro: dejá SIEMPRE el actuador en estado seguro antes del loop.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
Serial.begin(VELOCIDAD_SERIAL);
}
void loop() {
int humedad = analogRead(PIN_HIGROMETRO);
// Publicamos la lectura por consola: sirve para calibrar los umbrales
// y para ver en vivo qué "piensa" el sistema del suelo.
Serial.println(humedad);
// Histéresis del original: dos ifs independientes, dos umbrales.
if (humedad > UMBRAL_SECO) {
// Tierra demasiado seca: abrir la válvula para regar.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
}
if (humedad < UMBRAL_HUMEDO) {
// Tierra suficientemente húmeda: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
}
// Entre 380 y 750 no se cumple ninguno: la válvula queda como estaba.
delay(INTERVALO_MEDICION_MS);
} // Riego por humedad: un higrómetro de suelo (FC-28) mide qué tan seca está
// la tierra y el programa abre o cierra la electroválvula en función de eso.
// El higrómetro también se imprime por la consola serial para poder
// calibrar los umbrales observando valores reales.
//
// CONVENCIÓN DEL HIGRÓMETRO (¡importante!): en estos módulos resistivos,
// MAYOR lectura = tierra MÁS SECA (más resistencia, menos agua conduciendo).
// Por eso "seco" es el umbral ALTO y "húmedo" el umbral BAJO. El original
// lo confirma: "mayor a 750 => demasiado seco; menor a 380 => húmedo".
//
// HISTÉRESIS NATURAL DEL ORIGINAL (se preserva tal cual): son dos ifs
// independientes con DOS umbrales distintos. Por encima del umbral seco
// abre; por debajo del húmedo cierra; en la franja intermedia NINGUNO de
// los dos se cumple, así que la válvula conserva su estado anterior. Esa
// banda muerta evita que la válvula traquetee cuando la lectura baila
// cerca de un único umbral: es una solución elegante que ya venía en el
// original.
//
// DIFERENCIA DE ADC (didáctica): el conversor del ESP32 es de 12 bits, así
// que analogRead() devuelve 0 a 4095 (3,3 V), NO el 0 a 1023 (10 bits, 5 V)
// del UNO. Los umbrales del original (750 y 380) se reescalan en la misma
// proporción: 750/1023 ≈ 3000/4095 y 380/1023 ≈ 1520/4095. Mismo fenómeno,
// distinta "regla de medir".
//
// SEGURIDAD: agua y electricidad no se llevan bien. Conexiones eléctricas
// fuera y por encima del agua. Electroválvula de baja tensión (12 V) o
// simulación en el aula; 220 V solo docente/instalación supervisada, nunca
// sobre la protoboard (desvío pedagógico acordado).
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: señal analógica del higrómetro → GPIO 34; relé de la
// electroválvula → GPIO 16.
// Nota eléctrica: el ESP32 trabaja a 3,3 V. El GPIO 34 es de SOLO ENTRADA
// y pertenece al ADC1 (sigue midiendo con WiFi activo, a diferencia del
// ADC2). El módulo higrómetro de 3 pines ya entrega una señal analógica
// lista para el pin; alimentalo con 3,3 V para que su salida no supere ese
// nivel.
//
// Basado en: Fragmento de código 5 — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: constantes nombradas y portado a ESP32 (el original usaba
// A0 y el pin 2 del UNO); umbrales reescalados al ADC de 12 bits; el
// original llamaba a analogRead tres veces por vuelta (una para imprimir y
// una por cada if), lo que podía dar tres valores distintos; acá se lee UNA
// vez a una variable y esa misma lectura se imprime y se compara.
const int PIN_HIGROMETRO = 34;
const int PIN_RELE_VALVULA = 16;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int VALVULA_ABIERTA = HIGH;
const int VALVULA_CERRADA = LOW;
// Umbrales del original reescalados al ADC de 12 bits del ESP32.
// Ajustalos a TU suelo midiendo con la consola (Paso 4 del original).
const int UMBRAL_SECO = 3000; // por encima: tierra seca → regar (750 en UNO)
const int UMBRAL_HUMEDO = 1520; // por debajo: tierra húmeda → cortar (380 en UNO)
const long VELOCIDAD_SERIAL = 115200; // la del original
// El original medía una vez por segundo (_delay(1)).
const unsigned long INTERVALO_MEDICION_MS = 1000;
void setup() {
pinMode(PIN_HIGROMETRO, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Estado inicial SEGURO: arrancamos con la válvula cerrada. Sin esta línea
// el pin queda en LOW por defecto; si invertís las constantes para un módulo
// activo-bajo, ese LOW pasaría a ser "abierta" y, si al encender la lectura
// cae en la banda muerta (entre 1520 y 3000), la válvula regaría sin control.
// Regla de oro: dejá SIEMPRE el actuador en estado seguro antes del loop.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
Serial.begin(VELOCIDAD_SERIAL);
}
void loop() {
int humedad = analogRead(PIN_HIGROMETRO);
// Publicamos la lectura por consola: sirve para calibrar los umbrales
// y para ver en vivo qué "piensa" el sistema del suelo.
Serial.println(humedad);
// Histéresis del original: dos ifs independientes, dos umbrales.
if (humedad > UMBRAL_SECO) {
// Tierra demasiado seca: abrir la válvula para regar.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
}
if (humedad < UMBRAL_HUMEDO) {
// Tierra suficientemente húmeda: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
}
// Entre el umbral húmedo y el seco no se cumple ninguno: la válvula
// queda como estaba.
delay(INTERVALO_MEDICION_MS);
} Hay un detalle elegante que ya venía en el original: son dos if independientes con dos
umbrales distintos. Cuando la lectura queda en la franja intermedia (entre UMBRAL_HUMEDO y
UMBRAL_SECO), ninguno de los dos se cumple, así que la válvula conserva el estado que
tenía. Esa banda “muerta” es una histéresis natural: evita que la válvula traquetee
abriendo y cerrando sin parar cuando la lectura baila cerca de un único punto. Es la respuesta
al desafío del paso 4.
Podés ver el sistema completo —el higrómetro midiendo, la lectura subiendo cuando la tierra se seca y la válvula regando hasta humedecerla— en el simulador:
Simulación del comportamiento
La misma máquina de estados del firmware, portada a TypeScript, maneja el
comportamiento del dispositivo. No se ejecuta el binario real: la ejecución
del .hex con avr8js está en el roadmap.
Simulación lista. Presioná «Iniciar» para arrancar la secuencia.
Verificá
Con el Monitor Serie abierto a 115200 baudios, probalo primero en seco: al clavar la horquilla
en tierra seca (o al dejar el sensor al aire), la lectura sube por encima de UMBRAL_SECO y la
válvula tiene que abrir (el LED del relé se enciende); al mojar la tierra, la lectura baja por
debajo de UMBRAL_HUMEDO y la válvula tiene que cerrar. Si abre y cierra sin parar, revisá que
UMBRAL_SECO sea mayor que UMBRAL_HUMEDO y que haya una franja razonable entre los dos.
Cierre del nivel
Al terminar este nivel, el sistema dejó de regar “por reloj” y pasó a regar “por necesidad”: el higrómetro mide la humedad del suelo y la placa abre la válvula solo cuando la tierra está seca, cortando cuando ya está húmeda. Aprendiste a leer un sensor analógico por el puerto serie, a calibrar umbrales con mediciones reales y a aprovechar una histéresis que evita el traqueteo de la válvula. En el nivel avanzado, los estudiantes y docentes van a poder mirar todo esto desde el celular: vamos a publicar la humedad del suelo y el estado de la válvula por Internet de las Cosas.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- El higrómetro está conectado a la entrada analógica de la placa (A0 en el UNO, GPIO 34 en el ESP32) y su horquilla clavada en un lugar representativo de la tierra a regar.
- Sabés abrir el Monitor Serie del Arduino IDE 2.x a 115200 baudios y leer los valores que reporta el higrómetro.
- Determinaste tus umbrales UMBRAL_SECO y UMBRAL_HUMEDO tomando muestras, entendiendo que a mayor lectura, tierra más seca.
- El sistema riega cuando la tierra está seca y corta cuando está húmeda, con la banda entre umbrales evitando que la válvula traquetee.
Monitorear el riego con Internet de las Cosas
Situación problema
En última instancia, estudiantes y docentes se propusieron generar un sistema que les permitiera monitorear remotamente, desde un dispositivo móvil, el nivel de humedad del suelo y el estado de la válvula. Así, sin ir hasta la huerta, pueden saber si la tierra está seca, si el sistema está regando y si todo funciona como esperan.
En esta tercera instancia se programará el envío de los datos obtenidos a un dispositivo móvil a través de internet (IoT).
Introducción a Internet de las Cosas (IoT)
Internet de las Cosas (en inglés Internet of Things, abreviado IoTIoT (Internet de las Cosas)Interconexión digital de objetos cotidianos con internet. Permite, por ejemplo, enviar los datos de un sensor a una central y visualizarlos desde un dispositivo móvil. Requiere un dispositivo capaz de conectarse a internet y un servidor que reciba y aloje los datos.) es un concepto que refiere a la interconexión digital de objetos cotidianos con internet. Esta interconexión puede tener diversas funciones. Por ejemplo, monitorear la temperatura de un ambiente enviando los datos de un sensor a una central donde se recopile la información, para visualizarla desde un dispositivo móvil: la temperatura de un laboratorio, de un invernadero o de una sala de un hospital.
Para poder incorporar IoT a nuestro proyecto es necesario:
- Un dispositivo capaz de conectarse a internet.
- Un servidor que reciba y aloje los datos.
Existen diversas formas de registrar y almacenar los datos del sistema de riego. En este caso, se detallará cómo hacerlo con el WiFi integrado de la placa ESP32ESP32Placa con un microcontrolador de Espressif que trae WiFi (y Bluetooth) integrados. Se programa desde el Arduino IDE igual que un Arduino, con pines llamados GPIO. En este proyecto reemplaza al conjunto Arduino UNO + módulo OBLOQ para el nivel IoT. y con los servidores de Adafruit IOAdafruit IOPlataforma online de uso gratuito, orientada al uso educativo, que centraliza y gestiona la información que reportan los dispositivos IoT. Permite crear feeds y paneles de control para monitorear los datos desde cualquier dispositivo..
El material original de 2019 resolvía este punto agregando al Arduino UNO un módulo externo llamado OBLOQ, un adaptador WiFi-serie de DFRobot hoy discontinuado (igual que su biblioteca ObloqAdafruit). Como el UNO clásico no tiene conectividad propia, en esta reedición la práctica de IoT se realiza con la variante ESP32 del proyecto: podés seguir este nivel de manera conceptual con tu UNO (el paso 3, sobre código no bloqueante, funciona perfectamente en él) y cambiar al ESP32 con el selector de plataforma para la parte práctica de conexión, que es idéntica en lo didáctico y más simple en el circuito.
El ESP32 cumple los dos roles del “dispositivo capaz de conectarse a internet”: es el microcontrolador que ya está midiendo la humedad y manejando la válvula y, a la vez, trae radio WiFi integrada. No hace falta ningún módulo adicional ni cableado extra: la conexión a internet se resuelve por completo desde el código.
Crear un panel de control en Adafruit IO
Primero se explicará cómo crear un panel de control en Adafruit IOAdafruit IOPlataforma online de uso gratuito, orientada al uso educativo, que centraliza y gestiona la información que reportan los dispositivos IoT. Permite crear feeds y paneles de control para monitorear los datos desde cualquier dispositivo., una plataforma online con posibilidad de uso gratuito, orientada al uso educativo, que centraliza la información que reportan los dispositivos. Empezamos creando una cuenta de usuario en io.adafruit.com.
Una vez que ingresamos, el trabajo tiene dos partes: crear los feeds donde se publicarán los datos y armar el panel que los muestre.
Un feedFeedFuente de datos en la que se puede publicar y a la que uno puede suscribirse. Permite enviar datos para que se almacenen en el tiempo, y también leerlos recibiendo las actualizaciones de quienes publican allí. es una fuente de datos en la que uno puede publicar, así como también suscribirse para recibir sus datos. Desde la sección Feeds creamos dos, con estos nombres exactos (sin tildes, porque forman parte de la dirección con la que se publica):
humedad: recibirá la lectura del higrómetro. Recordá la convención del sensor: a mayor valor, tierra más seca.valvula: recibirá el estado de la válvula, con la convención 1 = abierta (regando) y 0 = cerrada.
Luego, desde la sección Dashboards, creamos un nuevo panel con el nombre y la descripción que quieras. Dentro del panel agregamos dos bloques, uno por feed:
- Un bloque Gauge (indicador de aguja) asociado a
humedad, para ver la lectura del sensor. Como es una lectura inversa, tené presente al leerlo que la aguja alta significa tierra seca y la aguja baja, tierra húmeda. - Un bloque Indicator (luz virtual) asociado a
valvula, con la condición “igual a 1”: encendido cuando la válvula está abierta (regando), apagado cuando está cerrada.
Cada bloque permite elegir un título y sus colores, y luego se puede ajustar su tamaño y ubicación dentro del panel. Al finalizar, el panel replicará a distancia el estado del sistema: qué tan seca está la tierra y si el riego está activo.
Por último, necesitamos las credenciales que le permitirán a nuestro dispositivo publicar en la cuenta: en Adafruit IO, tocá el ícono de la llave (API Key). Vas a ver dos datos, el nombre de usuario (Username) y la clave (Active Key): anotalos, porque los vamos a copiar dentro del código en el paso 4. La clave es secreta: cualquiera que la tenga puede publicar en tus feeds.
Verificá
Para probar el panel sin la placa, entrá al feed humedad y agregale valores a mano (Add
Data): la aguja del Gauge tiene que moverse con cada valor. Cargale un 1 al feed valvula
y su Indicator tiene que encenderse; con 0, apagarse. Si un bloque no reacciona, revisá su
condición y que esté asociado al feed correcto.
Programar sin código bloqueante
Antes de usar IoT debemos hacer una aclaración sobre la función delay() que venimos usando
(nuestro programa espera un segundo entre medición y medición). Esta función brinda un tiempo
de espera al sistema y suele usarse bastante en las primeras aproximaciones a la programación,
porque su comportamiento es fácil de comprender y no requiere más que una línea de código.
Sin embargo, delay() genera un código bloqueanteCódigo bloqueanteCódigo que detiene todo el procesamiento hasta que se cumple una condición, como delay(), que deja al programa 'colgado' durante el tiempo indicado. En IoT es conflictivo: impide atender tareas simultáneas como la publicación de datos y la conexión a internet.: cuando
el programa entra en esa función, se detiene todo el procesamiento hasta que se cumple el
tiempo indicado. En otras palabras, el programa queda “colgado” durante ese período.
Al utilizar IoT, el código bloqueante es un problema: mientras el procesamiento está detenido, el sistema no puede realizar otras operaciones que funcionan en simultáneo, como las tareas de publicación y el mantenimiento constante de la conexión a internet.
Para evitarlo, usamos una alternativa no bloqueante, la función millis(). Esta función
devuelve un conteo de tiempo (en milisegundos) desde que se inició el sistema: funciona como un
cronómetro que, cada vez que se lo consulta, informa en cuánto va. Con eso podemos preguntarle
al sistema cuánto tiempo pasó desde la última medición, sin detener todo lo demás.
La receta tiene tres ingredientes, que vas a reconocer en el código: una variable
millisAnterior, que guarda cuándo fue la última medición (arranca en cero); la consulta del
valor actual con millis() en cada vuelta de loop(); y la comparación entre ambos contra el
INTERVALO_MEDICION_MS. Si ya pasó el intervalo, el programa mide el higrómetro y decide sobre
la válvula, y anota el nuevo valor en millisAnterior, para que la cuenta arranque de cero otra
vez. Si todavía no pasó el tiempo, no espera: sigue de largo, con el procesador libre para otras
tareas.
Así queda el programa del nivel intermedio quitando el código bloqueante. Sigue midiendo cada segundo, igual que el original, pero ahora sin colgarse:
Ver el código completo · riego-no-bloqueante.ino
// Riego por humedad SIN delay(): la misma lógica del nivel intermedio
// (higrómetro que abre o cierra la electroválvula), pero no bloqueante.
// En vez de detener el programa un segundo entre mediciones, cada vuelta
// de loop() pregunta con millis() si ya pasó el intervalo; el resto del
// tiempo el procesador queda libre. Esta es la base que en ESP32 permite
// sumar IoT en riego-iot.ino sin que el riego se "cuelgue".
//
// CONVENCIÓN DEL HIGRÓMETRO: MAYOR lectura = tierra MÁS SECA (módulo
// resistivo). Por eso "seco" es el umbral alto (750) y "húmedo" el bajo
// (380), igual que en el nivel intermedio.
//
// HISTÉRESIS NATURAL DEL ORIGINAL (se preserva tal cual): dos ifs con dos
// umbrales; en la franja 380 a 750 la válvula conserva su estado, lo que
// evita el traqueteo cuando la lectura baila cerca de un borde.
//
// SEGURIDAD: agua y electricidad no se llevan bien. Conexiones eléctricas
// fuera y por encima del agua. Electroválvula de baja tensión (12 V) o
// simulación en el aula; 220 V solo docente/instalación supervisada, nunca
// sobre la protoboard (desvío pedagógico acordado).
//
// Plataforma: Arduino UNO.
// Conexión (la del esquema original): higrómetro → A0; relé de la
// electroválvula → pin 2.
//
// Basado en: Fragmentos de código 6 (patrón millis) y 7 (medición y
// control cada segundo, sin la parte IoT) — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: constantes nombradas; millisAnterior como unsigned long
// (el long del original desborda la cuenta); una sola lectura del
// higrómetro por ciclo, reutilizada para imprimir y comparar.
const int PIN_HIGROMETRO = A0;
const int PIN_RELE_VALVULA = 2;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int VALVULA_ABIERTA = HIGH;
const int VALVULA_CERRADA = LOW;
// Umbrales del original (escala del UNO: 0 a 1023). Ajustalos a TU suelo.
const int UMBRAL_SECO = 750; // por encima: tierra seca → regar
const int UMBRAL_HUMEDO = 380; // por debajo: tierra húmeda → cortar
const long VELOCIDAD_SERIAL = 115200; // la del original
// El Fragmento de código 7 del original mide una vez por segundo.
const unsigned long INTERVALO_MEDICION_MS = 1000;
// Momento (ms desde el arranque) de la última medición.
unsigned long millisAnterior = 0;
void setup() {
pinMode(PIN_HIGROMETRO, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Estado inicial SEGURO: arrancamos con la válvula cerrada. Sin esta línea
// el pin queda en LOW por defecto; si invertís las constantes para un módulo
// activo-bajo, ese LOW pasaría a ser "abierta" y, si al encender la lectura
// cae en la banda muerta (entre 380 y 750), la válvula regaría sin control.
// Regla de oro: dejá SIEMPRE el actuador en estado seguro antes del loop.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
Serial.begin(VELOCIDAD_SERIAL);
}
void loop() {
unsigned long millisActual = millis();
// ¿Ya pasó el intervalo desde la última medición? Si no, no hacemos
// nada y loop() vuelve a empezar: eso es NO bloquear.
if (millisActual - millisAnterior >= INTERVALO_MEDICION_MS) {
millisAnterior = millisActual;
int humedad = analogRead(PIN_HIGROMETRO);
Serial.println(humedad);
// Histéresis del original: dos ifs independientes, dos umbrales.
if (humedad > UMBRAL_SECO) {
// Tierra demasiado seca: abrir la válvula para regar.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
}
if (humedad < UMBRAL_HUMEDO) {
// Tierra suficientemente húmeda: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
}
// Entre 380 y 750 la válvula queda como estaba.
}
// En este punto el procesador queda libre para realizar otras tareas.
} // Riego por humedad SIN delay(): la misma lógica del nivel intermedio
// (higrómetro que abre o cierra la electroválvula), pero no bloqueante.
// En vez de detener el programa un segundo entre mediciones, cada vuelta
// de loop() pregunta con millis() si ya pasó el intervalo; el resto del
// tiempo el procesador queda libre. Este programa es la base directa de
// riego-iot.ino: sin código bloqueante, el ESP32 puede mantener el WiFi y
// publicar por MQTT sin desatender el riego.
//
// CONVENCIÓN DEL HIGRÓMETRO: MAYOR lectura = tierra MÁS SECA (módulo
// resistivo). Por eso "seco" es el umbral alto y "húmedo" el bajo.
//
// HISTÉRESIS NATURAL DEL ORIGINAL (se preserva tal cual): dos ifs con dos
// umbrales; en la franja intermedia la válvula conserva su estado, lo que
// evita el traqueteo cuando la lectura baila cerca de un borde.
//
// DIFERENCIA DE ADC (didáctica): el ESP32 mide 0 a 4095 (12 bits, 3,3 V),
// no 0 a 1023 (10 bits, 5 V) del UNO; los umbrales del original se
// reescalan en la misma proporción (750→3000, 380→1520).
//
// SEGURIDAD: agua y electricidad no se llevan bien. Conexiones eléctricas
// fuera y por encima del agua. Electroválvula de baja tensión (12 V) o
// simulación en el aula; 220 V solo docente/instalación supervisada, nunca
// sobre la protoboard (desvío pedagógico acordado).
//
// Plataforma: ESP32 (DevKit v1).
// Conexión: higrómetro → GPIO 34 (ADC1, solo entrada); relé de la
// electroválvula → GPIO 16. Nota eléctrica: el ESP32 trabaja a 3,3 V;
// alimentá el higrómetro con 3,3 V y nunca inyectes 5 V en un GPIO.
//
// Basado en: Fragmentos de código 6 (patrón millis) y 7 (medición y
// control cada segundo, sin la parte IoT) — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: constantes nombradas; millisAnterior como unsigned long
// (el long del original desborda la cuenta); portado a ESP32 con umbrales
// reescalados; una sola lectura del higrómetro por ciclo, reutilizada para
// imprimir y comparar.
const int PIN_HIGROMETRO = 34;
const int PIN_RELE_VALVULA = 16;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int VALVULA_ABIERTA = HIGH;
const int VALVULA_CERRADA = LOW;
// Umbrales del original reescalados al ADC de 12 bits del ESP32.
const int UMBRAL_SECO = 3000; // por encima: tierra seca → regar (750 en UNO)
const int UMBRAL_HUMEDO = 1520; // por debajo: tierra húmeda → cortar (380 en UNO)
const long VELOCIDAD_SERIAL = 115200; // la del original
// El Fragmento de código 7 del original mide una vez por segundo.
const unsigned long INTERVALO_MEDICION_MS = 1000;
// Momento (ms desde el arranque) de la última medición.
unsigned long millisAnterior = 0;
void setup() {
pinMode(PIN_HIGROMETRO, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Estado inicial SEGURO: arrancamos con la válvula cerrada. Sin esta línea
// el pin queda en LOW por defecto; si invertís las constantes para un módulo
// activo-bajo, ese LOW pasaría a ser "abierta" y, si al encender la lectura
// cae en la banda muerta (entre 1520 y 3000), la válvula regaría sin control.
// Regla de oro: dejá SIEMPRE el actuador en estado seguro antes del loop.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
Serial.begin(VELOCIDAD_SERIAL);
}
void loop() {
unsigned long millisActual = millis();
// ¿Ya pasó el intervalo desde la última medición? Si no, no hacemos
// nada y loop() vuelve a empezar: eso es NO bloquear.
if (millisActual - millisAnterior >= INTERVALO_MEDICION_MS) {
millisAnterior = millisActual;
int humedad = analogRead(PIN_HIGROMETRO);
Serial.println(humedad);
// Histéresis del original: dos ifs independientes, dos umbrales.
if (humedad > UMBRAL_SECO) {
// Tierra demasiado seca: abrir la válvula para regar.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
}
if (humedad < UMBRAL_HUMEDO) {
// Tierra suficientemente húmeda: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
}
// Entre el umbral húmedo y el seco la válvula queda como estaba.
}
// En este punto el procesador queda libre para realizar otras tareas
// (en riego-iot.ino, acá se atiende la conexión WiFi/MQTT).
} Teniendo un programa de riego con código no bloqueante (es decir, sin delay()) estamos en
condiciones de incorporar IoT.
Para el aula
Este es el concepto más transferible del nivel: la diferencia entre esperar deteniendo el
mundo y consultar un reloj sin detenerlo. Funciona muy bien teatralizarlo: un estudiante
“bloqueante” que se congela contando hasta uno sin poder responder nada, contra uno “no
bloqueante” que sigue atendiendo consultas y cada tanto mira el reloj de la pared. Cuando el
grupo puede predecir cuál de los dos puede, además, “atender el teléfono de internet”, el
paso 4 se explica solo. Si el curso ya hizo el proyecto de Sistema de Tanques, este millis()
es un reencuentro.
Verificá
Cargá el programa: el sistema tiene que comportarse igual que en el nivel intermedio —la
válvula abre cuando la lectura supera UMBRAL_SECO y cierra cuando cae por debajo de
UMBRAL_HUMEDO—, y el Monitor Serie tiene que seguir mostrando la lectura cada segundo. Que por
fuera se vea idéntico y por dentro sea tan distinto es, justamente, el punto de este paso.
Programar IoT
Con el panel listo y el código ya libre de bloqueos, falta el último eslabón: que el sistema publique la humedad y el estado de la válvula en Adafruit IO.
Esta parte práctica corresponde a la variante ESP32: el Arduino UNO clásico no tiene WiFi (el original lo resolvía con el módulo OBLOQ, hoy discontinuado). Cambiá la plataforma a ESP32 con el selector para ver el código y las instrucciones de conexión. Todo lo conceptual —qué se publica en cada feed, la convención de valores, el porqué del código no bloqueante— ya lo tenés resuelto con tu UNO en los pasos anteriores.
El programa final integra tres cosas que ya conocés: el control no bloqueante del paso 3, la conexión WiFi nativa del ESP32 y la publicación en Adafruit IO (mediante el protocolo MQTT, usando la Adafruit MQTT Library, que se instala desde el gestor de bibliotecas del Arduino IDE; reemplaza a la biblioteca ObloqAdafruit del original, discontinuada junto con su módulo).
Antes de subirlo, tenés que completar cuatro datos al comienzo del código: el nombre (SSID) y la contraseña de tu red WiFi, y el usuario y la clave que copiaste de Adafruit IO en el paso 2.
La publicación se engancha en el tiempo que el paso 3 le dejó libre al procesador: en cada
vuelta de loop(), además de medir y decidir cuando toca, el programa mantiene viva la conexión
con el servidor y publica los cambios: el estado (1 o 0) en valvula cada vez que la
válvula conmuta, y la lectura en humedad cuando difiere de la última publicada. El original
publicaba la humedad y el estado en cada medición, cada segundo; publicar solo los cambios
muestra lo mismo en el panel sin agotar el cupo de la cuenta gratuita de Adafruit IO (30
publicaciones por minuto; el desvío está documentado en la ficha). Por esto es importante que
nuestro código no sea bloqueante: si el programa quedara colgado en un delay(), la conexión
no podría atenderse y las publicaciones se perderían. Bonus del mismo diseño: si internet se
cae, el riego sigue funcionando, y al volver la conexión el panel se pone al día solo.
Ver el código completo · riego-iot.ino
Nota: Este código está disponible para ESP32. Cambiá la plataforma con el selector del encabezado para verlo y practicarlo.
// Riego por humedad con monitoreo IoT vía Adafruit IO (MQTT).
// La lógica no bloqueante de riego-no-bloqueante.ino sigue controlando la
// electroválvula según el higrómetro; además se publican dos feeds para
// verlos desde el Panel de Control de Adafruit (como en la guía):
//
// "humedad": lectura cruda del higrómetro (número más alto = más seco).
// "valvula": 0 = cerrada, 1 = abierta.
//
// CONVENCIÓN DEL HIGRÓMETRO: MAYOR lectura = tierra MÁS SECA (módulo
// resistivo). Por eso "seco" es el umbral alto y "húmedo" el bajo.
//
// HISTÉRESIS NATURAL DEL ORIGINAL (se preserva tal cual): dos ifs con dos
// umbrales; en la franja intermedia la válvula conserva su estado.
//
// DIFERENCIA DE ADC (didáctica): el ESP32 mide 0 a 4095 (12 bits, 3,3 V),
// no 0 a 1023 del UNO; los umbrales se reescalan (750→3000, 380→1520).
//
// SEGURIDAD: agua y electricidad no se llevan bien. Conexiones eléctricas
// fuera y por encima del agua. Electroválvula de baja tensión (12 V) o
// simulación en el aula; 220 V solo docente/instalación supervisada, nunca
// sobre la protoboard (desvío pedagógico acordado).
//
// Plataforma: ESP32 (DevKit v1) — usa su WiFi integrado.
// Conexión: higrómetro → GPIO 34 (ADC1, solo entrada); relé de la
// electroválvula → GPIO 16. Nota eléctrica: el ESP32 trabaja a 3,3 V;
// alimentá el higrómetro con 3,3 V y nunca inyectes 5 V en un GPIO.
//
// Librería requerida (Library Manager del IDE de Arduino):
// "Adafruit MQTT Library" (de Adafruit) — la misma elección que en los
// demás proyectos: cada feed es un objeto y publish() acepta números
// directamente, igual que el olq.publish() del original.
//
// Basado en: Fragmento de código 7 — Sistema de Riego Automatizado,
// Saberes Digitales (INET/EDUCAR 2019)
// Modernización: (1) el módulo OBLOQ y la librería ObloqAdafruit quedaron
// discontinuados; se reemplazan por el WiFi nativo del ESP32 (WiFi.h) y
// MQTT contra io.adafruit.com. (2) El original publicaba "humedad" en CADA
// medición (cada 1 s = 60 publicaciones por minuto, el doble del límite
// gratuito de Adafruit IO de 30/min); acá se publica solo cuando algo
// cambia: la válvula al conmutar y la humedad cuando difiere 50 o más del
// último valor publicado. (3) Umbrales reescalados al ADC de 12 bits.
#include <WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
// ---------------------------------------------------------------------------
// Credenciales: reemplazar los cuatro valores por los propios.
// El usuario y la key de Adafruit se copian desde io.adafruit.com
// haciendo clic en el ícono de la "llave" (igual que en la guía original).
// ---------------------------------------------------------------------------
#define WIFI_SSID "TU_SSID"
#define WIFI_PASSWORD "TU_PASSWORD"
#define IO_USERNAME "TU_USUARIO_ADAFRUIT"
#define IO_KEY "TU_KEY_ADAFRUIT"
// Servidor MQTT de Adafruit IO.
const char SERVIDOR_MQTT[] = "io.adafruit.com";
const int PUERTO_MQTT = 1883;
const int PIN_HIGROMETRO = 34;
const int PIN_RELE_VALVULA = 16;
// Módulo relé activo-alto, como en el original (HIGH = válvula abierta).
// Si tu módulo es activo-bajo, invertí solo estas dos constantes.
const int VALVULA_ABIERTA = HIGH;
const int VALVULA_CERRADA = LOW;
// Umbrales del original reescalados al ADC de 12 bits del ESP32.
const int UMBRAL_SECO = 3000; // por encima: tierra seca → regar (750 en UNO)
const int UMBRAL_HUMEDO = 1520; // por debajo: tierra húmeda → cortar (380 en UNO)
// La humedad se re-publica solo si difiere en 50 o más (sobre 0-4095) del
// último valor publicado: los saltitos de ruido entre medición y medición
// no le aportan nada a la central y consumen el cupo gratuito de Adafruit.
const int UMBRAL_PUBLICACION = 50;
const long VELOCIDAD_SERIAL = 115200;
// El original mide una vez por segundo.
const unsigned long INTERVALO_MEDICION_MS = 1000;
// Si se cae la conexión MQTT, reintentamos cada tanto SIN bloquear:
// el riego debe seguir funcionando aunque no haya internet.
const unsigned long INTERVALO_REINTENTO_MQTT_MS = 5000;
// Cliente MQTT sobre el WiFi del ESP32, y un objeto por feed.
WiFiClient clienteWifi;
Adafruit_MQTT_Client mqtt(&clienteWifi, SERVIDOR_MQTT, PUERTO_MQTT,
IO_USERNAME, IO_KEY);
Adafruit_MQTT_Publish feedHumedad(&mqtt, IO_USERNAME "/feeds/humedad");
Adafruit_MQTT_Publish feedValvula(&mqtt, IO_USERNAME "/feeds/valvula");
// Momento (ms desde el arranque) de la última medición y del último
// intento de conexión MQTT.
unsigned long millisAnterior = 0;
unsigned long millisUltimoIntentoMqtt = 0;
// Todavía no se midió: no hay que publicar humedad inventada si la
// conexión MQTT llega antes que la primera medición.
bool hayMedicion = false;
// Estado actual (lo que muestran la válvula y el higrómetro)...
int estadoValvula = 0; // 0 = cerrada, 1 = abierta
int humedadActual = 0; // última lectura cruda del higrómetro
// ...y lo último que llegó a publicarse. Separarlos permite publicar solo
// los CAMBIOS y, si la conexión estaba caída, ponerse al día al volver.
int estadoValvulaPublicado = -1; // -1 = todavía no se publicó nada
int humedadPublicada = -1000; // imposible: fuerza la 1ª publicación
// Diferencia sin signo entre dos enteros (para comparar contra el umbral).
int diferenciaAbsoluta(int a, int b) {
if (a > b) {
return a - b;
}
return b - a;
}
// Mantiene viva la conexión MQTT sin bloquear el riego: si está caída,
// reintenta como mucho una vez cada 5 segundos.
void mantenerConexionMqtt() {
if (mqtt.connected()) {
return;
}
unsigned long millisActual = millis();
if (millisActual - millisUltimoIntentoMqtt < INTERVALO_REINTENTO_MQTT_MS) {
return; // todavía no toca reintentar
}
millisUltimoIntentoMqtt = millisActual;
Serial.print("Conectando a Adafruit IO... ");
int8_t resultado = mqtt.connect(); // 0 = conexión exitosa
if (resultado == 0) {
Serial.println("conectado.");
} else {
Serial.println(mqtt.connectErrorString(resultado));
mqtt.disconnect(); // deja el socket limpio para el próximo intento
}
}
// Publica cada feed SOLO si cambió desde la última publicación exitosa
// (la humedad, solo si cambió 50 o más). Si publish() falla o no hay
// conexión, no se actualiza el registro: se reintenta en la próxima vuelta.
void publicarCambios() {
if (!mqtt.connected() || !hayMedicion) {
return; // sin internet o sin datos reales todavía: no se publica
}
if (estadoValvula != estadoValvulaPublicado
&& feedValvula.publish((int32_t)estadoValvula)) {
estadoValvulaPublicado = estadoValvula;
}
if (diferenciaAbsoluta(humedadActual, humedadPublicada) >= UMBRAL_PUBLICACION
&& feedHumedad.publish((int32_t)humedadActual)) {
humedadPublicada = humedadActual;
}
}
void setup() {
Serial.begin(VELOCIDAD_SERIAL);
pinMode(PIN_HIGROMETRO, INPUT);
pinMode(PIN_RELE_VALVULA, OUTPUT);
// Estado inicial seguro: válvula cerrada hasta que la primera medición
// diga otra cosa.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
// Conexión WiFi. Esperar acá con delay() es aceptable porque el riego
// todavía no arrancó; una vez dentro de loop(), nada bloquea.
Serial.print("Conectando a la red WiFi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("WiFi conectado, IP: ");
Serial.println(WiFi.localIP());
}
void loop() {
unsigned long millisActual = millis();
// --- Medición y control, una vez por segundo (como el original) ---
if (millisActual - millisAnterior >= INTERVALO_MEDICION_MS) {
millisAnterior = millisActual;
humedadActual = analogRead(PIN_HIGROMETRO);
hayMedicion = true; // desde ahora, publicarCambios() tiene datos reales
Serial.println(humedadActual);
// Histéresis del original: dos ifs independientes, dos umbrales.
if (humedadActual > UMBRAL_SECO) {
// Tierra demasiado seca: abrir la válvula para regar.
digitalWrite(PIN_RELE_VALVULA, VALVULA_ABIERTA);
estadoValvula = 1;
}
if (humedadActual < UMBRAL_HUMEDO) {
// Tierra suficientemente húmeda: cerrar la válvula.
digitalWrite(PIN_RELE_VALVULA, VALVULA_CERRADA);
estadoValvula = 0;
}
// Entre el umbral húmedo y el seco la válvula queda como estaba.
}
// --- Parte IoT ---
// Gracias a que el control no bloquea, estas dos tareas se atienden en
// CADA vuelta de loop(): esta es la razón de fondo por la que la guía
// enseña a abandonar delay() antes de llegar a IoT.
mantenerConexionMqtt();
publicarCambios();
} Así queda funcionando el tablero que permite monitorear el riego a distancia. Podés ver el sistema completo —el higrómetro midiendo, la válvula regando y el panel reflejando cada publicación— en el simulador:
Simulación del comportamiento
La misma máquina de estados del firmware, portada a TypeScript, maneja el
comportamiento del dispositivo. No se ejecuta el binario real: la ejecución
del .hex con avr8js está en el roadmap.
Simulación lista. Presioná «Iniciar» para arrancar la secuencia.
De lectura cruda a porcentaje
El Gauge muestra la lectura cruda del higrómetro, y “612” no le dice mucho a alguien que solo quiere saber si hay que regar. Tomando los umbrales que calibraste, modifiquen el programa para publicar un porcentaje de humedad (o directamente un estado “seco / húmedo”) en lugar del número crudo. ¿Qué hay que cambiar en el panel para que el bloque siga siendo coherente con el nuevo valor? ¿Conviene un Gauge o un Indicator?
Verificá
Con el programa cargado y la placa conectada a tu red WiFi, abrí el panel de Adafruit IO en el
celular o la computadora: el Indicator de valvula tiene que encenderse y apagarse junto con la
válvula en cada conmutación, y el Gauge de humedad, actualizarse cuando la lectura cambia
(recordá que se publica por cambios: con la tierra quieta, que no lleguen datos nuevos es lo
esperado; cambiá la humedad y van a aparecer). Todo con una pequeña demora de red. Si no llega
nada, revisá las credenciales y el nombre de la red; si llegan datos pero un bloque no reacciona,
revisá a qué feed está asociado y su condición.
Cierre del nivel
Al terminar este nivel, tu sistema de riego dejó de ser solo un dispositivo local: es un
dispositivo IoT. El programa funciona con millis(), sin ningún delay() que lo cuelgue; sabés
explicar por qué eso es imprescindible cuando hay que atender internet en simultáneo; y el panel
de Adafruit IO muestra desde cualquier dispositivo qué tan seca está la tierra y si el sistema
está regando. Con esto queda completo el recorrido del proyecto. Si el grupo quiere seguir, en
la ficha del proyecto está la extensión sugerida: complementar con el proyecto “Invernadero
inteligente”, sumando sensores de humedad de ambiente y de temperatura.
Evidencia de cierre
Al terminar este nivel, esto tiene que estar funcionando:
- El sistema de riego funciona con código no bloqueante basado en millis(): no queda ningún delay() que detenga el programa entre mediciones.
- Podés explicar con tus palabras por qué el código bloqueante es un problema cuando el dispositivo tiene que atender internet en simultáneo.
- El panel de Adafruit IO muestra la lectura de humedad del suelo y el estado de la válvula publicados por el dispositivo (variante ESP32).