Regador automático con ESP32 + Bloomit
Armá un regador que mide la humedad del suelo, enciende la bomba solo cuando la planta lo necesita y registra cada riego en Bloomit. Código completo, diagrama y precauciones.
Hardware necesario
- ESP32 DevKit V1
- Sensor de humedad YL-69 / FC-28 (o capacitivo v1.2)
- Módulo relay 1 canal 5V con optoacoplador
- Bomba sumergible DC 5V (~120L/h)
- Fuente externa 5V 1A
- Mangueras de silicona Ø5mm
- Recipiente/tacho para el agua
- Protoboard y cables jumper
Qué vas a armar
Este tutorial extiende el tutorial de sensor de humedad con ESP32 agregando la parte actuadora: cuando la humedad baja del umbral que configurás, el ESP32 activa un relay que enciende la bomba durante unos segundos, espera el cooldown y luego registra el riego en Bloomit.
El ciclo completo es el siguiente: cada 30 minutos el ESP32 lee la humedad del suelo. Si el valor cae por debajo de HUMIDITY_THRESHOLD y pasaron al menos 30 minutos desde el último riego (cooldown), activa el relay, la bomba corre PUMP_RUN_MS milisegundos, y luego se registra en Bloomit con /sense (lectura de humedad) y /actuate (evento de riego). Si la humedad está bien, solo envía la lectura y vuelve a dormir.
Si todavía no completaste el tutorial anterior, te conviene hacerlo primero: la configuración de WiFi, la calibración del sensor y el registro del device token son idénticos. Acá nos enfocamos en lo nuevo: el relay, la bomba y la lógica de decisión.
⚠️ Precauciones de seguridad
Leé esto antes de conectar cualquier cosa.
- Nunca alimentes la bomba desde el USB del ESP32. El pin 5V del ESP32 en modo USB entrega como máximo 500 mA; una bomba de 120L/h arranca con picos de 800 mA o más. El regulador se quema. Usá siempre una fuente externa.
- GND común obligatorio. El ESP32, el relay y la fuente externa tienen que compartir el mismo GND. Sin GND común el relay puede no responder o comportarse de forma impredecible.
- El relay debe tener optoacoplador. Aísla el circuito de control (3.3V del ESP32) del circuito de carga (bomba + fuente). Los módulos relay baratos sin opto pueden generar picos de voltaje que dañan el microcontrolador.
- Probá el relay sin la bomba conectada primero. Cargá el sketch, abrí el Monitor Serial y verificá que el relay clickea en el momento correcto antes de conectar la carga real.
- Electrónica lejos del agua. Elevá el ESP32 y el relay al menos 20 cm sobre el nivel del recipiente. Un salpicado puede cortocircuitar todo. Usá canaletas o cajas plásticas con tapa.
- Este tutorial es solo para 5V DC. Si en algún momento considerás usar 220V AC para una bomba más potente, necesitás un relay certificado, caja cerrada y protección GFCI. No está cubierto aquí y no es para principiantes.
Diagrama de conexión
| ESP32 | Componente | Pin destino | Cable |
|---|---|---|---|
| VIN / 5V | Módulo relay | VCC | Naranja |
| GND | Módulo relay | GND | Negro |
| GPIO 26 | Módulo relay | IN | Violeta |
| GPIO 34 | Sensor YL-69 | AO (Analog Out) | Amarillo |
| 3.3V | Sensor YL-69 | VCC | Rojo |
| GND | Sensor YL-69 | GND | Negro |
| GPIO 2 | Resistencia 220Ω → | Ánodo LED (+) | Azul |
| Fuente 5V (+) | Relay | COM (terminal carga) | Verde |
| Relay | Bomba (+) | NO (normalmente abierto) | Verde |
| Bomba (−) | Fuente 5V (−) | GND rail | Negro |
Nota sobre active-low: la mayoría de los módulos relay de 5V con optoacoplador se activan con LOW en el pin IN y se desactivan con HIGH. El código usa esa convención. Si tu relay funciona al revés (active-high), invertí los valores en la función waterPlant().
Obtener el device token
Si ya completaste el tutorial anterior y tenés un token, podés reutilizarlo. Si no, registrá el dispositivo desde bloomit.app o via API:
# 1. Login → obtenés el userToken
curl -X POST https://user.api.bloomit.app/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"tu@email.com","password":"tupassword"}'
# 2. Registrar dispositivo → obtenés el deviceToken
curl -X POST https://device.api.bloomit.app/register \
-H "Authorization: Bearer <userToken>" \
-H "Content-Type: application/json" \
-d '{"name":"ESP32 Regador Balcón","metadata":{"location":"balcon"}}'
# Respuesta: { "deviceToken": "eyJhbGci...", "deviceId": "abc123" }
# Guardá el deviceToken — lo pegás en el sketchCódigo completo
Copiá este sketch en Arduino IDE. Reemplazá SSID, PASSWORD y DEVICE_TOKEN con tus datos. Ajustá HUMIDITY_THRESHOLD según la planta (ver sección siguiente).
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// ── Configuración WiFi y Bloomit ───────────────────────
const char* SSID = "tu_red_wifi";
const char* PASSWORD = "tu_password";
const char* DEVICE_TOKEN = "eyJhbGci..."; // tu deviceToken de bloomit.app
// ── Pines ──────────────────────────────────────────────
const int SENSOR_PIN = 34; // ADC1 — solo lectura analógica
const int RELAY_PIN = 26; // GPIO 26 — control relay (active-low)
const int LED_PIN = 2; // GPIO 2 — LED indicador integrado
// ── Calibración del sensor ────────────────────────────
// Medí el valor en seco (sensor en aire) y en húmedo (sensor sumergido).
const int SENSOR_DRY = 4095; // valor en aire → 0 % humedad
const int SENSOR_WET = 1500; // valor en agua → 100 % humedad
// ── Parámetros de riego ───────────────────────────────
const int HUMIDITY_THRESHOLD = 30; // regar si humedad < 30 %
const unsigned long PUMP_RUN_MS = 5000UL; // cuántos ms corre la bomba
const unsigned long COOLDOWN_MS = 1800000UL; // 30 min mínimo entre riegos
const unsigned long LOOP_MS = 1800000UL; // 30 min entre lecturas
// ── Estado global ─────────────────────────────────────
unsigned long lastWateringMs = 0; // millis() del último riego
// ── Ayudante LED ──────────────────────────────────────
void blink(int times, int onMs, int offMs) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_PIN, HIGH); delay(onMs);
digitalWrite(LED_PIN, LOW); delay(offMs);
}
}
// ── Setup ──────────────────────────────────────────────
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
// Relay apagado desde el arranque (active-low → HIGH = apagado)
digitalWrite(RELAY_PIN, HIGH);
// Señal de inicio: 2 parpadeos lentos
blink(2, 500, 300);
Serial.print("Conectando a WiFi");
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" OK — IP: " + WiFi.localIP().toString());
// WiFi listo: 3 parpadeos rápidos
blink(3, 100, 100);
}
// ── Lectura del sensor ────────────────────────────────
int readHumidity() {
// Promediamos 5 lecturas para estabilizar el valor ADC
long sum = 0;
for (int i = 0; i < 5; i++) {
sum += analogRead(SENSOR_PIN);
delay(10);
}
int raw = (int)(sum / 5);
int humidity = map(raw, SENSOR_DRY, SENSOR_WET, 0, 100);
return constrain(humidity, 0, 100);
}
// ── Acción de riego ───────────────────────────────────
void waterPlant() {
Serial.println("Regando...");
digitalWrite(LED_PIN, HIGH); // LED fijo durante el riego
digitalWrite(RELAY_PIN, LOW); // activa relay (active-low → bomba ON)
delay(PUMP_RUN_MS);
digitalWrite(RELAY_PIN, HIGH); // desactiva relay → bomba OFF
digitalWrite(LED_PIN, LOW);
Serial.println("Riego finalizado.");
}
// ── Envío de lectura a Bloomit (/sense) ───────────────
bool sendSensor(int humidity) {
if (WiFi.status() != WL_CONNECTED) {
WiFi.reconnect();
delay(3000);
return false;
}
HTTPClient http;
http.begin("https://device.api.bloomit.app/sense");
http.addHeader("Authorization", "Bearer " + String(DEVICE_TOKEN));
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<128> doc;
doc["sensorType"] = "soil_humidity";
doc["value"] = humidity;
String body;
serializeJson(doc, body);
int code = http.POST(body);
http.end();
Serial.printf("POST /sense → %d | humedad: %d%%\n", code, humidity);
return code == 200;
}
// ── Registro del riego en Bloomit (/actuate) ─────────
bool sendActuate() {
if (WiFi.status() != WL_CONNECTED) {
WiFi.reconnect();
delay(3000);
return false;
}
HTTPClient http;
http.begin("https://device.api.bloomit.app/actuate");
http.addHeader("Authorization", "Bearer " + String(DEVICE_TOKEN));
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<128> doc;
doc["action"] = "turn_on";
doc["value"] = 100; // intensidad 100 % — bomba encendida al máximo
String body;
serializeJson(doc, body);
int code = http.POST(body);
http.end();
Serial.printf("POST /actuate → %d\n", code);
return code == 200;
}
// ── Loop principal ────────────────────────────────────
void loop() {
// Reconectar WiFi si se cayó
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi caído — reconectando...");
WiFi.reconnect();
delay(5000);
}
// Leer humedad (1 parpadeo = midiendo)
blink(1, 200, 0);
int humidity = readHumidity();
Serial.printf("Humedad: %d%%\n", humidity);
unsigned long now = millis();
bool cooldownOk = (now - lastWateringMs) >= COOLDOWN_MS;
bool needsWater = humidity < HUMIDITY_THRESHOLD;
if (needsWater && cooldownOk) {
// Regar, registrar y actualizar el timestamp
waterPlant();
lastWateringMs = millis();
bool okActuate = sendActuate();
if (!okActuate) {
// LED 1 s = error al registrar actuación
digitalWrite(LED_PIN, HIGH); delay(1000); digitalWrite(LED_PIN, LOW);
}
} else if (needsWater && !cooldownOk) {
Serial.println("Humedad baja pero cooldown activo — esperando.");
}
// Siempre enviar la lectura de humedad
bool okSensor = sendSensor(humidity);
if (okSensor) {
blink(3, 100, 100); // 3 rápidos = dato enviado OK
} else {
digitalWrite(LED_PIN, HIGH); delay(1000); digitalWrite(LED_PIN, LOW);
}
// Esperar hasta el próximo ciclo (30 minutos)
delay(LOOP_MS);
}Señales del LED
2 parpadeos lentos (500ms)Arranque — El sketch inició correctamente3 parpadeos rápidos (100ms) al inicioWiFi OK — La red WiFi está conectadaLED fijo durante varios segundosRegando — La bomba está activa — no interrumpas1 parpadeo (200ms)Leyendo sensor — Capturando la lectura analógica3 parpadeos rápidos tras lecturaEnvío exitoso — El dato llegó a Bloomit (HTTP 200)LED 1 segundo fijoError HTTP — No se pudo enviar — se reintenta en el próximo cicloLED apagado entre ciclosCooldown / espera — El ESP32 está en delay — todo normal
Elegir el umbral correcto
El valor de HUMIDITY_THRESHOLD depende de la planta. Bloomit aplica rangos recomendados por especie cuando la asignás desde la app:
- Cactus y suculentas: 10–25 % — riegan muy poco, esperan que el sustrato esté casi seco.
- Plantas tropicales (pothos, calathea): 40–60 %.
- Tomate y vegetales: 60–80 % — prefieren sustrato húmedo constante.
- Helechos: más de 50 % — no toleran que el sustrato se seque.
Antes de configurar el riego automático, hacé al menos un día de observación en modo solo lectura: cargá el sketch con HUMIDITY_THRESHOLD = 0 (nunca va a regar), mirá los datos en Bloomit durante 24 horas y fijate cuánto baja la humedad naturalmente en tu tierra. Con eso vas a tener el rango real de tu maceta, no el teórico del sensor.
Troubleshooting
El relay clickea pero la bomba no arranca
La fuente no tiene corriente suficiente. Probá con una fuente de 2A. También verificá la polaridad de la bomba (los cables rojo/negro pueden estar invertidos en algunas unidades chinas).
El sensor da valores fuera de rango o inconsistentes
En sensores resistivos (YL-69), las sondas metálicas se oxidan en pocas semanas de uso continuo. El oxido aumenta la resistencia y distorsiona la lectura. Considerá migrar a un sensor capacitivo v1.2 que dura mucho más.
La bomba no se detiene o el relay no responde como esperás
Puede ser que tu módulo relay sea active-high en lugar de active-low. Intercambiá los valores: donde el código pone LOW, poné HIGH, y viceversa. Verificá también si el LED de tu módulo enciende al recibir LOW o HIGH.
Error "HTTP -1" en el monitor serial
El cable USB alimenta el ESP32 pero cuando arranca la bomba hay un pico de corriente que hace caer el voltaje de 3.3V y el ESP32 se reinicia o pierde el stack de red. La fuente externa para la bomba es obligatoria, no opcional.
El WiFi se corta justo al momento de regar
Pico de corriente del motor al arrancar. Soldá un capacitor electrolítico de 470µF (o más) en paralelo entre VIN y GND del ESP32. Esto actúa como buffer ante los picos de demanda.
¿Te trabaste en algún paso?
Sumate al grupo de Telegram de Bloomit: ahí te ayudamos a resolver errores de cableado, compilación o conexión. Hay gente armando los mismos proyectos que vos.
Unirme al grupoBloomit
¿Todo funcionando? Abrí el panel
Registrá tu cuenta gratis, conectá el dispositivo y los datos aparecen en tiempo real. Hardware Bloomit listo para usar en bloomit.com.ar.