← Riego inteligente con la API de OpenWeather en Node-RED
Riego agrícola automatizadoRaspberry Pi (Docker)HTTPControl
Riego inteligente con la API de OpenWeather en Node-RED — ejemplo completo
Riego inteligente que consulta OpenWeather antes de cada ciclo: los programadores de Node-RED cancelan el riego si se prevé lluvia o helada, con modo manual.
Programa completo y ejecutable para el Raspberry Pi (Docker) (irrigation-weather-openweather-scheduler.js): incluye cabecera de conexionado, requisitos y notas de integración.
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales
Vista de solo lectura.
/*
* COMPLETE EXAMPLE — Weather-conditioned irrigation (OpenWeather) in Node-RED
*
* Hardware: Raspberry Pi (Docker) with Node-RED
* Based on: automated agricultural irrigation project
*
* Requirements:
* - Nodes: node-red-contrib-cron-plus, http request (core), switch, change.
* - OpenWeather API key (free plan is enough: One Call / forecast 5d-3h).
*
* Flow wiring (tabs "Irrigation" / "OpenWeather" / "Irrigation Logic"):
*
* [cron-plus "morning 07:00"] --\
* >--> [function 1: prepare weather query]
* [cron-plus "evening 19:00"] --/ |
* [inject "manual irrigation"] ----------/ (msg.mode = "manual" skips
* the rain check)
* [function 1] --> [http request GET, URL in msg.url] --> [function 2: decide irrigation]
* [function 2] --> [switch msg.irrigate: true / false]
* true --> [function 3: run command] --> (Modbus: ATV320 VFD)
* false --> [change: prepare notice] --> (Telegram: cycle cancelled)
*
* Credentials go in environment variables of the Node-RED container
* (OPENWEATHER_API_KEY), never in the flow.
*/
// ===========================================================================
// FUNCTION 1 — "Prepare weather query"
// Builds the forecast URL and keeps the trigger mode of the cycle.
// ===========================================================================
const LAT = 41.6000; // latitude of the farm (placeholder)
const LON = 1.8000; // longitude of the farm (placeholder)
const API_KEY = env.get("OPENWEATHER_API_KEY");
msg.mode = msg.mode || "auto"; // "auto" (scheduler) or "manual"
msg.url =
"https://api.openweathermap.org/data/2.5/forecast" +
`?lat=${LAT}&lon=${LON}&appid=${API_KEY}&units=metric&cnt=8`;
// cnt=8 -> next 24 h in 3-hour blocks
return msg;
// ===========================================================================
// FUNCTION 2 — "Decide irrigation"
// Analyzes the OpenWeather response: cancels if rain is forecast or there
// is frost risk. Manual mode ignores the rain (the farmer's decision).
// ===========================================================================
/*
const RAIN_THRESHOLD_MM = 2.0; // mm accumulated in 24 h that cancel the cycle
const FROST_THRESHOLD_C = 1.0; // forecast minimum in ºC that cancels the cycle
const blocks = msg.payload.list || [];
let totalRain = 0;
let minTemp = 99;
for (const b of blocks) {
totalRain += (b.rain && b.rain["3h"]) ? b.rain["3h"] : 0;
minTemp = Math.min(minTemp, b.main.temp_min);
}
msg.weather = {
rain_24h_mm: Math.round(totalRain * 10) / 10,
min_temp_c: Math.round(minTemp * 10) / 10,
};
if (msg.mode === "manual") {
msg.irrigate = true;
msg.reason = "Manual irrigation requested by the user";
} else if (totalRain >= RAIN_THRESHOLD_MM) {
msg.irrigate = false;
msg.reason = `Rain forecast: ${msg.weather.rain_24h_mm} mm in 24 h`;
} else if (minTemp <= FROST_THRESHOLD_C) {
msg.irrigate = false;
msg.reason = `Frost risk: forecast minimum ${msg.weather.min_temp_c} ºC`;
} else {
msg.irrigate = true;
msg.reason = "No rain or frost forecast";
}
node.status({
fill: msg.irrigate ? "green" : "yellow",
shape: "dot",
text: msg.reason,
});
return msg;
*/
// ===========================================================================
// FUNCTION 3 — "Run command"
// Prepares the command for the VFD (see the Altivar 320 example) and arms the
// end-of-cycle timer. The duration depends on the time slot.
// ===========================================================================
/*
const MORNING_DURATION_MIN = 45;
const EVENING_DURATION_MIN = 30;
const hour = new Date().getHours();
const durationMin = hour < 12 ? MORNING_DURATION_MIN : EVENING_DURATION_MIN;
flow.set("irrigation_active", true);
flow.set("irrigation_end_ts", Date.now() + durationMin * 60 * 1000);
msg.payload = { command: "run", rpm: 2200, duration_min: durationMin };
msg.topic = "irrigation/vfd";
node.warn(`Irrigation cycle started: ${durationMin} min (${msg.reason})`);
return msg;
*/
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales