Mostrando las entradas con la etiqueta Node-red. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Node-red. Mostrar todas las entradas

domingo, 18 de noviembre de 2018

estación meteorológica con base de datos

Hoy les traigo como hacer que la estación meteorológica almacene los datos con una base de datos.

Esto va a ser muy similar a lo ya implementado con el ejemplo de la base de datos, pero la idea es tener los siguientes campos:

temperatura
humedad
lux
hora
fecha
localización

Estos datos nos van a permitir discriminar la ubicación de las lecturas. Entonces vamos a crear una nueva base de datos, con la ubicación en donde querramos y vamos a poner el nodo inject con lo siguiente en el tópico

CREATE TABLE clima(temperatura NUMERIC, humedad NUMERIC, lux NUMERIC, hora TIME, fecha DATE, localizacion TEXT)

Una vez creada la base de datos ese módulo de injección ya no nos sirve para nada, por lo que podemos eliminar el nodo (sólo para no tener cosas inútiles en la pantalla). Luego vamos a poner un nodo de función en el cuál vamos a poner el siguiente código (para que funcione de la mejor forma posible vamos a modificar el código del esp para que mande todos los mensajes con el formato: temperatura&&&humedad&&&lux&&&localizacion, el dato de la localización lo vamos a embeber en el código de forma manual (sin gps) para no complicar las cosas, quizá algún día hagamos algo similar):


var mensaje = msg.payload.split("&&&");
if((mensaje[0] !== "nan") && (mensaje[1] !== "nan") && (mensaje[2] !== "nan"))
{
    msg.payload = null;
    msg.topic = "INSERT INTO clima(temperatura, humedad, lux) VALUES(" + mensaje[0] + "," + mensaje[1] + "," + mensaje[2] + ")";
    return msg
}
return null;



Que nos va a permitir administrar la información y generar el comando necesario para poder guardarlo con la base de datos, y la segunda parte nos va a permitir graficar todos los datos en un mismo gráfico (queda muy bien, además se van a poder comparar los datos más directamente).


En la imágen está el flujo de ejemplo (en realidad se podría usar, y en lugar del nodo de inyección habría que poner un nodo de MQTT que nos entregue los datos de los sensores), en la cuál concentramos todos los datos en una sola gráfica, y realizando ciertos ajustes podríamos ver qué datos representa cada color o incluso cambiar el color de cada dato.

Para completar el proyecto habría que modificar el código de nuestro micro para que nos mande los lúmenes y los datos de la ubicación. Como no vamos a agregarle datos de ubicación reales (todavía no me meto en el mundo del gps), solo vamos a utilizar identificadores del estilo "casa" o alguna otra cosa. En cuanto a los lúmenes, sólo hay que realizar una lectura analógica siguiendo esta librería. El código final es el siguiente:

/*
 * Este programa es una estación meteorológica que verifica los niveles de 
 * temperatura y humedad del ambiente con el sensor DTH11. Se alimenta con 
 * una celda fotovoltáica, y posee un cargador de baterías y alimentación 
 * para el equipo.
 */


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//---------------------------------------------------------------------------

#include "DHT.h"

#define DHTPIN            5         // Pin de datos
#define DHTTYPE           DHT11     // DHT 11

// El tercer parámetro va en función de la velocidad
// del microprocesador, cuanto más rápido sea, más 
// grande el valor (6 es para un micro de 16Mhz).

DHT dht(DHTPIN, DHTTYPE, 11);

//---------------------------------------------------------------------------

// verificar el ejemplo de la librería para saber como 
//conectar la resistencia.
// quizá lo mejor sea poner una resistencia de 10k.
#include <LightDependentResistor.h>

#define OTHER_RESISTOR 3300 //ohms
#define USED_PIN A0
#define USED_PHOTOCELL LightDependentResistor::GL5528

// Create a GL5528 photocell instance (on A0 pin)
LightDependentResistor photocell(USED_PIN, OTHER_RESISTOR, USED_PHOTOCELL);

//---------------------------------------------------------------------------

// Las siguientes tres constantes definen, nombre
// de red wifi y su contraseña.

