Skip to content

Sesión 1 · Fundamentos de Node-RED y flujos de control ​

Objetivos de la sesión ​

  • Instalar Node-RED de forma nativa con npm, identificar los ficheros de su directorio de usuario y levantar después el entorno del curso con Docker.
  • Explicar la programación basada en flujos y la estructura del objeto msg.
  • Construir flujos con los nodos inject, debug, change, switch y function.
  • Recibir por MQTT una magnitud del invernadero simulado y convertirla a un valor numérico.
  • Programar una decisión de control basada en umbrales guardados en el contexto de flujo.

Conexión con el sistema del invernadero ​

Esta sesión construye la lógica de procesado: la pieza que recibe una lectura, la interpreta y decide qué hacer. En las sesiones siguientes esa decisión se enriquecerá con la previsión meteorológica (S2), actuará sobre la bomba (S3), se verá en el panel (S4), quedará registrada (S5) y generará alertas (S6).

Esquema del flujo de la sesión: la humedad del suelo llega por MQTT o por inject de prueba, se convierte a número, un switch la clasifica con los umbrales del contexto de flujo, cada salida etiqueta el estado y un function decide si regar

Este es el flujo que construirás en la práctica guiada. Los recuadros discontinuos son el contexto de flujo: los umbrales y el último estado se guardan ahí, no en los nodos.

Conceptos clave ​

Programación basada en flujos ​

En Node-RED un programa es un flujo: un grafo de nodos unidos por cables. Cada nodo recibe un mensaje, hace una cosa y pasa uno o más mensajes al siguiente. No hay un bucle principal: el motor (Node.js) ejecuta cada nodo cuando le llega un mensaje.

Ya conoces la idea desde Python:

Script Python con paho-mqttFlujo de Node-RED
client.connect(...) y loop_forever()Nodo de configuración mqtt-broker: Node-RED mantiene la conexión
client.subscribe("invernadero/suelo/humedad")Nodo mqtt in con ese topic
Callback on_message(client, userdata, msg)Todo lo que cuelga del cable de salida del mqtt in
if valor < umbral: ...Nodo switch
print(...)Nodo debug

La diferencia está en lo que viene después: en Node-RED añadir un panel, una base de datos o un bot de Telegram es añadir nodos al mismo flujo, no reescribir el script.

Repasar MQTT

Si no tienes claro qué son el broker, los topics, el QoS o el retain, el anexo MQTT en lo que necesitas lo resume con ejemplos del invernadero.

El mensaje msg ​

Todo lo que circula por un cable es un objeto JavaScript llamado msg:

PropiedadContenido
msg.payloadEl dato principal. Con MQTT, el contenido del mensaje: "42.5"
msg.topicEl topic MQTT o una etiqueta libre: "invernadero/suelo/humedad"
msg._msgidIdentificador único que asigna Node-RED
cualquier otraPuedes añadir las tuyas: msg.estado, msg.unidad…

Documentación: Working with messages.

Nodos de esta sesión ​

NodoPara qué
injectGenera un mensaje: al pulsar, al desplegar o periódicamente
debugMuestra el mensaje en la barra lateral de depuración
changeModifica propiedades sin escribir código: asignar, borrar, mover, expresiones JSONata
switchEnruta el mensaje a una salida u otra según reglas
functionCódigo JavaScript con acceso a msg, al contexto y al estado del nodo
mqtt inSuscripción a un topic MQTT

Documentación: Core nodes y Writing functions.

Contexto ​

Los mensajes no se acuerdan de nada. Para guardar estado entre mensajes (el último valor, unos umbrales, un contador) Node-RED ofrece el contexto en tres ámbitos: nodo (context), flujo (flow, compartido por los nodos de la pestaña) y global (global, todo Node-RED). Documentación: Working with context.

Práctica guiada paso a paso ​

Cada paso tiene la misma estructura: para qué sirve, qué hacer (con los nombres exactos que verás en el editor, que está en inglés), qué debes ver al terminar y si no funciona. Las operaciones básicas del editor se explican con detalle la primera vez que aparecen; después solo se nombran.

Paso 1 · Instalar Node-RED en tu PC (40 min) ​

Para qué sirve. Antes de usar el entorno del curso vas a instalar Node-RED a mano. Así verás qué es realmente (una aplicación de Node.js), dónde guarda tu trabajo y cómo se maneja el editor.

1.1 · Instala Node.js en su versión LTS. Node-RED 4 necesita Node.js 18 o superior.

powershell
winget install OpenJS.NodeJS.LTS
# o descarga el instalador LTS de https://nodejs.org
bash
brew install node
bash
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs

