Tema
Guía del simulador
El simulador es un pequeño programa en Python, dentro del entorno Docker, que hace de invernadero. Publica en el Mosquitto local los mismos topics y con el mismo formato que los ESP32 reales, y responde a los comandos de los Shelly como lo harían la bomba y el ventilador. Todo el módulo se hace con él, y un flujo que funciona con el simulador funciona también con el invernadero real: solo cambia el broker en el .env (ver Trabajar con el invernadero real).
Esta guía reúne lo que necesitas para trabajar con él: su panel web, qué publica, cómo evoluciona, cómo actuar sobre la bomba y el ventilador, y cómo provocar fallos y situaciones extremas (una helada, una tormenta…) para comprobar tus flujos.
Solo con el simulador
Todo lo de esta página funciona con el .env en modo simulador (el modo por defecto, ver el paso 2 de la sesión 1). Los topics simulador/... no existen en el invernadero real.
El panel del simulador
El simulador tiene un panel web en http://localhost:8090. Desde él ves en tiempo real lo que pasa dentro del invernadero y lo manejas sin escribir comandos:

| Zona | Qué muestra | Qué puedes hacer |
|---|---|---|
| Cabecera | Conexión con el broker, hora simulada y temperatura exterior | Cambiar la velocidad del tiempo, pausarlo y saltar a una hora del día |
| Escenarios | El escenario activo y su descripción | Lanzar una situación completa: helada, tormenta, corte de red… (ver Escenarios) |
| Actuadores | Bomba y ventilador: encendido o apagado, potencia y energía. El ventilador gira y la bomba gotea mientras riega | Pulsar botón del enchufe: cambia el relé como el botón físico del Shelly, sin que Node-RED lo pida |
| Depósito | Nivel de agua, distancia que mide el ultrasonidos y peso de la maceta | Rellenarlo |
| Estado físico | Temperatura, humedades, nivel y TDS reales del modelo, con una gráfica de los últimos 5 minutos | Cambiar cualquiera a mano (ver Cambiar valores a mano) |
| Nodos ESP32 | Si cada nodo está online y el último valor de cada topic, con su antigüedad. En rojo, lo que lleva demasiado sin publicar | Provocar y quitar fallos con un clic (ver Provocar fallos) |
| Registro | Lo que ha pasado, con hora real y simulada: comandos que llegan por MQTT, cambios de escenario, fallos… |
Lo más útil del panel es comprobar si tus flujos actúan: cuando Node-RED envía un comando a un Shelly, la tarjeta del equipo se enciende y el registro muestra shellyplug-s-SIM001 -> on (bomba, MQTT).
El panel no sustituye a tu panel de Node-RED
Es la "realidad" del invernadero, vista desde fuera. Tu panel de la sesión 4 debe mostrar lo mismo a partir de lo que llega por MQTT. Compararlos es una buena prueba: si un sensor está en fallo, el panel del simulador sigue sabiendo el valor real, pero tu Node-RED no debería presentarlo como actual.
Si no se abre. Ejecuta docker compose up -d --build en tu carpeta docker: el simulador se reconstruye con el panel. Si aun así no abre, tu entorno es de una versión anterior del curso: descarga de nuevo entorno-docker.zip, descomprímelo encima de tu carpeta docker aceptando reemplazar los ficheros (tu .env se conserva) y repite el comando.
Qué afecta a qué
Dos relaciones que no se ven en el dibujo: con más calor el suelo se seca antes, y la bomba no riega si el depósito está vacío.
El tiempo va acelerado
SIM_VELOCIDAD=60 (en tu .env) hace que un minuto real equivalga a una hora simulada: un día entero pasa en 24 minutos. Así ves secarse el suelo o subir la temperatura sin esperar horas.
- La hora simulada arranca en la hora real a la que se inicia el simulador y desde ahí avanza 60 veces más rápido.
- Desde el panel puedes pausar el tiempo, cambiar la velocidad (x1 es tiempo real; x300 pasa un día en menos de 5 minutos) y saltar a una hora del día, por ejemplo a las 03:00 para ver una helada. Con el tiempo en pausa los sensores siguen publicando, siempre el mismo valor.
- Los cambios del panel se pierden al reiniciar el simulador. Para cambiar la velocidad de forma permanente, pon
SIM_VELOCIDADen el.env(por ejemplo1para tiempo real) y ejecutadocker compose up -d.
Los tiempos de esta guía están en minutos reales con la velocidad por defecto.
Qué publica
Todos los payloads son números en texto (por ejemplo "23.4"), igual que los ESP32. Los sensores publican con retain: al suscribirte recibes al instante la última lectura.
Topic (invernadero/...) | Unidad | Rango en el simulador | Cuándo publica |
|---|---|---|---|
dht22/temperatura | ºC | 10 – 30 (unos 6 menos con el ventilador), ruido de ±0,1 | cada 5 s |
dht22/humedad | % | 50 – 95 | cada 5 s |
dht11/temperatura, dht11/humedad | ºC, % | como el DHT22, pero redondeado a enteros y con un pequeño sesgo (+0,8 ºC, −2 %) | cada 5 s |
suelo/humedad | % | 5 – 95 | al cambiar 1 % o cada 5 s |
suelo/lectura | ADC | 2920 (seco) – 1480 (mojado) | junto con la humedad |
balanza/peso | g | 4260 – 5340: sube con la humedad del suelo | al cambiar 1 g o cada 5 s |
ultrasonidos/distancia | cm | 5 (depósito lleno) – 40 (vacío) | al cambiar 1 cm o cada 5 s |
tds/tds | ppm | empieza en unos 370 y deriva despacio | al cambiar 2 ppm o cada 5 s |
tds/voltaje | V | empieza en 1,0 | junto con el TDS |
<nodo>/online | 1 / 0 | 1 si el nodo está alcanzable | al cambiar (retain) |
<nodo> es dht11, dht22, balanza, ultrasonidos, suelo, tds o actuador.
Los dos Shelly publican en invernadero/shelly/<id>/...:
| Topic | Payload | Cuándo publica |
|---|---|---|
relay/0 | on / off (retain) | al recibir un comando y cada 30 s |
relay/0/power | W: 35 la bomba y 22 el ventilador encendidos, 0 apagados | al recibir un comando y cada 30 s |
relay/0/energy | W·min acumulados desde que arrancó el simulador | al recibir un comando y cada 30 s |
online | true (retain) | al recibir un comando y cada 30 s |
| Equipo | Shelly en el simulador |
|---|---|
| Bomba de riego | shellyplug-s-SIM001 |
| Ventilador | shellyplug-s-SIM002 |
Valores al arrancar el simulador: suelo al 55 %, depósito al 80 % (unos 12 cm), 22 ºC, bomba y ventilador apagados.
Cómo evoluciona
| Qué | Cómo cambia (minutos reales) |
|---|---|
| Temperatura | Sigue el ciclo del día: mínimo de unos 10 ºC de madrugada y máximo de unos 30 ºC a primera hora de la tarde (hora simulada). Reacciona a los cambios en menos de un minuto |
| Humedad del aire | Baja cuando sube la temperatura |
| Suelo | Se seca entre 1 y 2 puntos por minuto, más cuanto más calor hace. Nunca baja del 5 % |
| Suelo con la bomba encendida | Sube unos 13 puntos por minuto, hasta el 95 % |
| Depósito con la bomba encendida | Pierde un 10 % por minuto: de lleno a vacío en 10 minutos |
| Calidad del agua | Deriva al azar, muy despacio |
Si el entorno lleva tiempo encendido
El suelo se seca solo, así que tras un rato sin regar estará en el 5 %, y tus flujos verán una alarma de suelo seco permanente. Es lo esperado. Riega con la bomba o reinicia el simulador para volver a los valores iniciales.
Escenarios
Un escenario cambia el entorno del invernadero, y el modelo reacciona poco a poco, como lo haría el real: con una helada la temperatura no cae de golpe, baja durante varios minutos. Solo hay un escenario activo a la vez; Normal vuelve al clima de siempre.
| Escenario | Qué pasa | Para comprobar en tus flujos |
|---|---|---|
| Helada | El exterior baja 14 ºC: bajo cero de madrugada. De día no llega a helar | Alarmas de temperatura baja. Salta a las 03:00 para verla en un par de minutos |
| Ola de calor | El exterior sube 13 ºC: más de 40 ºC dentro por la tarde, el aire más seco y el suelo se seca 2,5 veces más rápido | La decisión de ventilar y de regar, las alarmas de temperatura alta |
| Tormenta | Frío, sin sol y humedad cerca del 95 %. La Wi-Fi se corta a ratos: cada nodo, también el actuador, se desconecta entre 5 y 25 s y vuelve | Eventos inalcanzable/alcanzable que van y vienen, comandos que no se confirman, antirrebote de alarmas (sesión 6) |
| Fuga en el depósito | El depósito pierde agua sin que la bomba esté encendida y el suelo se seca algo más rápido | Detectar que baja el nivel sin estar regando |
| Agua de mala calidad | El TDS sube poco a poco hasta más de 1000 ppm. Al rellenar el depósito vuelve el agua limpia (unos 370 ppm) | Alarmas de calidad del agua, tendencias (sesión 5) |
| Sensores averiados | El DHT22 da a veces lecturas imposibles (-3276.7 y 3276.7), el fallo típico de este sensor. El de suelo tiene el cable suelto: lectura 4095 y humedad 0 | La validación por rango del paso 3 de la sesión 3, y por qué no basta: un 0 % de humedad pasa el filtro |
| Corte de red | Se cae la red del invernadero: ningún nodo publica, todos los online pasan a 0 y los comandos a los Shelly se pierden | Que tu sistema avisa de una caída general (mejor una alarma con la causa que quince alarmas sueltas) |
Los escenarios no tocan los fallos que hayas puesto a mano: al volver a Normal, cada nodo sigue como lo dejaste.
Cambiar valores a mano
En la zona Estado físico del panel puedes cambiar la temperatura, las humedades del aire y del suelo, el nivel del depósito y el TDS. Escribe el valor y elige:
- Aplicar: pone ese valor y deja que el modelo siga evolucionando desde ahí. Por ejemplo, el suelo al 15 % para ver si tu riego automático arranca.
- Fijar: lo mantiene en ese valor, pase lo que pase, hasta que pulses Soltar. Sirve para probar un umbral con calma, por ejemplo la temperatura fijada en 35 ºC.
Cambias la magnitud física, no un topic: con la temperatura a 35 ºC la publican los dos DHT (cada uno con su error), y con el suelo al 15 % también baja el peso de la balanza.
Cómo enviarle órdenes
La forma más cómoda es el panel. Pero todo lo que hace el panel también se puede pedir por MQTT, con el usuario alumno, y eso permite automatizar las pruebas desde Node-RED. Estos son los topics de control:
| Topic | Payload | Qué hace |
|---|---|---|
simulador/fallo/<nodo> | ok, sensor o desconectado | Provoca o quita un fallo (ver Provocar fallos) |
simulador/escenario | normal, helada, calor, tormenta, fuga, agua, averia o corte | Lanza un escenario |
simulador/deposito/rellenar | cualquiera | Rellena el depósito con agua limpia |
simulador/velocidad | número: 1, 60, 300… (0 pausa) | Cambia la velocidad del tiempo |
simulador/hora | HH:MM, por ejemplo 03:00 | Salta a esa hora simulada |
Tienes tres formas de publicarlos; elige la que te resulte más cómoda.
Desde la terminal
Dentro de tu carpeta docker, con el mosquitto_pub que trae el contenedor del broker (no tienes que instalar nada; sus opciones están en Probar desde la terminal):
bash
docker compose exec mosquitto mosquitto_pub -u alumno -P alumno -t <topic> -m <payload>Si cambiaste MQTT_ALUMNO_PASS en el .env, pon tu contraseña después de -P. Para ver todo lo que publica el invernadero en ese momento (sal con Ctrl+C):
bash
docker compose exec mosquitto mosquitto_sub -u alumno -P alumno -t "invernadero/#" -vDesde Node-RED: una pestaña de pruebas
Es la forma más cómoda si vas a provocar fallos a menudo: cada orden queda en un botón.
- Crea una pestaña nueva llamada
Pruebas simulador. - Arrastra un
mqtt out(paleta, sección network) y ábrelo. En Server eligeBroker invernaderoy deja Topic vacío: así usará elmsg.topicde cada mensaje. Done. - Añade un
injecty únelo almqtt out. Ábrelo y rellena:- msg.payload, tipo string (az): el payload de la orden, por ejemplo
sensor. - msg.topic: el topic, por ejemplo
simulador/fallo/suelo. - Name: lo que hace, por ejemplo
suelo: fallo sensor.
- msg.payload, tipo string (az): el payload de la orden, por ejemplo
- Repite el paso 3 con un
injectpor cada orden que quieras tener a mano (por ejemplo, la que restaura el fallo conok), todos unidos al mismomqtt out. Deploy.