const char* ssid = "NombreRed";
const char* password = "Contraseña";
const char* mqtt_server = "DirecciónServidor";

// Acá definimos los pines.

const int d1 = 5, d2 = 4, d3 = 0, pin_led = 2;

long tiempo = 0;

// A continuación declaramos el nombre del cliente 
// que se va a conectar.

WiFiClient espClient;
PubSubClient client(espClient);

// En esta variable se almacena el mensaje recibido
// notar que tiene un máximo de 50 (en realidad son
// 49) caracteres.

char msg[50];

void setup() {
  pinMode(pin_led, OUTPUT);   //Pin del LED 2
  digitalWrite(pin_led, LOW);
  pinMode(d1, INPUT);         //Pin D1
  pinMode(d2, INPUT);         //Pin D2
  pinMode(d3, INPUT);         //Pin D3
  
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  dht.begin();
}

void setup_wifi() {

    Serial.println();
    Serial.print("Conectando a: ");
    Serial.println(ssid);
  
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }
  
    digitalWrite(pin_led, HIGH);
  
    Serial.println("");
    Serial.println("WiFi conectado");
    Serial.println("IP: ");
    Serial.println(WiFi.localIP());

}

// En esta función se administra la llegada de 
// mensajes, nos avisa en qué tópico llegó y 
// cuál es el mensaje.

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");

  if ((char)payload[0] == 'O') {  // si recibo como primer caracter una O
    if ((char)payload[1] == 'N'){  // si recibo como segundo caracter una N
      Serial.println("El boton esta apagado"); 
      digitalWrite(pin_led, LOW);
    } 
    else {
      Serial.println("El boton esta encendido");  
      digitalWrite(pin_led, HIGH);
    }
  }
}

// Esta función se encarga de conectar con el 
// mqtt broker, si lo consigue se subscribe a
// los tópicos que definamos (no es necesario
// subscribirnos en esta función, pero si lo
// recomiendo para organizar mejor el código.
// Prueba reconectarse cada cinco segundos si
// no lo consigue.

void reconnect() {
  // Loop hasta lograr la conexión
  while (!client.connected()) {
    Serial.print("Intentando conectar al servicio MQTT...");
    
    if (client.connect("ESP8266Client")) {
      Serial.println("Conectado!");
      client.publish("temperatura", "0");    //envío dato
      client.publish("humedad", "0");    //envío dato
    } 
    else 
    {
      Serial.print("Fallo, Resultado=");
      Serial.print(client.state());
      Serial.println("Intetando nuevamente en 5 segundos");
      delay(5000);
    }
  }
}

// En el loop principal no hacemos nada más 
// que verificar si perdimos la conexión con
// el servicio mqtt, que lleguen mensajes y
// actualizamos la temperatura y humedad. 
// El "client.loop();" se encarga de revisar 
// si llegaron mensajes, por lo que habría
// que invocar esta función regularmente.

void loop() {

  if (WiFi.status() != WL_CONNECTED)
  {
    setup_wifi();
  }
  if (!client.connected()) 
  {
    reconnect();
  }
  
  //-------------------------------------------------------
  if ((millis() - tiempo) > 2500)
  {
    tiempo = millis();
    float humedad = dht.readHumidity();
    float temperatura = dht.readTemperature();
    float lux = photocell.getCurrentLux();
    client.publish("estacion/datos", (String(temperatura) + "&&&" + String(humedad) + "&&&" + String(lux)).c_str(),true);
    Serial.print(temperatura);
    Serial.print(" ");
    Serial.print(humedad);
    Serial.print(" ");
    Serial.println(lux);
  }
  //-------------------------------------------------------
}


De esta forma sólo obtenemos los valores sin promediar (lo cual significa que hay muchísimos más datos que de otra forma) por lo que si no disponemos de mucha memoria ram (como es en el caso de la raspberry pi) habría que realizar un promedio cada cierta cantidad de horas, como es el caso de la gráfica de valores históricos.

De esta forma podemos mostrar los valores históricos de los tres sensores (con lo cuál se podrían hacer análisis de las variaciones de temperatura, humedad y luz a lo largo de un año).

A continuación les dejo el código del flujo de la nueva estación meteorológica (sin los valores promedio):

https://mega.nz/#!7kIjGCqB!4Mvq78SucQepGiCdXp9osuNRZIeh3hODLgFcOVFkybk

Acá les dejo el código del flujo de la parte que maneja los valores históricos (con promedio):

https://mega.nz/#!7pRzkQAQ!GKUfib8z-Z7judA3EvsLSXDgjk5Gse-wYoIhKtz5-II

El nuevo código para el micro lo tienen arriba así que no lo subo a mega.

domingo, 2 de julio de 2017

Cómo mantener las gráficas en node-red

Hoy les voy a explicar, como indica el título, cómo mantener las gráficas en node-red incluso si éste se detiene o se corta la luz.

Si realizaron la estación meteorológica simple (la versión que les dejé en el link de mega) quizá les pasó que las gráficas históricas se perdieron si se desconectaba el servidor o si detenían los servicios (hay algunos casos más en los que se pueden perder los datos, pero no los voy a mencionar porque el resultado siempre es el mismo, la pérdida de los datos), sin lugar a dudas a mi me pasó varias veces y tenía que mantener el servidor funcionando 24/7 si no quería perder esos datos, lo que hacía que la raspberry pi se me tildase o funcionase erráticamente luego de estar encendida por un par de meses (no me ejecutaba las funciones correctamente por lo que no filtraba los datos que se mostraban). Luego del último corte de luz me puse a pensar en cómo corregir eso, y decidí guardar los datos en un archivo, simplemente conectando los nodos de la siguiente forma


Así no perdía los datos, pero seguía sin poder mostrarlos nuevamente, revisando los datos que se guardaban, quedaba un objeto como el siguiente:

[{"key":"Series 1","values":[[1492920133027,32],[1492920135027, 33]...]}]

Si analizamos este objeto nos quedan las propiedades "Key" que guarda el valor "Series 1" y "values" que es un array de arrays (o un array de dos dimensiones) que contiene los milisegundos desde el año 1970 y la temperatura (o la humedad, si analizamos el otro archivo) correspondiente a esa fecha exacta.
Mi primera prueba fue crear una función que devuelva un objeto similar y mandarlo directo al graficador, pero no sirvió (lo más probable es que haya echo algo mal dado que no tengo experiencia trabajando con objetos), por lo que probé mandar el mismo objeto que guardo de la siguiente forma


Cuando presionaba el botón que inyecta el "timestamp" debería mandar los datos del archivo, de más está decir que esto no funciona porque lo que se guarda dentro del archivo es procesado como texto plano y no como un objeto, pero esto se resuelve poniendo el nodo json de la siguiente forma

Este nodo lo que hace es tomar el  texto plano y lo transforma en lo que es (en este caso un objeto). Esto sí es tomado de forma correcta por el nodo "chart" y nos muestra los datos subidos, entonces ahora nos faltaría hacer que se guarde en ese mismo archivo y la solución que se me ocurrió es la siguiente (sé que el tamaño de la imágen es bastante chico)


Cada tres horas mando el promedio de la humedad (en este caso) al nodo "chart" el cual me devuelve todos los puntos graficados, en la función siguiente verifico si lo que me manda está vacío, si lo está no devuelve nada y si no lo está guarda en el archivo todos los datos. Cada vez que se enciende el servidor el nodo "inject" manda una señal que hace que se lea el archivo donde se guardan los datos, estos se convierten a objeto y se mandan al nodo "chart" que los grafica.
Esta solución sigue teniendo el problema de que se muestra el último año de datos, y luego se van a ir descartando los datos más antiguos al año, por lo que no podríamos almacenar más que eso (si modificamos cuántos días queremos mostrar en el pasado podríamos hacer que se muestre, pero como el espacio para graficar es reducido llegaría un punto en el cuál no se podría apreciar ningún detalle).
La solución a esto podría ser crear un archivo por año y que se muestren todos los datos del año actual (del primero de enero al 31 de diciembre), y esto se podría implementar en la última función (la que está a la salida de la gráfica). Vamos a obtener el año actual y lo vamos a usar como nombre del archivo (o al menos como parte del nombre del archivo) y luego le vamos a pasar el nombre del archivo al nodo que guarda los datos para que los guarde en dicho archivo o cree el archivo si el mismo no existe. Un ejemplo de esto sería lo siguiente, los nodos función obtienen el año, le agregan la ruta y pasan ese string como nombre de archivo, el nodo que maneja archivos crea el archivo y guarda el dato, si ya está creado solo guarda el dato, el otro nodo de manejo de archivos sólo lo abre y lo muestra por consola.