Cierra la terminal, abre una nueva (para que reconozca los comandos recién instalados) y comprueba las versiones:

bash
node -v    # por ejemplo v22.x
npm -v     # por ejemplo 10.x

1.2 · Instala Node-RED como paquete global de npm. Tarda uno o dos minutos:

powershell
npm install -g --unsafe-perm node-red
bash
sudo npm install -g --unsafe-perm node-red

1.3 · Arráncalo escribiendo node-red en la terminal. Deja esa terminal abierta: Node-RED funciona mientras el comando siga en marcha. Verás un log como este (las rutas y versiones dependen de tu equipo):

text
Welcome to Node-RED
===================
27 Sep 19:05:34 - [info] Node-RED version: v4.1.15
27 Sep 19:05:34 - [info] Node.js  version: v22.x
27 Sep 19:05:41 - [info] Settings file  : C:\Users\tu-usuario\.node-red\settings.js
27 Sep 19:05:41 - [info] Context store  : 'default' [module=memory]
27 Sep 19:05:41 - [info] User directory : C:\Users\tu-usuario\.node-red
27 Sep 19:05:41 - [info] Flows file     : C:\Users\tu-usuario\.node-red\flows.json
27 Sep 19:05:41 - [info] Server now running at http://127.0.0.1:1880/
27 Sep 19:05:41 - [info] Starting flows

Localiza en tu log las cuatro líneas importantes: User directory (dónde guarda todo), Settings file (su configuración), Flows file (tus flujos) y Server now running (la dirección del editor).

1.4 · Abre el editor en http://localhost:1880. Estas son sus partes:

Editor de Node-RED con cinco zonas numeradas: 1 la paleta de nodos a la izquierda, 2 el lienzo en el centro con un inject y un debug unidos, 3 el botón Deploy arriba a la derecha, 4 la barra lateral con la pestaña debug mostrando un mensaje, 5 el botón del nodo inject

#ZonaPara qué sirve
1PaletaTodos los nodos disponibles, agrupados por secciones (common, function, network…). Se arrastran de aquí al lienzo. El buscador filter nodes de arriba los filtra por nombre
2LienzoDonde construyes el flujo. Cada pestaña de arriba es un flujo distinto
3DeployEnvía los cambios al motor. Hasta que no pulsas Deploy, nada de lo que dibujas se ejecuta
4Barra lateralVarias pestañas: info, ayuda, debug (el insecto, donde aparecen los mensajes) y ⚙ (configuración). Si no la ves, pulsa Ctrl+Espacio
5Botón del injectEl cuadradito a la izquierda del nodo: al pulsarlo, el nodo envía un mensaje

1.5 · Tu primer flujo. Las tres operaciones básicas del editor:

  1. Añadir un nodo: en la paleta, sección common, arrastra el nodo inject al lienzo y suéltalo. Haz lo mismo con el nodo debug, a su derecha.
  2. Unir dos nodos: cada nodo tiene un puerto de salida (cuadradito gris a la derecha) y/o un puerto de entrada (a la izquierda). Pincha en el puerto de salida del inject y, sin soltar, arrastra hasta el puerto de entrada del debug. Aparece un cable gris.
  3. Desplegar: pulsa Deploy. El botón se pone gris hasta que vuelvas a cambiar algo.

Ahora pulsa el botón del inject (zona 5) y abre la pestaña debug de la barra lateral.

Qué debes ver. Un mensaje con la fecha, node: … y un número largo en azul, como 1790528874059: es la marca de tiempo (milisegundos desde 1970) que el inject envía por defecto.

Si no funciona.

  • No aparece nada en debug: falta pulsar Deploy, o el cable no llega al puerto de entrada del debug. Un cable bien conectado se ve continuo de un puerto a otro.
  • El nodo tiene un triángulo rojo o un punto azul encima: el triángulo indica un error de configuración y el punto azul, cambios sin desplegar.

1.6 · Instala un nodo desde la paleta. Node-RED se amplía con nodos que publica la comunidad.

  1. Abre el menú ☰ (arriba a la derecha) → Manage palette.
  2. Pestaña Install. En el buscador escribe node-red-node-random.
  3. Pulsa install en el resultado y confirma.

Diálogo User Settings, sección Palette, pestaña Install: el buscador contiene node-red-node-random y aparece el módulo con su descripción y el botón install

Qué debes ver. Al terminar, el nodo random aparece en la sección function de la paleta. Pruébalo: inject → random → debug, Deploy, pulsa el inject y en debug sale un número entre 1 y 10.

1.7 · Explora el directorio de usuario desde otra terminal, sin parar Node-RED:

powershell
dir $HOME\.node-red
type $HOME\.node-red\package.json
bash
ls -la ~/.node-red
cat ~/.node-red/package.json

Qué debes ver. Los ficheros settings.js, flows.json, flows_cred.json (si ya hay credenciales), package.json y la carpeta node_modules. En package.json aparece node-red-node-random: lo que instalas desde la paleta se guarda en tu directorio de usuario, no junto a Node-RED. Qué es cada fichero lo tienes en Node-RED como plataforma.

1.8 · Comprueba que el trabajo persiste. En la terminal donde corre Node-RED pulsa Ctrl+C (lo para) y vuelve a escribir node-red. Recarga el editor: tu flujo sigue ahí. Abre flows.json con un editor de texto: es un JSON con tus nodos, el mismo formato que obtienes al exportar un flujo.

1.9 · Para Node-RED con Ctrl+C antes de seguir. Si quieres conservar el flujo, antes selecciónalo todo en el lienzo (Ctrl+A), pulsa Ctrl+E (Export) y Download.

Puerto 1880 ocupado

El Node-RED nativo y el de Docker usan el mismo puerto. Si en el paso 2 docker compose up falla con port is already allocated, o el editor que abres no es el que esperas, es que el nativo sigue en marcha: páralo con Ctrl+C en su terminal.

Sin permisos de administrador

Si no puedes instalar paquetes globales, ejecuta Node-RED sin instalarlo con npx node-red.

Paso 2 · Pasar al entorno del curso con Docker (20 min) ​

Para qué sirve. Una instalación nativa sirve para un Node-RED. El sistema del invernadero necesita además un broker, una base de datos y el simulador, con las mismas versiones en todos los PCs. Docker Compose levanta todo eso igual en cada máquina con un solo comando.

Comparación: en la instalación nativa Node-RED corre sobre el Node.js de tu sistema y guarda sus ficheros en ~/.node-red; en Docker, Node.js y Node-RED vienen en la imagen del contenedor y los ficheros van al volumen node-red-data, montado en /data

Qué hacer.

  1. Descarga el entorno: entorno-docker.zip. Descomprímelo donde quieras trabajar (por ejemplo, en el Escritorio): se crea una carpeta docker. Abre una terminal dentro de ella (en el explorador de Windows: clic derecho en la carpeta → Abrir en Terminal).

  2. Crea tu fichero de configuración copiando la plantilla:

    bash
    cp .env.example .env

    En PowerShell funciona igual; también puedes copiar el fichero y renombrarlo a mano.

  3. No hace falta cambiar nada del .env, pero ábrelo con un editor de texto (el Bloc de notas vale) para ver qué contiene. Las primeras líneas eligen el broker al que se conecta Node-RED: el mosquitto local, donde publica el simulador del invernadero.

    ini
    # Broker local + simulador del invernadero
    COMPOSE_PROFILES=simulador
    MQTT_HOST=mosquitto

    El resto son las contraseñas del broker, la velocidad del simulador y los datos de las sesiones siguientes. Debajo hay un segundo bloque, comentado, para conectarse al invernadero real del laboratorio; todo el módulo se hace con el simulador, y si algún día usas los dispositivos físicos, Trabajar con el invernadero real explica qué cambiar.

  4. Arranca el entorno. La primera vez tarda unos minutos, porque descarga y construye las imágenes:

    bash
    docker compose up -d --build
    docker compose ps
  5. Abre http://localhost:1880.

Qué debes ver.

  • docker compose ps lista node-red, influxdb, mosquitto y simulador, todos con estado running o Up.

  • El editor está vacío: es otra instalación, con su propio directorio de usuario. Compruébalo con:

    bash
    docker compose exec node-red ls -la /data

    Verás los mismos tipos de fichero que en ~/.node-red. Si exportaste el flujo del paso 1, impórtalo aquí: menú ☰ → Import (o Ctrl+I) → select a file to import → Import.

Si no funciona.

  • unknown shorthand flag: 'd' in -d o docker: unknown command: docker compose: tienes el cliente docker pero no el plugin Compose. Pasa, por ejemplo, si instalaste solo el paquete Docker CLI con winget. Ese paquete tampoco trae el motor que ejecuta contenedores Linux, que son los que usa el curso. Instala Docker Desktop (siguiente punto) y desinstala el otro paquete para que no se mezclen: winget uninstall Docker.DockerCLI.
  • docker compose no se reconoce o failed to connect to the docker API: Docker Desktop no está instalado o no está arrancado. En Windows, instálalo con winget install Docker.DockerDesktop (necesita permisos de administrador y WSL 2, y puede pedir reiniciar), ábrelo y espera a que el icono de la ballena diga Engine running. Comprueba que todo está en orden con docker compose version y docker run --rm hello-world.
  • ports are not available: exposing port TCP 0.0.0.0:1883 … Only one usage of each socket address: otro programa usa ya el puerto 1883. Lo habitual es un Mosquitto que instalaste en tu PC en la práctica anterior. En Windows, averigua cuál es con Get-NetTCPConnection -LocalPort 1883 -State Listen (la columna OwningProcess es su PID) y detenlo: si es el servicio de Mosquitto, con Stop-Service mosquitto en una terminal de administrador. Si pasa con el 1880, es el Node-RED nativo del paso 1. Después repite docker compose up -d.
  • El editor no carga: espera un minuto y mira el log con docker compose logs node-red.

El simulador

El simulador reproduce el invernadero: publica los mismos topics y con el mismo formato que sus sensores, y responde a los comandos de la bomba y el ventilador. SIM_VELOCIDAD=60 hace que un minuto real equivalga a una hora simulada: verás secarse el suelo en pocos minutos. Mira qué publica con docker compose exec mosquitto mosquitto_sub -u alumno -P alumno -t "invernadero/#" -v (sal con Ctrl+C). También tiene un panel web en http://localhost:8090 para ver el invernadero en tiempo real y provocar situaciones como una helada o una tormenta. La guía del simulador explica qué valores publica, cómo encender la bomba y el ventilador y cómo provocar fallos.

Paso 3 · Anatomía de msg (15 min) ​

Para qué sirve. Todo lo que viaja por un cable es un objeto msg. En este paso vas a ver qué contiene, a cambiar sus valores y a añadirle una propiedad tuya. Es la base de todo lo demás.

3.1 · Configura el inject. Ya en el Node-RED de Docker, crea un inject unido a un debug, como en el paso 1.5. Después haz doble clic en el inject: se abre su diálogo de configuración en un panel a la derecha.

Diálogo Edit inject node: Name "humedad 42.5"; propiedad msg.payload de tipo texto con valor 42.5; propiedad msg.topic de tipo texto con valor invernadero/suelo/humedad

  1. En la fila msg.payload, pincha en la flechita ▾ del desplegable de tipo (a la izquierda del valor) y elige string (icono az). Escribe 42.5 como valor.
  2. En la fila msg.topic, escribe invernadero/suelo/humedad. Si esa fila no existe, añádela con el botón +add de debajo de la lista.
  3. En Name, escribe humedad 42.5: el nombre es lo que se ve en el lienzo.
  4. Pulsa Done (arriba a la derecha del diálogo) para aceptar. Cancel descarta los cambios.

3.2 · Configura el debug para ver el mensaje entero. Doble clic en el debug:

Diálogo Edit debug node: Output "complete msg object", To "debug window" marcado, Name "mensaje completo"

  1. En Output, abre el desplegable y elige complete msg object. Por defecto solo muestra msg.payload.
  2. En Name, escribe mensaje completo.
  3. Done, Deploy y pulsa el botón del inject.

Qué debes ver. En la pestaña debug, un mensaje con : msg : Object. Pincha en la flechita ▸ para desplegarlo: aparecen _msgid, payload: "42.5" y topic: "invernadero/suelo/humedad".

3.3 · Añade una propiedad con un nodo change. El nodo change modifica el mensaje sin escribir código. Vas a añadir msg.unidad con el valor %.

  1. Insértalo en el cable: busca change en la paleta (sección function, color amarillo), arrástralo y suéltalo encima del cable que une el inject con el debug. Cuando el cable se vuelva discontinuo, suelta: el nodo queda insertado entre los dos.

    Otra forma: pincha en el cable (se resalta), pulsa Supr para borrarlo, y cablea inject → change → debug.

    Flujo del paso 3: inject "humedad 42.5" unido a un change "añadir unidad" y este a un debug "mensaje completo"

  2. Configúralo: doble clic en el change. Trae una regla, que se lee como una frase: Set msg. payload to the value …

    Diálogo Edit change node: Name "añadir unidad"; regla Set msg.unidad to the value, de tipo texto, %

    • En el campo de la derecha de msg., borra payload y escribe unidad.
    • En to the value, deja el tipo az (texto) y escribe %.
    • En Name, escribe añadir unidad.
    • Done.
  3. Deploy y pulsa el inject.

Qué debes ver. El mensaje llega con una propiedad más, unidad: "%":

Pestaña debug con el mensaje desplegado: _msgid, payload "42.5", topic "invernadero/suelo/humedad" y unidad "%"

Si no funciona.

  • Solo sale "42.5": el debug sigue en msg.payload; cambia Output a complete msg object.
  • No aparece unidad: revisa que la regla es Set (no Change ni Delete) y que no hay un espacio antes o después de unidad.

Paso 4 · Conectar con el invernadero: mqtt in (30 min) ​

Para qué sirve. Recibir una lectura del invernadero, igual que hacía tu script Python con subscribe. Aquí aparece un concepto nuevo: el nodo de configuración, que guarda los datos de conexión al broker y comparten todos los nodos MQTT.

4.1 · Añade el mqtt in. En la paleta, sección network, arrastra mqtt in al lienzo y haz doble clic en él.

Diálogo Edit mqtt in node: Server "Broker invernadero" con botones de lápiz y +; Action "Subscribe to single topic"; Topic invernadero/suelo/humedad; QoS 0; Output "a String"; Name "humedad del suelo"

4.2 · Crea el nodo de configuración del broker. En Server aparece Add new mqtt-broker...: pulsa el lápiz de su derecha. Se abre un segundo diálogo encima del primero.

En la pestaña Connection:

Diálogo Edit mqtt-broker node, pestaña Connection: Name "Broker invernadero", Server ${MQTT_HOST}, Port ${MQTT_PORT}, Connect automatically marcado, Protocol MQTT V3.1.1, Client ID vacío

CampoValorPor qué
NameBroker invernaderoEs el nombre con el que lo elegirás en otros nodos
Server${MQTT_HOST}Se sustituye por la variable del .env: si cambia el broker, cambias el .env, no el flujo
Port${MQTT_PORT}Igual, normalmente 1883
Client IDvacíoNode-RED genera uno aleatorio. Si dos alumnos usan el mismo, el broker los expulsa en bucle

En la pestaña Security:

Diálogo Edit mqtt-broker node, pestaña Security: Username alumno y Password con la contraseña oculta

  • Username: alumno.
  • Password: la de MQTT_ALUMNO_PASS en tu .env (alumno si no la cambiaste).

Pulsa Add (arriba a la derecha). Vuelves al diálogo del mqtt in, con Broker invernadero ya elegido en Server.

4.3 · Configura la suscripción en el mqtt in:

CampoValor
ActionSubscribe to single topic
Topicinvernadero/suelo/humedad
QoS0
Outputa String: queremos el texto tal cual llega
Namehumedad del suelo

Done. Une su salida a un debug nuevo y pulsa Deploy.

Qué debes ver. Bajo el mqtt in, un cuadradito verde con el texto connected. En debug, una lectura cada pocos segundos (por ejemplo "50.1"). La primera llega nada más desplegar: es el valor retenido (retain) que guarda el broker (qué es el retain).

Si no funciona.

  • Pone connecting o disconnected: comprueba que MQTT_ALUMNO_PASS del .env coincide con la contraseña que has puesto, y que docker compose ps muestra mosquitto y simulador.
  • Pone connected pero no llega nada: revisa el topic letra a letra; MQTT distingue mayúsculas y minúsculas.
  • El estado alterna entre connected y disconnected cada pocos segundos: otro cliente usa tu mismo Client ID y el broker os expulsa por turnos. Abre el nodo Broker invernadero y deja Client ID vacío, para que Node-RED genere uno único.

Topics disponibles (todos con payload numérico en texto):

TopicMagnitud
invernadero/suelo/humedadHumedad del suelo (%)
invernadero/dht22/temperatura · invernadero/dht11/temperaturaTemperatura ambiente (ºC)
invernadero/dht22/humedad · invernadero/dht11/humedadHumedad ambiente (%)
invernadero/ultrasonidos/distanciaDistancia al agua del depósito (cm)
invernadero/balanza/pesoPeso (g)
invernadero/tds/tdsSólidos disueltos en el agua (ppm)

Paso 5 · De texto a número con change (15 min) ​

Para qué sirve. Los ESP32 publican texto: "50.1", no 50.1. Si comparas texto con un número ("9" < "25" es false porque compara carácter a carácter), obtendrás resultados erróneos sin ningún aviso. Hay que convertirlo.

Qué hacer.

  1. Inserta un change entre el mqtt in y el debug (como en el paso 3.3) y ábrelo.
  2. En la regla deja Set msg. payload.
  3. En to the value, abre el desplegable de tipo y elige expression (icono J:). Escribe $number(payload).
  4. Name: texto → número. Done y Deploy.

Diálogo Edit change node: Name "texto → número"; regla Set msg.payload to the value, de tipo expresión JSONata, $number(payload)

$number(...) es una función de JSONata, un lenguaje de expresiones que Node-RED usa en muchos campos. Dentro de la expresión, payload significa msg.payload.