Qué debes ver. Bajo el mqtt out, el estado connected. Al pulsar el botón de un inject, el log del simulador muestra la orden (ver Ver lo que hace el simulador).
Si no funciona. El mqtt out se queda en connecting: has elegido un nodo de broker sin contraseña. Pasa al importar un flujo de referencia, porque las credenciales no se exportan, y acabas con dos brokers parecidos en el desplegable Server. Elige el que usan tus mqtt in (los que están en connected), o abre el importado con el lápiz y escribe la contraseña en la pestaña Security.
Desde un cliente MQTT
Si usaste MQTT Explorer o MQTTX en la práctica de MQTT, conéctalo a localhost, puerto 1883, usuario alumno. Además de publicar órdenes, verás el árbol completo de topics con sus valores.
Actuar sobre la bomba y el ventilador
Igual que con los Shelly reales: se publica on, off o toggle en el topic de comando.
| Orden | Topic | Payload |
|---|---|---|
| Encender la bomba | invernadero/shelly/shellyplug-s-SIM001/relay/0/command | on |
| Apagar la bomba | invernadero/shelly/shellyplug-s-SIM001/relay/0/command | off |
| Encender el ventilador | invernadero/shelly/shellyplug-s-SIM002/relay/0/command | on |
| Apagar el ventilador | invernadero/shelly/shellyplug-s-SIM002/relay/0/command | off |
| Pedir el estado de los dos Shelly | invernadero/shelly/command | update |
Por ejemplo, desde la terminal:
bash
docker compose exec mosquitto mosquitto_pub -u alumno -P alumno -t invernadero/shelly/shellyplug-s-SIM002/relay/0/command -m onQué debes ver. En el panel, la tarjeta del equipo se enciende y el registro muestra el comando. El Shelly confirma al instante en relay/0 (on) y relay/0/power (22 W el ventilador, 35 W la bomba). Después, en uno o dos minutos, cambian los sensores: con el ventilador baja la temperatura del DHT22; con la bomba sube la humedad del suelo y el peso, y aumenta la distancia del ultrasonidos porque baja el agua del depósito.
Cuando el depósito se vacía, el ultrasonidos marca 40 cm y la bomba deja de regar aunque siga encendida (el panel lo avisa en su tarjeta). Rellénalo con el botón Rellenar depósito del panel o con:
bash
docker compose exec mosquitto mosquitto_pub -u alumno -P alumno -t simulador/deposito/rellenar -m 1El payload da igual. Con el invernadero real, el depósito se rellena a mano.
El botón del enchufe. Los Shelly Plug S tienen un botón físico que enciende y apaga el relé. En el panel, Pulsar botón del enchufe hace lo mismo: el Shelly cambia y publica su nuevo estado sin que Node-RED lo haya pedido. Tus flujos deben enterarse igualmente, porque leen el estado de relay/0 en vez de suponer que su último comando se cumplió.
Provocar fallos
Los sistemas reales fallan, y tus flujos deben notarlo. El simulador imita dos tipos de fallo por nodo. En el panel, cada nodo de la tabla Nodos ESP32 tiene sus tres botones; por MQTT, se usa el topic simulador/fallo/<nodo>:
| Payload | Qué simula | Qué ves en MQTT |
|---|---|---|
sensor | El sensor se estropea, pero el ESP32 sigue en la red | El nodo deja de publicar lecturas; <nodo>/online sigue en 1 |
desconectado | El ESP32 se apaga o pierde la Wi-Fi | Deja de publicar y <nodo>/online pasa a 0 al instante |
ok | Todo vuelve a la normalidad | Vuelven las lecturas; <nodo>/online en 1 |
Con simulador/fallo/actuador el fallo afecta a los Shelly: el simulador ignora los comandos y los Shelly dejan de publicar. Sirve para comprobar que tu flujo detecta un comando sin confirmar.
bash
# El sensor de suelo deja de publicar
docker compose exec mosquitto mosquitto_pub -u alumno -P alumno -t simulador/fallo/suelo -m sensor
# Vuelve a la normalidad
docker compose exec mosquitto mosquitto_pub -u alumno -P alumno -t simulador/fallo/suelo -m okLa última lectura se queda en el broker
Las lecturas se publican con retain. Cuando un sensor deja de publicar, el broker sigue entregando su último valor a quien se suscriba de nuevo (por ejemplo, al hacer Deploy). Por eso un fallo se detecta por la ausencia de mensajes nuevos durante un tiempo (un watchdog, sesión 3), no por el valor.
Recetas para comprobar tus flujos
| Quieres comprobar… | Haz esto | Deberías ver |
|---|---|---|
| Una alarma de suelo seco | Espera con la bomba apagada | La humedad del suelo baja 1-2 puntos por minuto hasta el 5 % |
| Que el riego funciona | Enciende la bomba | Suben la humedad del suelo y el peso; sube la distancia |
| Un depósito vacío | Deja la bomba encendida unos 8 minutos | Distancia de 40 cm; el suelo deja de subir. Después, rellena el depósito |
| La decisión de ventilar | Mira la temperatura a media tarde (hora simulada) o enciende el ventilador | La temperatura baja unos 6 ºC en uno o dos minutos |
| El watchdog de un sensor | simulador/fallo/<nodo> = sensor | Sin lecturas nuevas de ese nodo; online sigue en 1 |
| Un nodo inalcanzable | simulador/fallo/<nodo> = desconectado | <nodo>/online = 0 al instante |
| Un comando sin confirmar | simulador/fallo/actuador = desconectado y envía un comando | El Shelly no cambia relay/0 |
| Una alarma de helada | Escenario Helada y salta a las 03:00 | La temperatura baja de 0 ºC en un par de minutos |
| Una alarma de calor y la ventilación | Escenario Ola de calor y salta a las 15:00 | Más de 40 ºC; con el ventilador encendido, unos 6 ºC menos |
| Que tus alarmas no se disparan una y otra vez | Escenario Tormenta | Nodos que se desconectan y vuelven cada poco |
| La validación de lecturas | Escenario Sensores averiados | Lecturas de 3276.7 en el DHT22 y 4095 en el suelo |
| Un umbral concreto | Fija la magnitud en el panel (por ejemplo, el suelo al 20 %) | El valor se mantiene hasta que pulses Soltar |
| Que lees el estado real del Shelly | Pulsar botón del enchufe en el panel | Tu flujo ve el cambio aunque no haya enviado ningún comando |
Al terminar cada prueba, restaura con ok, vuelve al escenario Normal y suelta los valores fijados.
Ver lo que hace el simulador
El registro del panel muestra las órdenes que recibe el simulador y los cambios de estado, con la hora real y la simulada, y la tabla de nodos muestra el último valor de cada topic. Lo mismo, sin las lecturas, sale en el log del contenedor:
bash
docker compose logs -f simuladortext
12:52:14 Nodo suelo: sensor
12:52:15 shellyplug-s-SIM002 -> on (ventilador, MQTT)
12:52:17 shellyplug-s-SIM002 -> off (ventilador, MQTT)
12:52:18 Nodo suelo: okSi escribes un nodo o un modo que no existe, verás Fallo no válido: .... Si una orden no aparece en el log, el simulador no la ha recibido: revisa el topic letra a letra y la contraseña.
Reiniciar el simulador
Para volver a los valores iniciales (suelo al 55 %, depósito al 80 %, actuadores apagados, sin fallos, escenario Normal, sin valores fijados y la velocidad del .env):
bash
docker compose restart simuladorAl detenerse, el simulador publica online = 0 en todos los nodos, y al arrancar los vuelve a poner en 1: tus flujos verán una desconexión breve.
Si no funciona
- Las órdenes no hacen nada y el log no las muestra: el
.envno está en modo simulador, o el Mosquitto local no está en marcha.docker compose psdebe mostrarmosquittoysimulador. Connection Refused: not authorisedal publicar: la contraseña no coincide conMQTT_ALUMNO_PASSdel.env.- No llega ningún dato: mira en el panel si dejaste un nodo en fallo o el escenario Corte de red. Pulsa
oken el nodo, vuelve a Normal o reinicia el simulador. - Los valores no cambian: el tiempo está en pausa o el valor está fijado. Mira la cabecera y la zona Estado físico del panel.