El resultado final nos quedaría algo similar a la imágen anterior, pero con un nodo de función extra, deberíamos crear los archivos iniciales por como está planteado el sistema.

Acá les dejo el código de la versión actualizada de la estación meteorológica para que puedan importar y ver el código, o la configuración, de cada nodo. Vale aclarar que el sistema de archivos que estoy usando es el de linux que es el sistema operativo recomendado para la raspberry pi 3, si tienen montado este servidor en windows hay que cambiar la ruta de los archivos.

https://mega.nz/#!W5g1UBII!Xwh1HVaIYwi6lRhlVImE--tZM8qVIy2kR73KcwNCgDM

domingo, 25 de junio de 2017

Estación meteorológica simple

En esta ocasión les traigo una forma de hacer una estación meteorológica simple con node-red, mqtt, esp8266, un dth11 y una raspberry pi 3 haciendo las veces de servidor. La idea es dejar este equipo en el exterior y que se comunique con el servidor a través de la red wifi, y que a través de un servicio web podamos consultar los datos actuales y atrás en el tiempo.

Primero y principal deberíamos tener los componentes mínimos para montar el sistema, por lo que vamos a necesitar un par de cargadores de celular (para alimentación de las dos placas), una vez realizado esto tendríamos que establecer una conexión vnc, que lo vamos a conseguir ingresando al terminal (de la raspberry pi 3) y ponemos los siguientes comandos:

sudo apt-get update

sudo apt-get install realvnc-vnc-server realvnc-vnc-viewer

esto nos va a instalar el real vnc, una vez puesto todo eso vamos a descargar el vnc viewer y a instalarlo. una vez echo esto vamos a conectarnos (es posible que haya que configurar una contraseña además de darle permiso desde la rbpi 3, no pongo todos los pasos por acá porque se va a hacer muy largo el post y esto tampoco es tan necesario para tener andando todo, directamente se podría realizar desde la rbpi 3 y dejarlo andando sin problemas, pero me resulta más práctico tener acceso a la computadora de forma remota) a la dirección que nos indique en la rbpi3. Esto nos va a "simular" lo que aparecería por pantalla de la computadora, y debería ser algo como lo siguiente:


Luego deberíamos bajar el mqtt broker mosca en la rbpi 3, para poder crear el servicio. Para ello abriremos el terminal e ingresar el siguiente comando (quizá sea bastante molesto, pero poner la palabra "sudo" antes de cualquier comando, le da atributos root y nos evita perder el tiempo, aunque hay que tener cuidado porque justamente estamos ejecutando cosas como root):

sudo npm install mosca bunyan -g

y debería aparecer lo siguiente:



El proceso de instalación demora bastante, sobre todo si la tarjeta SD sobre la cual montamos el SO es medio lenta o si están ejecutando otras cosas como el navegador.

Una vez terminado el proceso de instalación, solo hay que iniciar el servidor mqtt con el comando:

mosca -v | bunyan

y debería iniciar de la siguiente forma:


Hay que recordar que también hay que iniciar el node-red para este proyecto. Una vez todo configurado vamos a abrir en nuestro navegador el node-red (con la ip de la rbpi 3) y vamos a colocar los siguientes nodos:

El código para estos nodos lo dejo al final del post.
Le damos "deploy" y ya deberíamos tener esa parte lista, si queremos guardar los dato o si queremos graficar más tiempo solo tenemos que cambiar las bases de las gráficas. Si nos vamos a la página del node-red (que es agregando a la dirección que termina en 1880, /ui) tendremos lo siguiente:


Ahora vamos a arrancar con la parte del sensor (dht11) y el esp8266. Los componentes que estoy usando son los de las fotos (sé que no queda bien usar el flash, pero se veía tan poco que decidí cometer el pecado):

 

Los tengo conectados con un cable que me vino con mi modelo del esp.
El cable no era el ideal, porque tenía la separación de los pines muy
corta y los cables no me coincidían con el sensor, pero lo invertí y
"forcé" los pines del dht para que todo quedase bien (creo).
Según mi placa (el modelo es "crowtail- ESP8266 NodeMCU") lo tengo conectado sobre el pin "D1" que según la web es el GPIO5, por lo que si ustedes tienen otra placa deberían corroborar cuál es el pin adecuado.

El código que le cargué es el siguiente:



/*
 * Este programa es una estación meteorológica que verifica los niveles de 
 * temperatura y humedad del ambiente con el sensor DTH11. Se alimenta con 
 * una celda fotovoltáica, y posee un cargador de baterías y alimentación 
 * para el equipo.
 */


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//---------------------------------------------------------------------------

#include "DHT.h"

#define DHTPIN            5         // Pin de datos
#define DHTTYPE           DHT11     // DHT 11

// El tercer parámetro va en función de la velocidad
// del microprocesador, cuanto más rápido sea, más 
// grande el valor (6 es para un micro de 16Mhz).

DHT dht(DHTPIN, DHTTYPE, 11);

//---------------------------------------------------------------------------

// Las siguientes tres constantes definen, nombre
// de red wifi y su contraseña.

const char* ssid = "Fibertel WiFi999";
const char* password = "0043546735";
const char* mqtt_server = "192.168.1.23";

// Acá definimos los pines.

const int d1 = 5, d2 = 4, d3 = 0, pin_led = 2;

long tiempo = 0;

// A continuación declaramos el nombre del cliente 
// que se va a conectar.

WiFiClient espClient;
PubSubClient client(espClient);

// En esta variable se almacena el mensaje recibido
// notar que tiene un máximo de 50 (en realidad son
// 49) caracteres.

char msg[50];

void setup() {
  pinMode(pin_led, OUTPUT);   //Pin del LED 2
  digitalWrite(pin_led, LOW);
  pinMode(d1, INPUT);         //Pin D1
  pinMode(d2, INPUT);         //Pin D2
  pinMode(d3, INPUT);         //Pin D3
  
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  dht.begin();
}

void setup_wifi() {

    Serial.println();
    Serial.print("Conectando a: ");
    Serial.println(ssid);
  
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }
  
    digitalWrite(pin_led, HIGH);
  
    Serial.println("");
    Serial.println("WiFi conectado");
    Serial.println("IP: ");
    Serial.println(WiFi.localIP());

}

// En esta función se administra la llegada de 
// mensajes, nos avisa en qué tópico llegó y 
// cuál es el mensaje.

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");

  if ((char)payload[0] == 'O') {  // si recibo como primer caracter una O
    if ((char)payload[1] == 'N'){  // si recibo como segundo caracter una N
      Serial.println("El boton esta apagado"); 
      digitalWrite(pin_led, LOW);
    } 
    else {
      Serial.println("El boton esta encendido");  
      digitalWrite(pin_led, HIGH);
    }
  }

}

// Esta función se encarga de conectar con el 
// mqtt broker, si lo consigue se subscribe a
// los tópicos que definamos (no es necesario
// subscribirnos en esta función, pero si lo
// recomiendo para organizar mejor el código.
// Prueba reconectarse cada cinco segundos si
// no lo consigue.

void reconnect() {
  // Loop hasta lograr la conexión
  while (!client.connected()) {
    Serial.print("Intentando conectar al servicio MQTT...");
    
    if (client.connect("ESP8266Client")) {
      Serial.println("Conectado!");
      client.publish("temperatura", "0");    //envío dato
      client.publish("humedad", "0");    //envío dato
    } 
    else 
    {
      Serial.print("Fallo, Resultado=");
      Serial.print(client.state());
      Serial.println("Intetando nuevamente en 5 segundos");
      delay(5000);
    }
  }
}