Qué debes ver. Para comprobar la diferencia, deja un debug directamente en la salida del mqtt in y otro detrás del change:

Flujo del paso 5: el mqtt in "humedad del suelo" con el estado connected va a un debug "como texto" y, a través del change "texto → número", a un debug "como número"

Pestaña debug con dos mensajes: el de "como texto" muestra "50.1" en rojo entre comillas y tipo string; el de "como número" muestra 50.1 en azul y tipo number

El texto aparece en rojo, entre comillas y con tipo string; el número, en azul, sin comillas y con tipo number.

Si no funciona. Sale NaN o un error: el tipo del valor no es expression (con az estarías guardando literalmente el texto $number(payload)).

Paso 6 · Probar sin sensores (10 min) ​

Para qué sirve. Probar la lógica con valores concretos, sin depender de lo que marque el sensor en ese momento. Son tus casos de prueba: los usarás en los pasos siguientes y en el entregable.

Qué hacer.

  1. Añade tres inject. En cada uno: msg.payload de tipo string con los valores 20.0, 30.0 y 50.0, y Name prueba: 20 %, prueba: 30 %, prueba: 50 %.
  2. Une la salida de los tres a la entrada del change texto → número. Una entrada puede recibir tantos cables como quieras.
  3. Deploy.

Qué debes ver. Al pulsar cada inject, el debug de detrás del change muestra 20, 30 o 50 como número. Es exactamente el mismo camino que recorren las lecturas reales.

Paso 7 · Umbrales en el contexto de flujo (20 min) ​

Para qué sirve. Los umbrales no deben estar escritos a fuego dentro de los nodos: se cargan una vez en el contexto de flujo (una memoria compartida por los nodos de la pestaña) y todos los nodos los leen de ahí. Así, cambiar un umbral es cambiar un solo sitio.

7.1 · Un inject que se dispara solo al desplegar. Añade un inject y ábrelo:

Diálogo Edit inject node: Name "cargar umbrales"; msg.payload de tipo JSON con el valor {"suelo":{"critico":25,"aviso":35}}

  1. Name: cargar umbrales.

  2. En msg.payload, elige el tipo JSON (icono {}) y escribe:

    json
    { "suelo": { "critico": 25, "aviso": 35 } }

    El botón … de la derecha abre un editor más cómodo que avisa si el JSON está mal escrito.

  3. Si hay fila msg.topic, bórrala con su ×: no hace falta.

  4. Más abajo, marca Inject once after 0.1 seconds, then y deja Repeat en none: se disparará una vez, justo después de cada Deploy.

    Detalle del diálogo del inject: casilla Inject once after 0.1 seconds marcada y Repeat none

7.2 · Guardarlo en el contexto. Une el inject a un change con la regla Set flow. umbrales to the value msg. payload. Para escribir flow. en el primer campo, abre su desplegable de tipo y elige flow.; en el segundo, elige msg.. Name: flow.umbrales = payload. Done y Deploy.

Qué debes ver. Abre la pestaña Context Data de la barra lateral (icono de base de datos; si no aparece, búscala en la flechita ▾ del extremo derecho de las pestañas). En la sección Flow, pulsa el botón de refrescar (↻):

Pestaña Context Data, sección Flow: umbrales desplegado muestra suelo con critico 25 y aviso 35; también aparecen estadoSuelo y ultimaHumedadSuelo

umbrales aparece con suelo.critico: 25 y suelo.aviso: 35. estadoSuelo y ultimaHumedadSuelo aparecerán cuando completes el paso 9.

Si no funciona. umbrales no aparece: pulsa ↻ (esta pestaña no se refresca sola), y comprueba que el inject tiene marcado Inject once after.

Paso 8 · Clasificar con switch (20 min) ​

Para qué sirve. El nodo switch es el if de Node-RED: envía cada mensaje por una salida u otra según unas reglas. Los dos umbrales dividen el rango de humedad en tres bandas. Así se clasificaría un día sin riego:

Humedad del suelo de un día sin riego: baja de 52 % a 18 %; pasa a aviso al cruzar 35 % a las 13:40 y a crítico al cruzar 25 % a las 16:20, momento en que el flujo decide regar

8.1 · Configura el switch. Añade un switch (sección function) detrás del change texto → número y ábrelo:

Diálogo Edit switch node: Name "clasificar"; Property msg.payload; regla 1 menor que flow.umbrales.suelo.critico hacia la salida 1; regla 2 menor que flow.umbrales.suelo.aviso hacia la salida 2; regla 3 otherwise hacia la salida 3

  1. Name: clasificar. Property: msg.payload (ya viene así).

  2. La primera regla ya existe. En su primer desplegable elige <. En el desplegable de tipo del valor elige flow. y escribe umbrales.suelo.critico.

  3. Pulsa +add (bajo la lista) para una segunda regla: <, tipo flow., umbrales.suelo.aviso.

  4. Pulsa +add otra vez y en el primer desplegable elige otherwise (el "en otro caso").

  5. Abajo del todo, cambia checking all rules por stopping after first match:

    Detalle del diálogo del switch: desplegable con la opción stopping after first match

    Sin esta opción, un 20 % cumpliría las dos primeras reglas (20 < 25 y 20 < 35) y saldría por las dos salidas.

  6. Done. El nodo tiene ahora tres puertos de salida, numerados de arriba abajo; si pasas el ratón por uno, ves su número.

8.2 · Etiqueta cada salida. Añade tres change, uno por salida, cada uno con la regla Set msg. estado to the value (tipo az) crítico, aviso o normal. Llámalos estado = crítico, estado = aviso y estado = normal, y une la salida 1 al primero, la 2 al segundo y la 3 al tercero.

Qué debes ver. Conecta un debug en complete msg object a cada change, Deploy, y pulsa los tres inject de prueba: 20 llega con estado: "crítico", 30 con "aviso" y 50 con "normal".

Si no funciona. Todo sale como normal: los umbrales no están en el contexto (repasa el paso 7) o el tipo del valor de las reglas quedó en az en lugar de flow., con lo que compara con el texto "umbrales.suelo.critico".

Paso 9 · Decidir con function (25 min) ​

Para qué sirve. Cuando la lógica no cabe en un switch o un change, el nodo function permite escribir JavaScript. Aquí decidirá si hay que regar y guardará el último estado.

Qué hacer.

  1. Añade un function (sección function, naranja) y une a su entrada las salidas de los tres change de estado.

  2. Ábrelo. Name: decidir riego. En la pestaña On Message borra lo que haya y pega el código:

    Diálogo Edit function node: Name "decidir riego", pestaña On Message con el código de la función

    js
    // Al arrancar pueden llegar lecturas retenidas antes que los umbrales:
    // sin umbrales, el switch no ha podido clasificar bien la lectura
    if (!flow.get("umbrales")) {
        node.warn("Lectura ignorada: los umbrales aún no están cargados");
        return null;
    }
    
    // Guarda el último estado en el contexto de flujo y decide la acción
    const anterior = flow.get("estadoSuelo");
    flow.set("estadoSuelo", msg.estado);
    flow.set("ultimaHumedadSuelo", msg.payload);
    
    const accion = msg.estado === "crítico" ? "regar" : "no regar";
    
    msg.payload = {
        humedad: msg.payload,
        estado: msg.estado,
        accion: accion,
        cambio: msg.estado !== anterior   // true solo cuando cambia el estado
    };
    
    node.status({
        fill: msg.estado === "normal" ? "green" : msg.estado === "aviso" ? "yellow" : "red",
        shape: "dot",
        text: `${msg.payload.humedad} % → ${accion}`
    });
    return msg;
  3. Done. Une la salida del function a un debug llamado decisión (en msg.payload) y pulsa Deploy.

Qué hace el código:

  • flow.get(...) / flow.set(...) leen y escriben el contexto de flujo del paso 7.
  • return msg envía el mensaje por la salida; return null no envía nada.
  • La comprobación del principio evita una condición de carrera. Los topics del invernadero llevan retain, así que al desplegar llega enseguida la última lectura, a veces antes de que el inject haya cargado los umbrales. Sin ellos, el switch compara con undefined, todas las reglas fallan y la lectura sale por otherwise: se clasificaría como normal sin avisar.
  • node.status(...) muestra un indicador bajo el nodo: útil para ver el estado sin abrir la depuración.
  • cambio servirá en la sesión 6 para avisar solo cuando el estado cambia, no con cada lectura.

Qué debes ver. Pulsa los tres inject de prueba. En debug, una decisión por cada uno, y bajo el nodo decidir riego un punto de color con el último valor:

Flujo completo de la práctica guiada: umbrales, entradas, texto a número, clasificar, estados y decidir riego con el estado "50 % → no regar"; en la pestaña debug, las decisiones para 20 % (crítico, regar), 30 % (aviso, no regar) y 50 % (normal, no regar)

Entradaestadoaccion
20críticoregar
30avisono regar
50normalno regar

Después deja correr los datos reales: cada lectura del sensor produce una decisión.

Si no funciona.

  • Aparece Lectura ignorada… en debug: es el aviso de la condición de carrera. Es normal justo tras un Deploy; si se repite siempre, el inject cargar umbrales no se está disparando.
  • Error SyntaxError al pulsar Done: falta o sobra un paréntesis o una llave; el editor del function marca la línea con una cruz roja.

Si te atascas, puedes descargar el flujo de referencia de la práctica guiada: s1-control-riego.json. Impórtalo con menú ☰ → Import, abre el nodo Broker invernadero (doble clic en el mqtt in → lápiz de Server) y escribe el usuario y la contraseña en Security: las credenciales nunca se exportan.

Node-RED como plataforma ​

Dentro de una instalación de Node-RED ​

Todo lo que distingue a tu Node-RED de otro está en su directorio de usuario: ~/.node-red en la instalación nativa y /data en el contenedor.

FicheroContenido
settings.jsConfiguración del runtime: puerto, seguridad del editor, almacenamiento del contexto…
flows.jsonTus flujos: lo que guardas al pulsar Deploy
flows_cred.jsonLas credenciales de los nodos (contraseñas, tokens), cifradas y separadas de los flujos
package.json y node_modules/Los nodos instalados desde la paleta
.config.*.jsonEstado interno del editor; no lo toques

Hacer copia de seguridad de un Node-RED es copiar ese directorio. En la sesión 6 editarás settings.js para proteger el editor y cifrar las credenciales.

Contexto: dónde vive el estado ​

  • La pestaña Context Data muestra el contexto de nodo, flujo y global. Úsala para depurar.
  • Por defecto el contexto está en memoria: se pierde al reiniciar Node-RED. Por eso los umbrales se cargan con un inject once.
  • Usa flow para lo que comparten los nodos de una pestaña y global solo para lo que necesiten varias pestañas.

Organizar el flujo ​

  • Nombres: cada nodo con un nombre que diga qué hace (texto → número, no change).
  • Comentarios: nodos comment como títulos de sección. Su pestaña info admite Markdown.

Importar y exportar ​

  • Ctrl+E exporta la selección, la pestaña o todos los flujos a JSON. Ctrl+I importa.
  • El JSON incluye los nodos de configuración (el broker) pero no las credenciales: por eso puedes compartir flujos sin filtrar contraseñas.
  • Exportar es la forma de entregar tu trabajo y de guardar copias: hazlo al final de cada sesión.

Entregable y evidencias para el informe ​

Qué debe funcionar ​

Amplía el flujo de la práctica guiada para que controle también la temperatura:

  1. Suscríbete además a invernadero/dht22/temperatura y conviértela a número.

  2. Añade al inject de umbrales los de temperatura, por ejemplo:

    json
    {
      "suelo":       { "critico": 25, "aviso": 35 },
      "temperatura": { "aviso": 30, "critico": 35 }
    }
  3. Clasifica cada temperatura como normal, aviso o crítico. Cuidado: aquí el peligro está en los valores altos.

  4. Una única función de decisión que, con la última lectura de cada sensor guardada en el contexto, produzca:

    json
    { "regar": true, "ventilar": false, "suelo": "crítico", "temperatura": "normal" }

    Criterio mínimo: regar si el suelo está en estado crítico y ventilar si la temperatura está en aviso o crítico.

  5. Casos de prueba con inject que cubran los tres estados de cada magnitud.

Cómo se comprueba ​

  • Con los inject de prueba, cada combinación produce la decisión esperada.
  • Con los datos del simulador, la decisión se actualiza al llegar cada lectura.
  • Cambiar un umbral en el inject y volver a pulsarlo cambia el comportamiento sin tocar ningún otro nodo.

Criterios de calidad: umbrales solo en el contexto (ningún número "mágico" dentro de switch o function), nodos con nombre y flujo organizado con comentarios.

Evidencias que debes guardar ​

  • [ ] Captura de la terminal con Node-RED nativo arrancado (versiones y User directory) y del listado de tu ~/.node-red.
  • [ ] Captura del flujo completo.
  • [ ] Captura de la depuración con al menos un caso de cada estado para cada magnitud.
  • [ ] Captura de Context Data con los umbrales y los últimos valores guardados.
  • [ ] Flujo exportado: s1-<tu-apellido>.json.
  • [ ] En el informe, respuesta breve a:
    • ¿Dónde se guardan tus flujos en la instalación nativa y en Docker? ¿Qué ganas usando Docker?
    • ¿Qué ventajas e inconvenientes ves frente a tu script Python de la práctica anterior?
    • ¿Por qué hay que convertir el payload a número y qué pasaría si no lo hicieras?
    • ¿Por qué el switch debe detenerse en la primera coincidencia?

Recursos adicionales ​