// En el loop principal no hacemos nada más 
// que verificar si perdimos la conexión con
// el servicio mqtt, que lleguen mensajes y
// actualizamos la temperatura y humedad. 
// El "client.loop();" se encarga de revisar 
// si llegaron mensajes, por lo que habría
// que invocar esta función regularmente.

void loop() {

  if (WiFi.status() != WL_CONNECTED)
  {
    setup_wifi();
  }
  if (!client.connected()) 
  {
    reconnect();
  }
  
  //-------------------------------------------------------
  if ((millis() - tiempo) > 2000)
  {
    tiempo = millis();
    float humedad = dht.readHumidity();
    float temperatura = dht.readTemperature();
    client.publish("temperatura", String(temperatura).c_str(),true);
    delay(250);
    client.publish("humedad", String(humedad).c_str(),true);
    delay(250);
    Serial.print(temperatura);
    Serial.print(" ");
    Serial.println(humedad);
  }

  //-------------------------------------------------------
}


Bueno, el resultado final va a ser similar al siguiente (mi sensor no anda del todo bien y me tira picos de 66º C, pero por suerte eso no pasa jaja)

Acá les dejo el código fuente del programa del node-red (recuerden modificar las direcciones ip para que se ajusten a su red, aunque si está todo montado de forma local, poniendo localhost debería bastar) para que puedan importarlo a sus servidores (con algunos extra):

domingo, 18 de junio de 2017

Raspberry pi 3

Como ya me pasó varias veces, finalmente incurrí en una nueva (al menos para mi) tecnología a la que le tenía rechazo. Esta vez les traigo una placa muy interesante, la raspberry pi 3, esta placa cuenta con pines de uso general, y tiene la posibilidad (que es lo mas recomendable) de instalarle un sistema operativo Linux (o incluso Windows IOT) ademas de que podremos elegir entre varias distros, lo cual lo hace una plataforma muy flexible. El OS recomendado (que por lo general suelen ser los mejores) es el Linux raspbian que está basado en debian.

  1. Primero que nada, para instalar el os, debemos contar con una memoria micro sd de 8gb como mínimo.
  2. Segundo, vamos a la siguiente página: https://www.raspberrypi.org/downloads/noobs/ y bajamos el noobs (hacemos click donde dice download zip)
  3. Descomprimimos el archivo y guardamos todas las cosas en la memoria micro sd (son varios archivos, por lo que si solo aparece una carpeta la vamos a abrir para encontrar todos los archivos).
  4. Insertamos la memoria en su ranura correspondiente de la raspberry pi, conectamos el monitor, conectamos mouse y teclado (admite un mouse y teclado inalámbricos) y energizamos la placa.
  5. Nos va a aparecer una ventana de instalación, que si seguimos los pasos correctamente no deberíamos tener ningún problema. El SO raspbian no hace falta descargarlo, pero si queremos otro SO (en el menú de instalación se puede elegir entre varios SO) vamos a tener que contar con una conexión a internet (ya sea por wifi o por ethernet) para bajarlo.
Una vez instalado el raspbian (si este fue el so que elegimos) la raspberry pi 3 puede ser usada como servidor, y una de las cosas que más me interesa es que soporta el node-red. Si bien la versión que viene por defecto con la distro debian (si, ya tiene el node-red instalado) está desactualizada, se puede actualizar ingresando por consola el siguiente comando:

update-nodejs-and-nodered

Si luego ejecutamos el comando node-red (para iniciar el servidor) vamos a contar con la versión para la raspberry pi, que viene con un nodo para verificar el estado de los pines (dicho con otras palabras, desde el node-red tendremos acceso a los pines gpio).

Conclusión: Esta plataforma (al igual que la beaglebone balck) es muy completa y tiene casi todo lo necesario para desarrollar sistemas robustos que necesiten de un sistema operativo y pines de propósito general.

domingo, 4 de junio de 2017

ESP8266 + Node-Red + MQTT broker

Bueno, ahora que ya tenemos los conocimientos básicos sobre el MQTT, node-red, el módulo ESP8266 y ya usamos el ESP8266 más un MQTT broker podremos integrar todo para obtener un sistema bastante completo y de cierta complejidad (de forma sencilla).

Primero que nada vamos a iniciar los servicios de node-red y mosca. Una vez que se inicien, vamos a la ip local 127.0.0.1:1880 y ahí deberíamos configurar los siguientes módulos:

  1. Text imput: configurado para que aparezca en el default del dashboard y con un Delay (ms) en 0 para que espere a que se presione el enter para mandar.
  2. MQTT: configurado con la ip donde se aloja el mqtt broker y con el tópico mensajes.
Y debería quedar como muestra la siguiente imágen:


Y si nos vamos a la dirección 127.0.0.1:1880/ui deberíamos encontrarnos con el dashboard de esta forma.


En donde dice escribir acá podremos ingresar un mensaje que se va a mandar a través del mqtt broker, de esta forma si accedemos a la dirección ip de nuestra pc desde el celular (el navegador) podremos mandar mensajes sin necesidad de ninguna aplicación.

Ahora si vamos a arduino y cargamos el siguiente código (que es el mismo que la última vez) y lo cargamos en nuestra ESP8266 deberíamos poder recibir por el puerto serie el mensaje que mandemos desde la interfaz web:


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Las siguientes tres constantes definen, ip del 
//mqtt broker, nombre de red wifi y su contraseña.

const char* mqtt_server = "192.168.1.15";
const char* ssid = "id_red_wifi";
const char* password = "contraseña_red_wifi";

// A continuación declaramos el nombre del cliente 
// que se va a conectar.
WiFiClient espClient;
PubSubClient client(espClient);

// En esta variable se almacena el mensaje recibido
// notar que tiene un máximo de 50 (en realidad son
// 49) caracteres.
char msg[50];

// Iniciamos la comunicación serie, la conexión por
// wifi y definimos en donde se aloja el servidor y
// en qué puerto, y la función donde administramos
// la llegada de mensajes.
void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

// En esta función se conecta con la red designada,
// mientras esté tratando de conectarse va a mandar
// un punto "." por el puerto serie y cuando lo 
// consiga nos avisará.
void setup_wifi() {

  delay(10);

  Serial.println();
  Serial.print("Conectando a: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi conectado");
  Serial.println("Direccion IP: ");
  Serial.println(WiFi.localIP());
}

// En esta función se administra la llegada de 
// mensajes, nos avisa en qué tópico llegó y 
// cuál es el mensaje.
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

// Esta función se encarga de conectar con el 
// mqtt broker, si lo consigue se subscribe a
// los tópicos que definamos (no es necesario
// subscribirnos en esta función, pero si lo
// recomiendo para organizar mejor el código.
// Prueba reconectarse cada cinco segundos si
// no lo consigue.
void reconectar() {

  while (!client.connected()) {
    Serial.print("Intentando conectar con el mqtt broker...");

    if (client.connect("ESP8266Client")) {
      Serial.println("conectado");
      client.subscribe("mensajes");
    } else {
      Serial.print("fallo, rc=");
      Serial.print(client.state());
      Serial.println(" prueba nuevamente en 5 segundos");

      delay(5000);
    }
  }
}

// En el loop principal no hacemos nada más 
// que verificar si perdimos la conexión con
// el servicio mqtt y verificamos que lleguen
// mensajes. El "client.loop();" se encarga 
// de revisar si llegaron mensajes, por lo 
// que habría que invocar esta función regu-
// larmente.
// Esta sección se podría mejorar si ponemos
// que revise si perdió la conexión con la
// red wifi.
void loop() {

  if (!client.connected()) {
    reconectar();
  }
  client.loop();
}

Si agregamos al código algo que "analice" el mensaje entrante podremos hacer algún programa que "reaccione" ante ciertos mensajes en específico.