Taller IoT con NodeRED y ESP8266

ESP8266: El Arduino con WiFi

ESP8266: El Arduino con WiFi

1. Instalación del entorno de programación

Arduino es una plataforma de hardware libre y de código abierto que se utiliza para desarrollar proyectos electrónicos interactivos. Para empezar a programar con Arduino, necesitas instalar su entorno de programación en tu ordenador.

A continuación, te explicamos los pasos para instalar el entorno de programación de Arduino:

Descarga el software de Arduino desde su sitio web oficial: https://www.arduino.cc/en/software

image-1682416823209.png

Descargaremos la versión 2 del software que corresponda con tu sistema operativo. Recomendable que sea la instalación

image-1682417013662.png

Si quieres puedes colaborar en el desarollo del proyecto o descargar directamente. 

image-1682417220555.png

Abre el archivo descargado y sigue las instrucciones de instalación. El proceso es muy sencillo y solo tienes que seguir los pasos que te indica el instalador.

Una vez finalizada la instalación, abre el entorno de programación de Arduino. Verás una pantalla en blanco con algunas opciones en la barra de herramientas.

image-1682418701953.png

Ahora vamos a instalar el núcleo de librerias para poder utilizar el ESP8266 con el entorno de programación de Arduino. 

En tu Arduino IDE, ve a Archivo > Preferencias.

Ingrese http://arduino.esp8266.com/stable/package_esp8266com_index.json en el campo "URLs adicionales de gestor de placas:" como se muestra en la figura a continuación. Luego, haga clic en el botón "Aceptar":

image-1682419841360.png

Ahora, en tu Arduino IDE, ve a Herramientas > Placas > Gestor de Placas. Y en el filtro escribe esp y haga clic en el botón "Instalar" en la placa esp8266 como aparece en la imagen.

image-1682419963692.png

Para probar que hemos instalado correctamente la placa y ver un ejemplo de código de programación. Vamos en tu Arduino IDE, ve a Archivo > Ejemplos > 01.Basics > Blink. Y se abrirá la ventana con código escrito del ejemplo.

El código para el ejemplo de Blink es muy simple y consta de dos funciones: setup() y loop(). En la función setup() se configura el pin del Arduino que se va a utilizar para conectar el LED y se establece como salida. En la función loop() se hace que el LED parpadee encendiéndolo durante un tiempo determinado y luego apagándolo durante otro tiempo determinado.

Para subirlo, pulsaremos la flecha y nos pedirá que seleccionemos una placa, en este caso utilizaremos para el taller LOLIN(WEMOS) D1 R2 & mini. Si te aparecen más puertos y no sabes muy bien cuál de ellos seleccionar, un truco es desconectar y conectar la placa, y ver que nuevo puerto aparece.

image-1682420262244.png

Por último, subimos el código y vemos el resultado.

 

 

ESP8266: El Arduino con WiFi

2. Instalación de una librería en el entorno de programación

¿Que es una librería de codigo?

Una librería de código, también conocida como biblioteca o framework, es un conjunto de funciones, clases y/o módulos que se pueden utilizar para facilitar la programación de una aplicación o sistema. Estas librerías pueden estar escritas en diferentes lenguajes de programación y se utilizan para realizar tareas comunes de programación, como el procesamiento de datos, la gestión de redes, la creación de interfaces gráficas de usuario, entre otras.

Las librerías de código son una herramienta importante para los desarrolladores, ya que les permiten reutilizar código ya existente y ahorrar tiempo en la creación de nuevas aplicaciones. Además, las librerías de código también pueden mejorar la calidad del software al proporcionar funciones ya probadas y optimizadas por otros desarrolladores.

¿Como la instalo?

Abrimos el entorno de programación y vamos a Skecth > Incluir biblioteca > Gestionar bibliotecas

install_lib.png

En el lateral se abrirá un nuevo menu en el cuál podremos buscar la libreria que nos interese, en este caso os invitamos a instalar la libreria para el uso del sensor DHT11, un sensor que nos permite medir temperatura y humedad.

install_lib_2.png

En este caso os sugerimos instalar la siguiente DHT sensor library de Adafruit,pulsamos INSTALAR, si aparece un menu como el siguiente INSTALAR TODO, ya que quizás la librería por bajo necesita de otras más principales para funcionar.

install_lib_3.png

¿Como elegir una libreria?

Elegir una librería adecuada puede ser una tarea importante en el desarrollo de una aplicación. A continuación, se presentan algunos consejos para seleccionar la librería adecuada:

  1. Identifica tus necesidades: Antes de buscar una librería, es importante tener claro qué funcionalidades necesitas en tu aplicación. De esta manera, podrás buscar una librería que ofrezca exactamente lo que necesitas.

  2. Investiga las opciones disponibles: Hay muchas librerías disponibles en línea, por lo que es importante investigar y comparar diferentes opciones. Revisa documentación, ejemplos de uso, popularidad y estabilidad.

  3. Comprueba la compatibilidad: Es importante asegurarte de que la librería sea compatible con tu sistema operativo, lenguaje de programación y otros elementos que se estén utilizando en tu proyecto.

  4. Revisa la comunidad y soporte: Una comunidad activa y un soporte adecuado pueden ser clave para resolver problemas en el futuro, asegúrate de que la librería elegida tenga una comunidad activa y actualizaciones recientes.

  5. Evalúa el rendimiento: La velocidad y la eficiencia son importantes en cualquier aplicación, así que es recomendable evaluar el rendimiento de la librería antes de integrarla en tu proyecto.

  6. Considera el coste: Algunas librerías pueden tener costos asociados, como licencias o suscripciones. Asegúrate de considerar los costos y beneficios antes de tomar una decisión.

  7. Prueba la librería: Antes de integrar la librería en tu proyecto, es recomendable hacer una prueba en un ambiente de pruebas para verificar que cumpla con tus expectativas y necesidades.

Ten en cuenta que la elección de una librería dependerá de las necesidades específicas de tu proyecto, por lo que es importante evaluar cada opción en función de sus características y ventajas.

ESP8266: El Arduino con WiFi

3. Montaje del circuito de sensores para el ESP8266, con dos LEDS, un sensor de temperatura y humedad, y un sensor fotorresistivo (LDR)

¿Como conectar un led a un esp8266? ¿Porque lleva una resistencia?

Para conectar un LED a un ESP8266, es necesario conectar el ánodo (patita más larga) del LED a uno de los pines de salida digital del ESP8266, y el cátodo (patita más corta) a través de una resistencia de limitación de corriente a la tierra (GND).

La resistencia de limitación de corriente es necesaria para evitar que el LED reciba más corriente de la que puede soportar, lo que puede dañar el LED o el ESP8266. La resistencia limita la corriente que fluye a través del LED, asegurándose de que la corriente esté dentro de los límites seguros. La resistencia que se utiliza dependerá del tipo de LED y del voltaje de alimentación utilizado, y se puede calcular utilizando la ley de Ohm.

Por ejemplo, si se utiliza un LED con una caída de voltaje de 2V y una corriente máxima de 20mA, y el voltaje de alimentación es de 3.3V, la resistencia de limitación de corriente necesaria sería de aproximadamente (3.3V - 2V) / 0.02A = 65 ohmios. Sin embargo, como los valores comerciales de resistencia no son exactos, se puede utilizar una resistencia comercial estándar de 68 ohmios, por ejemplo. Normalmente, utilizando una resistencia de 220 o 330 ohmios suele funcionar.

En resumen, para conectar un LED a un ESP8266 se debe conectar el ánodo del LED a un pin de salida digital, el cátodo a través de una resistencia de limitación de corriente a tierra, y elegir una resistencia adecuada para limitar la corriente que fluye a través del LED.

¿Como conectar un LDR a un esp8266? ¿Como leo su valor?

Para conectar un LDR (resistencia dependiente de la luz) a un ESP8266, primero se debe conectar uno de los terminales del LDR a un pin analógico del ESP8266, y el otro terminal del LDR a una fuente de voltaje, como el pin de 3.3V o 5V del ESP8266. Además, hay que colocar una resistencia en serie con el terminal del LDR conectado al pin analógico y otro pin de la resistencia conectado a toma de tierra GND. El valor dependerá de la resistencia del LDR, se suele utilizar el mismo valor que el proporcionado por el LDR, por ejemplo, 10K ohmios. (Concepto de divisor resistivo)

Una vez que se ha conectado el LDR al ESP8266, se puede leer su valor utilizando una de las entradas analógicas del ESP8266. El ESP8266 tiene un ADC (A0) (conversor analógico a digital) integrado que puede medir la tensión en el pin analógico. La lectura del ADC se puede realizar utilizando la función analogRead() en el código del ESP8266. Esta función devuelve un valor entero entre 0 y 1023, que representa la tensión medida en el pin analógico.

Para leer el valor del LDR, es necesario realizar una lectura analógica utilizando analogRead() y luego convertir ese valor en una medida de la luminosidad. La relación entre la resistencia del LDR y la luminosidad no es lineal, por lo que se debe calibrar la lectura del LDR para obtener una medida precisa de la luminosidad. La calibración se puede realizar midiendo el valor del LDR en diferentes condiciones de iluminación y ajustando una fórmula que convierta la lectura del LDR en una medida de la luminosidad en unidades apropiadas (por ejemplo, lux).

¿Como conecto el modulo DHT11?

Para conectar un módulo DHT11 al ESP8266, se deben seguir los siguientes pasos:

  1. Conectar el pin VCC del módulo DHT11 al pin de 3.3V o 5V del ESP8266.
  2. Conectar el pin GND del módulo DHT11 al pin GND del ESP8266.
  3. Conectar el pin DATA del módulo DHT11 al pin GPIO del ESP8266 (puede ser cualquier pin GPIO disponible).

Una vez conectado el módulo DHT11 al ESP8266, se puede leer la temperatura y la humedad utilizando una biblioteca específica para el DHT11. El módulo DHT11 utiliza el protocolo OneWire para transmitir los datos de temperatura y humedad a través de un solo pin de datos. El módulo tiene un chip interno que convierte la información de los sensores en una señal digital, que luego es transmitida a través del pin de datos utilizando el protocolo OneWire.

El protocolo OneWire es un protocolo de comunicación serial que permite la transferencia de datos a través de un solo cable. Es utilizado en una variedad de dispositivos electrónicos, incluyendo sensores de temperatura y humedad como el DHT11.

El protocolo OneWire funciona mediante la transmisión de pulsos de voltaje a través del pin de datos. La transmisión de datos se inicia con una señal de inicio enviada por el dispositivo maestro (en este caso, el ESP8266). Luego, el dispositivo esclavo (el DHT11) responde con una señal de presencia para indicar que está listo para recibir los datos. A continuación, el dispositivo maestro envía una serie de pulsos de sincronización y datos, y el dispositivo esclavo responde con un bit de confirmación después de cada dato recibido.

ESP8266_MQTT_SCHEMATIC_TALLER.png

¿Como funciona un divisor resistivo?

Un divisor resistivo es un circuito formado por dos resistencias conectadas en serie entre una fuente de voltaje y tierra (GND). La tensión de salida se toma de la conexión entre las dos resistencias.

El principio de funcionamiento del divisor resistivo se basa en la ley de Ohm, que establece que la corriente que fluye a través de una resistencia es proporcional a la diferencia de potencial (voltaje) entre los extremos de la resistencia. En un divisor resistivo, la corriente que fluye a través de ambas resistencias es la misma, ya que están conectadas en serie. Por lo tanto, la tensión en cada resistencia es proporcional a su resistencia.

Resistive_divider.png

La tensión de salida del divisor resistivo se calcula como la tensión en la resistencia de salida (la que está conectada al pin de salida) en relación con la tensión total en el circuito. Esto se puede expresar matemáticamente como:

Vout = Vin * R2 / (R1 + R2)

Donde Vin es la tensión de entrada, R1 es la resistencia conectada al pin de entrada, R2 es la resistencia conectada al pin de salida, y Vout es la tensión de salida.

En resumen, un divisor resistivo funciona al dividir la tensión de entrada en dos partes, proporcionalmente a las resistencias utilizadas. La tensión de salida se toma de la conexión entre las dos resistencias y se puede calcular utilizando la fórmula mencionada anteriormente.

ESP8266: El Arduino con WiFi

4. Testeando los sensores y LEDs

¿Como leer un sensor analógico?

Para leer un sensor analógico con Arduino, debes seguir los siguientes pasos:

  1. Conectar el sensor: Conecta el sensor analógico a un pin analógico en la placa Arduino. Asegúrate de que los pines del sensor estén conectados correctamente al pin analógico de la placa. Además, algunos sensores pueden requerir una conexión adicional de VCC y GND.

  2. Leer el valor: Se utiliza la función analogRead() para leer el valor del pin analógico. Esta función devuelve un valor entre 0 y 1023 que representa el voltaje en el pin. El valor 0 representa 0 voltios, mientras que el valor 1023 representa la referencia de voltaje de la placa, que en ESP8266 es de 3.3V.

  3. Convertir el valor: A veces, el valor devuelto por la función analogRead() no es el valor que se necesita para el cálculo. Por ejemplo, algunos sensores pueden requerir una conversión de voltaje a temperatura. En este caso, se puede usar una ecuación de conversión para convertir el valor leído a la unidad de medida necesaria.

Aquí hay un ejemplo de código para leer un sensor analógico conectado al pin A0:

int sensorValue = 0; // Variable para almacenar el valor del sensor

void setup() {
  Serial.begin(115200); // Inicia la comunicación serial a una velocidad de 115200 baudios
}

void loop() {
  sensorValue = analogRead(A0); // Lee el valor del sensor en el pin A0
  Serial.println(sensorValue);  // Imprime el valor en el monitor serial
  delay(100);                  // Espera un tiempo para evitar la sobrecarga del puerto serie
}

En este ejemplo, la función analogRead() se usa para leer el valor del pin A0 y luego se imprime en el monitor serial. El comando delay() se utiliza para esperar un tiempo antes de leer el valor del sensor de nuevo y enviarlo al monitor serial para evitar la sobrecarga del puerto serial.

¿Como encender un led con Arduino?

Para encender un LED con Arduino, sigue los siguientes pasos:

  1. Conecta un extremo de la resistencia a un pin digital del Arduino y el otro extremo a la protoboard.
  2. Conecta el cátodo (pata más corta) del LED a la misma fila de la protoboard en la que conectaste la resistencia.
  3. Conecta el ánodo (pata más larga) del LED a otra fila de la protoboard.
  4. Conecta un cable desde la fila de la protoboard donde está el ánodo del LED a una fuente de voltaje (por ejemplo, 3.3V).
  5. Conecta un cable desde la fila de la protoboard donde está la resistencia a un pin GND del Arduino.
  6. En el código de Arduino, usa la función pinMode para establecer el pin digital donde conectaste la resistencia como una salida: pinMode(PIN, OUTPUT);.
  7. En el código de Arduino, usa la función digitalWrite para establecer el estado del pin digital donde conectaste la resistencia a HIGH o LOW para encender o apagar el LED, respectivamente: digitalWrite(PIN, HIGH);.

Por ejemplo, el siguiente código encendería y apagaría un LED conectado al pin digital D2:

void setup() {
  pinMode(D2, OUTPUT); //establecer el pin 13 como salida
}

void loop() {
  digitalWrite(D2, HIGH); //encender el LED
  delay(1000); //esperar un segundo
  digitalWrite(D2, LOW); //apagar el LED
  delay(1000); //esperar un segundo
}
¿Como leer el sensor DHT11 con la librería Adafuit y Arduino?

Para leer el sensor de temperatura y humedad DHT11 con la librería de Adafruit y Arduino, debes seguir los siguientes pasos:

  1. Descarga e instala la librería de Adafruit DHT desde el administrador de librerías de Arduino. Puedes hacerlo yendo al menú "Sketch -> Incluir librería -> Administrar librerías" y buscando "DHT".

  2. Conecta el pin de datos del sensor DHT11 a uno de los pines digitales de la placa Arduino. En el ejemplo a continuación, se utiliza el pin D7.

  3. En el código, primero debes incluir las librerías necesarias:

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
  1. Luego, define el pin de datos y el tipo de sensor que estás utilizando:

#define DHTPIN  D7     // Pin digital conectado al sensor DHT
#define DHTTYPE DHT11  // DHT 11

DHT_Unified dht(DHTPIN, DHTTYPE);

  1. En la función setup(), inicializa el dispositivo DHT y realiza una impresión por consola de los detalles del sensor:
    void setup() {
      dht.begin(); // Inicializar dispositivo DHT
      Serial.begin(115200);
      Serial.println(F("Sensor DHT11"));
      // Imprime los detalles del sensor de temperatura.
      sensor_t sensor;
      dht.temperature().getSensor(&sensor);
      Serial.println(F("------------------------------------"));
      Serial.println(F("Sensor de Temperatura"));
      Serial.print  (F("Valor Max:   ")); Serial.print(sensor.max_value); Serial.println(F("°C"));
      Serial.print  (F("Valor Min:   ")); Serial.print(sensor.min_value); Serial.println(F("°C"));
      Serial.print  (F("Resolucion:  ")); Serial.print(sensor.resolution); Serial.println(F("°C"));
      // Imprime los detalles del sensor de humedad.
      dht.humidity().getSensor(&sensor);
      Serial.println(F("Sensor de Humedad"));
      Serial.print  (F("Valor Max:   ")); Serial.print(sensor.max_value); Serial.println(F("%"));
      Serial.print  (F("Valor Min:   ")); Serial.print(sensor.min_value); Serial.println(F("%"));
      Serial.print  (F("Resolucion:  ")); Serial.print(sensor.resolution); Serial.println(F("%"));
      Serial.println(F("------------------------------------"));
    }
  2. En la función loop(), puedes obtener los valores de temperatura y humedad del sensor DHT11 y mostrarlos por consola:
    void loop() {
      sensors_event_t event;
      dht.temperature().getEvent(&event);
      if (isnan(event.temperature)) {
        Serial.println(F("¡Error al leer la temperatura!"));
      }
      else {
        Serial.print(F("Temperatura: "));
        Serial.print(event.temperature);
        Serial.println(F("°C"));
      }
      dht.humidity().getEvent(&event);
      if (isnan(event.relative_humidity)) {
        Serial.println(F("¡Error al leer la humedad!"));
      }
      else {
        Serial.print(F("Humedad: "));
        Serial.print(event.relative_humidity);
        Serial.println(F("%"));
      }
      delay(2000);
    }

¡Ahora es tu turno! Realiza el código completo con los siguientes ingredientes hardware para que todo el sistema funcione.

El programa deberá utilizar un sensor DHT11 para medir la temperatura y humedad del ambiente y un sensor LDR para medir la intensidad de luz. También incluir dos LEDs que parpadean de manera alterna cada segundo.

En la función setup(), se inicializan los puertos de entrada y salida para los sensores y los LEDs, se imprime información detallada acerca del sensor DHT11 y se configura la velocidad de comunicación del puerto serie a 115200 bauds.

En la función loop(), se leen los valores del sensor LDR y se imprimen en el monitor serie junto con los valores de temperatura y humedad del sensor DHT11, si están disponibles. Los LEDs parpadean alternadamente cada segundo. 



Código Completo

Solución

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

#define DHTPIN  D7     // Pin digital conectado al sensor DHT
#define DHTTYPE DHT11  // DHT 11
DHT_Unified dht(DHTPIN, DHTTYPE);

#define LED_ROJO D5
#define LED_VERDE D6

#define LDR_PIN A0
int sensorLDRValue = 0;  // variable para almacenar el valor proveniente del sensor LDR

// la función de setup() se ejecuta una vez cuando presionas el botón de reset o enciendes la placa
void setup() {

  Serial.begin(115200);        // inicializa el puerto serie (USB - COM) en una velocidad de comunicación de 115200 bauds
  Serial.println("\n\n");

  pinMode(LED_ROJO, OUTPUT);   // inicializa el pin digital LED_ROJO como salida.
  pinMode(LED_VERDE, OUTPUT);  // inicializa el pin digital LED_VERDE como salida.

  dht.begin(); // Inicializar dispositivo DHT
  Serial.println(F("Sensor DHT11"));
// Imprime los detalles del sensor de temperatura.
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  Serial.println(F("------------------------------------"));
  Serial.println(F("Sensor de Temperatura"));
  Serial.print  (F("Valor Max:   ")); Serial.print(sensor.max_value); Serial.println(F("°C"));
  Serial.print  (F("Valor Min:   ")); Serial.print(sensor.min_value); Serial.println(F("°C"));
  Serial.print  (F("Resolucion:  ")); Serial.print(sensor.resolution); Serial.println(F("°C"));
// Imprime los detalles del sensor de humedad.
  dht.humidity().getSensor(&sensor);
  Serial.println(F("Sensor de Humedad"));
  Serial.print  (F("Valor Max:   ")); Serial.print(sensor.max_value); Serial.println(F("%"));
  Serial.print  (F("Valor Min:   ")); Serial.print(sensor.min_value); Serial.println(F("%"));
  Serial.print  (F("Resolucion:  ")); Serial.print(sensor.resolution); Serial.println(F("%"));
  Serial.println(F("------------------------------------"));
}

// la función de loop() se ejecuta una y otra vez para siempre
void loop() {
  digitalWrite(LED_ROJO, HIGH);   // enciende el LED (HIGH es el nivel alto de voltaje - 3.3V)
  digitalWrite(LED_VERDE, LOW);   // apaga el LED haciendo que el voltaje sea bajo (LOW)
  delay(1000);                    // espera un segundo - 1000 ms (milisegundos)
  digitalWrite(LED_ROJO, LOW);    // apaga el LED haciendo que el voltaje sea bajo (LOW)
  digitalWrite(LED_VERDE, HIGH);  // enciende el LED (HIGH es el nivel alto de voltaje - 3.3V)
  delay(1000);                    // espera un segundo - 1000 ms (milisegundos)

  // read the value from the sensor:
  sensorLDRValue = analogRead(LDR_PIN);
  Serial.print(F("LDR: "));
  Serial.print(sensorLDRValue);

  mostrar_datos_sensor_DHT11();

  Serial.println();
}

void mostrar_datos_sensor_DHT11(){
  // Obtenga si hay evento de temperatura e imprima su valor.
  sensors_event_t event;
  dht.temperature().getEvent(&event);
  if (isnan(event.temperature)) {
    Serial.print(F("\t"));
    //Serial.println(F("¡Error al leer la temperatura!"));
  }
  else {
    Serial.print(F("\t"));
    Serial.print(F("Temperatura: "));
    Serial.print(event.temperature);
    Serial.print(F("°C"));
  }
  // Obtenga si hay evento de humedad e imprima su valor.
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    Serial.print(F("\t"));
    //Serial.println(F("¡Error al leer la humedad!"));
  }
  else {
    Serial.print(F("\t"));
    Serial.print(F("Humedad: "));
    Serial.print(event.relative_humidity);
    Serial.print(F("%"));
  }
}


Descargar el código de ejemplo completo

ESP8266: El Arduino con WiFi

5. Comunicación de los datos utilizando MQTT

¿Que es MQTT?

MQTT (Message Queuing Telemetry Transport) es un protocolo de comunicación ligero y de publicación-suscripción que se utiliza comúnmente en aplicaciones de Internet de las cosas (IoT). 

MQTT se basa en un modelo de mensajería de publicación/suscripción, en el que los clientes pueden publicar mensajes en un tema (topic) y otros clientes pueden suscribirse a ese tema para recibir los mensajes. Los temas son cadenas de caracteres que representan un canal de comunicación en particular. Los clientes pueden suscribirse a un tema específico y recibir los mensajes que se publican en ese tema.

MQTT se utiliza comúnmente en aplicaciones IoT debido a su baja sobrecarga y su capacidad para funcionar en redes con ancho de banda limitado y alta latencia. También es compatible con la seguridad a nivel de transporte mediante TLS/SSL, lo que lo hace adecuado para entornos empresariales y de seguridad crítica.

¿Cómo hago un primer ejemplo?


Este código es un ejemplo básico de cómo conectar un dispositivo ESP8266 a un broker MQTT usando la biblioteca PubSubClient de Arduino.

En la función setup(), se inicializan los pines del dispositivo y se configura la conexión Wi-Fi. A continuación, se establece la conexión con el servidor MQTT mediante el método setServer() de la biblioteca PubSubClient. También se establece la función callback() para manejar los mensajes entrantes.

En la función loop(), se verifica si el cliente MQTT está conectado. Si no lo está, se intenta una reconexión llamando a la función reconnect(). Luego, se llama a la función loop() del cliente para procesar los mensajes entrantes y salientes.

Finalmente, en la función loop(), se envía un mensaje al broker MQTT cada dos segundos mediante el método publish() del cliente, y se incrementa el valor de la variable value para que cada mensaje tenga un número de secuencia único.

En resumen, este código muestra cómo establecer una conexión básica entre un dispositivo ESP8266 y un broker MQTT y cómo enviar mensajes a través de la red MQTT.

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

// Update these with values suitable for your network.
const char* ssid = "wifi_name";
const char* password = "wifi_password";
const char* mqtt_server = "mqtt.makersupv.com";
#define USER "makersupv"
#define PASS "makersupv"
String TEAM = "t00";
String OUT_TOPIC = "taller/" + TEAM + "/outTopic";
String IN_TOPIC = "taller/" + TEAM + "/inTopic";

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE	(64)
char msg[MSG_BUFFER_SIZE];
int value = 0;

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

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

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String client_id = "";
    // Attempt to connect
    if (client.connect(client_id.c_str(), USER, PASS)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(OUT_TOPIC.c_str(), "hello world");
      // ... and resubscribe
      client.subscribe(IN_TOPIC.c_str());
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {

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

  unsigned long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish(OUT_TOPIC, msg);
  }
}

Para poder verificar que estaís recibiendo información podeís descargaros una aplicación en vuestro movil como MyMQTT esta disponible para iOS y Android. Con esta aplicación podréis debuggear lo que está suciendo, si recibis mensajes, también si podéis actuar sobre los diferentes componentes.

Solución
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

#define DHTPIN  D7     // Pin digital conectado al sensor DHT
#define DHTTYPE DHT11  // DHT 11
DHT_Unified dht(DHTPIN, DHTTYPE);

#define LED_ROJO D5
#define LED_VERDE D6

#define LDR_PIN A0
int sensorLDRValue = 0;  // variable para almacenar el valor proveniente del sensor LDR


// Update these with values suitable for your network.
const char* ssid = "makersupv";
const char* password = "makersupv";
const char* mqtt_server = "mqtt.makersupv.com";
#define USER "makersupv"
#define PASS "makersupv"
String TEAM = "TEAM_MAKERS";
String OUT_TOPIC_TEMP = "taller/" + TEAM + "/sens/DHT11/temp";
String OUT_TOPIC_HUM = "taller/" + TEAM + "/sens/DHT11/hum";
String OUT_TOPIC_LDR = "taller/" + TEAM + "/sens/LDR";
String IN_TOPIC_LED_VERDE = "taller/" + TEAM + "/leds/verde";
String IN_TOPIC_LED_ROJO = "taller/" + TEAM + "/leds/rojo";

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE	(64)
char msg[MSG_BUFFER_SIZE];
int value = 0;

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

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

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if(topic == IN_TOPIC_LED_VERDE.c_str()){
    // Switch on the LED if an 1 was received as first character
    if ((char)payload[0] == '0') {
      digitalWrite(LED_VERDE, LOW);   // Turn the LED on (Note that LOW is the voltage level
    } else if ((char)payload[0] == '1'){
      digitalWrite(LED_VERDE, HIGH);  // Turn the LED off by making the voltage HIGH
    }
  }

  if(topic == IN_TOPIC_LED_ROJO.c_str()) {
    // Switch on the LED if an 1 was received as first character
    if ((char)payload[0] == '0') {
      digitalWrite(LED_ROJO, LOW);   // Turn the LED on (Note that LOW is the voltage level
    } else if ((char)payload[0] == '1'){
      digitalWrite(LED_ROJO, HIGH);  // Turn the LED off by making the voltage HIGH
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String client_id = "";
    // Attempt to connect
    if (client.connect(client_id.c_str(), USER, PASS)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      //client.publish(OUT_TOPIC.c_str(), "hello world");
      // ... and resubscribe
      client.subscribe(IN_TOPIC_LED_VERDE.c_str());
      client.subscribe(IN_TOPIC_LED_ROJO.c_str());
      //client.subscribe(OUT_TOPIC_HUM.c_str());

    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}



// la función de setup() se ejecuta una vez cuando presionas el botón de reset o enciendes la placa
void setup() {

  Serial.begin(115200);        // inicializa el puerto serie (USB - COM) en una velocidad de comunicación de 115200 bauds
  Serial.println("\n\n");

  pinMode(LED_ROJO, OUTPUT);   // inicializa el pin digital LED_ROJO como salida.
  pinMode(LED_VERDE, OUTPUT);  // inicializa el pin digital LED_VERDE como salida.

  dht.begin(); // Inicializar dispositivo DHT
  Serial.println(F("Sensor DHT11"));
// Imprime los detalles del sensor de temperatura.
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  Serial.println(F("------------------------------------"));
  Serial.println(F("Sensor de Temperatura"));
  Serial.print  (F("Valor Max:   ")); Serial.print(sensor.max_value); Serial.println(F("°C"));
  Serial.print  (F("Valor Min:   ")); Serial.print(sensor.min_value); Serial.println(F("°C"));
  Serial.print  (F("Resolucion:  ")); Serial.print(sensor.resolution); Serial.println(F("°C"));
// Imprime los detalles del sensor de humedad.
  dht.humidity().getSensor(&sensor);
  Serial.println(F("Sensor de Humedad"));
  Serial.print  (F("Valor Max:   ")); Serial.print(sensor.max_value); Serial.println(F("%"));
  Serial.print  (F("Valor Min:   ")); Serial.print(sensor.min_value); Serial.println(F("%"));
  Serial.print  (F("Resolucion:  ")); Serial.print(sensor.resolution); Serial.println(F("%"));
  Serial.println(F("------------------------------------"));

  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

// la función de loop() se ejecuta una y otra vez para siempre
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  unsigned long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;

    // read the value from the sensor:
    sensorLDRValue = analogRead(LDR_PIN);
    Serial.print(F("LDR: "));
    Serial.print(sensorLDRValue);
    snprintf (msg, MSG_BUFFER_SIZE, "%ld", sensorLDRValue);
    client.publish(OUT_TOPIC_LDR.c_str(), msg);

    mostrar_datos_sensor_DHT11();

    Serial.println();

  }
}

void mostrar_datos_sensor_DHT11(){
  // Obtenga si hay evento de temperatura e imprima su valor.
  sensors_event_t event;
  dht.temperature().getEvent(&event);
  if (isnan(event.temperature)) {
    Serial.print(F("\t"));
    //Serial.println(F("¡Error al leer la temperatura!"));
  }
  else {
    Serial.print(F("\t"));
    Serial.print(F("Temperatura: "));
    Serial.print(event.temperature);
    snprintf (msg, MSG_BUFFER_SIZE, "%ld", (int) event.temperature);
    client.publish(OUT_TOPIC_TEMP.c_str(), msg);
    Serial.print(F("°C"));
  }
  // Obtenga si hay evento de humedad e imprima su valor.
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    Serial.print(F("\t"));
    //Serial.println(F("¡Error al leer la humedad!"));
  }
  else {
    Serial.print(F("\t"));
    Serial.print(F("Humedad: "));
    Serial.print(event.relative_humidity);
    snprintf (msg, MSG_BUFFER_SIZE, "%ld", (int) event.relative_humidity);
    client.publish(OUT_TOPIC_HUM.c_str(), msg);
    Serial.print(F("%"));
  }
}

Ahora te toca a ti, coge el ejemplo del tutorial 4 y combinalo con el ejemplo anterior para poder enviar y recibir datos de los sensores.

Estos son los temas (topics) que debes usar:

Tipo

Descripción Unidades Topic MQTT
Sensor Lectura sensor temperatura DHT11 ºC taller/tXX/sens/DHT11/temp
Sensor Lectura sensor humedad relativa DHT11 %rh taller/tXX/sens/DHT11/hum
Sensor Lectura sensor luminosidad LDR Volts taller/tXX/sens/LDR
Actuador LED Indicador LED Verde   taller/tXX/leds/verde
Actuador LED Indicador LED Rojo   taller/tXX/leds/rojo

Recuerda cambiar t00 por el número de tu equipo

ESP8266: El Arduino con WiFi

6. (Opcional) Comunicación de los datos utilizando el broker de MQTT de HiveMQ

¡¡NIVEL MEDIO!!

Para ejecutar este tutorial se debe utilizar la versión 1 del IDE de Arduino.

¿Porque HiveMQ Cloud?

Un agente gratuito de Cloud MQTT que le permite conectar hasta 100 dispositivos.

A free Cloud MQTT Broker that enables you to connect up to 100 devices.

https://www.hivemq.com/downloads/

Registrarse en el enlace anterior. Una vez registrado, nos aparece las siguientes opciones, los primeros datos hacen referencia a los datos de conexión del servidor.

server_info.png

El segundo apartado trata de rellenar los datos de conexión con un usuario y una contraseña robusta.

credenciales.png

Por último, accede al tutorial de arduino, justamente un tutorial para ESP8266.

select_option.png

tutorial_1.png

tutorial_2.png

EXAMPLE FILES - CERTS.AR AND SKETCH

tutorial_3.png

 

tutorial_4.png

NodeRED

NodeRED

1. ¿Que es NodeRED?

Node-RED es como un juego de construcción que te permite conectar diferentes partes de tu hogar, tu negocio o tu proyecto de Internet of Thigns (como sensores, dispositivos y servicios en línea) de manera fácil y rápida, sin necesidad de ser un experto en programación. Es como jugar con bloques de LEGO, donde puedes unir diferentes bloques para hacer algo más grande y útil, como una casa o un robot.

Con Node-RED, puedes arrastrar y soltar diferentes "bloques" (llamados nodos) en una interfaz gráfica, conectarlos y configurarlos para que hagan cosas como leer datos de sensores o enviar alertas. Así, puedes automatizar procesos y hacer que todo funcione de manera más eficiente y sin necesidad de mucho conocimiento técnico.

Lo mejor de Node-RED es que tiene muchos bloques predefinidos que te permiten conectar con una gran variedad de dispositivos y servicios en línea, lo que lo hace muy versátil y adaptable a diferentes situaciones. Además, puedes integrarlo con otras herramientas y plataformas en el IoT para crear soluciones personalizadas y adaptadas a tus necesidades.

Te dejo con un video por si te has quedado con ganas de más:

NodeRED

2. Crear una instancia de NodeRED en la plataforma de MakersUPV

Para el taller de NodeRED hemos creado una plataforma donde cada uno de vosotros podrá tener su propia instancia de NodeRED de tal manera de que cada uno tenga su propia instalación y no os chaféis entre unos y otros.

Esta plataforma es accesible desde: taller-nodered.makersupv.com y ha sido creada utilizando el proyecto FlowForge. Si tienes curiosidad pregúntanos.

Registrarse en la plataforma de NodeRED

Deberéis crearos una cuenta por parejas en la plataforma que hemos alojado en nuestros servidores para que podáis hacer uso de NodeRED. Entra en click en taller-nodered.makersupv.com y haz click en Sign up:

image-1681063707031.png

Rellenar con el nombre de usuario, nombre completo, email y contraseña, como en cualquier otro sitio.

Os llegará un email con un enlace para confirmar la creación de la cuenta. Haz click en el enlace y confirma la cuenta.

El email llega desde donotreply@flowforge.com o talleres-nodered@makersupv.com. Si no te ha llegado a la bandeja de entrada, mira en la carpeta de Spam o en Promociones.

Una vez validado el email ya podrás loguearte en la plataforma con la cuenta que acabas de crear:

image-1681064582118.png

Crear una instancia de NodeRED

A continuación deberás crear una instancia de NodeRED. Esta instancia será unica y exclusiva para tu usuario, por lo que ningún compañero te podrá chafar tus progresos.

Para crear la instancia haz click en "Create Appication":

image-1681064880419.png

Te recomendamos utilizar el número del equipo que te han asignado, por ejemplo si eres el equipo 01, llama a la instancia "equipo01".

image-1681065031825.png

Ya nos hemos encargado de preparar el tipo de instancia y el stack que necesitaís para el taller por lo que el resto de opciones déjalas por defecto y haz click en "Create Application".

La instancia que acabas de crear aparecerá en la lista con estado starting. Deberás esperar a que el estado cambie a Running para poder empezar a hacer uso de la instancia de NodeRED.

image-1681065126880.png

image-1681065138003.png

Una vez haya pasado al estado running, le daremos a Open Editor para que nos habrá la instancia de NodeRED. También podremos acceder desde la URL [NOMBRE-INSTANCIA].taller-nodered.makersupv.com.

image-1681065741164.png

Observarás que hay que estar logueado en la plataforma para poder entrar, esto se ha hecho así para dar seguridad y que nadie pueda entrar a vuestros Flows.

Listo! ¿Facil verdad?... A decir verdad, hemos simplificado enormemente la tarea de creación de una instancia de NodeRED, gracias a usar FlowForge y a que lo hemos preparado de manera muy simplificada para este taller intruductorio. Pero NodeRED es compatible con casi cualquier hardware, por lo que lo puedes instalar en local en tu ordenador, en la nube con una VM con Docker, AWS,  en una Raspberry Pi, en un NAS, en un ordenador viejo que tengas por ahí tirado por casa, etc.

Si te llama la atención, desde MakersUPV te animamos a que nos preguntes y a que te instales NodeRED en tus equipos para aprender. Para empezar, échale un vistazo a https://nodered.org/docs/getting-started/

También puedes hacer uso de la plataforma de Makers para tus proyectos (preguntanos) o usar la versión hosteada de FlowForge, aunque la versión gratis tiene bastantes limitaciones, pero te servirá para aprender, hacer pruebas o incluso proyectos personales sencillitos.

Ahora sigue con el siguiente tutorial para crear tu primer Flow en NodeRED.

 

NodeRED

3. Crea tu primer flow: 'Hola mundo' con NodeRED

A continuación vamos a crear el primer flow en NodeRED. Y como no podía ser de otra manera, vamos a realizar un 'Hola mundo', es decir, el flow más sencillito que se puede realizar en NodeRED.

Espera, espera... ¿Que narices es un flow

Según ChatGPT:

En Node-RED, un "flow" es el término utilizado para describir el flujo de trabajo o la secuencia de nodos interconectados que se utilizan para automatizar un proceso o crear una aplicación. En otras palabras, un flujo en Node-RED es una representación visual de un programa que consta de una serie de nodos que realizan tareas específicas y que se conectan entre sí para formar un conjunto de acciones coordinadas.

Cada nodo en un flujo de Node-RED representa una funcionalidad específica, como leer un archivo, procesar datos, enviar un correo electrónico o publicar en Twitter. Los nodos se conectan entre sí mediante cables para indicar el orden en que se deben

ejecutar y cómo los datos deben fluir a través del flujo.

Los flujos de Node-RED son muy flexibles y se pueden personalizar para satisfacer una amplia gama de necesidades de automatización. Pueden ser utilizados para crear aplicaciones web, controlar dispositivos de IoT, analizar datos, integrar sistemas y mucho más.

Guía de uso, documentación oficial de NodeRED (recomendable tenerla a mano al principio): https://nodered.org/docs/user-guide/

1. El editor de NodeRED

El editor de Node-RED se compone de varias partes que se utilizan para crear y gestionar flujos. A continuación, se describen las partes principales del editor de Node-RED:

image-1681082094595.png    image-1681082083467.png

  1. Barra de menú (header): la barra de menú se encuentra en la parte superior del editor y contiene opciones para crear, abrir, guardar y exportar flujos, así como para configurar la herramienta y ver la documentación.

  2. Área de trabajo (workspace): el área de trabajo es el espacio central del editor donde se construyen los flujos. Es aquí donde se arrastran y sueltan los nodos, se conectan y se configuran.

  3. Paleta de nodo (palette)s: la paleta de nodos se encuentra en el lado izquierdo del editor y contiene todos los nodos disponibles en Node-RED. Los nodos se organizan por categorías, como entrada, salida, procesamiento, etc.

  4. Pestañas de flujo: las pestañas de flujo se encuentran en la parte superior del área de trabajo y se utilizan para alternar entre diferentes flujos que se han creado.

  5. Barra de propiedades (sidebar): la barra de propiedades se encuentra en la parte inferior del editor y muestra las opciones de configuración del nodo seleccionado. Esta barra cambia según el nodo que se seleccione en el área de trabajo.

Estas son las partes principales del editor de Node-RED. Con estas herramientas, los usuarios pueden construir flujos de manera intuitiva y eficiente.

1. Hola Mundo

Vamos a realizar el Hola mundo de NodeRED. Este sería el flow más sencillito que podemos hacer con NodeRED y nos servirá para empezar a aprender como funciona NodeRED.

En primer lugar, vamos a cambiar el nombre al Flow. Si partimos de una instalación limpia, tendremos el workspace vacío con una sola pestaña, llamada Flow 1. Este es el primer flow, que se crea por defecto. Haremos doble click en la pestaña y se nos desplegará un editor. En este editor podremos cambiar las propiedades del flow como el nombre y la descripción. 

Le pondremos "Hola mundo" como nombre y le daremos a Done:

image-1681082946789.png

A continuación vamos a insertar nuestro primer nodo dentro del flow "Hola mundo". El primer nodo va a ser un nodo de inyección o inject node. Este nodo nos permite inyectar un mensaje de forma manual o automatizada (luego lo veremos). El nodo de inyección es muy util para depurar un flow cuando estamos probando cosas (más adelante lo aprenderemos a usar también para este fin).

Insertar el nodo es tan sencillo como cogerlo de la paleta de nodos (está el primero, no tiene perdida, y si no lo podemos buscar en el buscador), y arrastrarlo al area de trabajo (da iguial donde, tu tiralo ahí en medio).

Posteriormente debemos configurar el nodo para que mande lo que nos interesa. Por defecto viene configurado para mandar un timestamp, es decir, un número con el tiempo. No obstante, lo vamos a cambiar para que mande el típico mensaje de "Hola mundo". Para ello hacemos doble click en el y se nos abrirá la ventana de propiedades. Cambiaremos el campo msg.payload para que mande un string, en vez de un timestamp

image-1681071330737.png

Introduciremos "Hola mundo" para que mande este mensaje cuando le pulsemos:

image-1681071352711.png

El siguiente nodo que introduciremos a nuestro primer flow es el nodo debug. Se trata de un nodo de salida que nos permite visualizar los mensajes que mandemos en la consola de depuración debug (en la barra de la derecha). Este nodo, como su nombre indica, nos será tremendamente util para depurar nuestros flujos de trabajo.

Lo mismo que antes: lo arrastramos al area de trabajo y a continuación uniremos el nodo de inyección del mensaje Hola mundo, con el de depuración mediante un cable:

image-1681071443241.png

Como ya te habrás podido imaginar, esto lo que hará será mostrar el mensaje de Hola mundo en la consola de depuración cuando hagamos click en el botón de lanzar el mensaje.

Para probarlo, haremos click en el botón de Deploy, lo cual hará que se guarden nuestros cambios y se despliegue nuestro flujo, es decir, que se comience a ejecutar.

Haremos click en el botón de inyectar y veremos como se muestra el mensaje en la consola de depuración:

image-1681071457733.png

Enhorabuena, ya has realizado tu primer flow en NodeRED!!

2. Hola mundo "avanzado"

Ahora vamos a modificar un poco el flow para que muestre un mensaje cada segundo en la consola de debug con la fecha formateada (vamos un pasito más allá).

Para ello vamos a introducir el nodo de function, el cual es muy utilizado, ya que nos permite ejectuar código de Javascript para actuar sobre los mensajes. No te preocupes si no sabes Javascript, lo haremos muy sencillito.

Además, vamos a introducir otros conceptos como el de exportar/importar flows para poder compartirlos con la comunidad o aprovecharnos de flujos hechos por otra gente.

Para descargar nodos compartidos por la comunidad puedes echar un ojo a esto:

https://flows.nodered.org/search?type=flow 

Para ello vamos a exportar el flow para importarlo en otroHaremos click en las opciones y luego en Export (o Ctrl+E, para los que os molen los atajos). Nos aseguraremos de que esté seleccionada la opción de Current flow, puesto que queremos exportar solo el flow de Hola mundo. Haremos click en Copy to clipboard y si somos curiosos podemos pegarlo en un Notepad para ver el contenido, aunque no hace falta, os lo dejo más abajo.

image-1681125315949.png

El contenido será algo parecido a esto:

hola-mundo-nodered.json
[
    {
        "id": "3df5086d4148c6a8",
        "type": "tab",
        "label": "Hola mundo",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "4e9e565e59b044c2",
        "type": "inject",
        "z": "3df5086d4148c6a8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "Hola mundo",
        "payloadType": "str",
        "x": 270,
        "y": 340,
        "wires": [
            [
                "5d6fe20a8f7613af"
            ]
        ]
    },
    {
        "id": "5d6fe20a8f7613af",
        "type": "debug",
        "z": "3df5086d4148c6a8",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 840,
        "y": 340,
        "wires": []
    }
]

Se trata de un archivo de texto en formato JSON que describe el flow. Tanto los nodos, como las conexiones entre ellos y sus configuraciones.

Ahora nos vamos otra vez a opciones, hacemos click en Import (Ctrl + I), pegamos el JSON, asegurandonos que esté marcada la opción de New Flow para que nos cree un nuevo flujo de trabajo, y hacemos click en el botón rojo de Import.

Podemos aprovechar también para echarle un vistazo a los ejemplos que vienen instalados en NodeRED, que nos pueden servir para aprender

image-1681126877785.png

Observaremos que nos salé un mensaje de que el flow y los nodos ya existen. Esto es porque cada nodo tiene asignado un identificador único y al haber importado un flujo cuyos identificadores ya existen nos dice que algo no cuadra.

Nos da la opción de revisar los nodos para ver donde está fallando. En este caso le daremos directamente a que lo importe como una copia:

image-1681130459113.png

Veremos que se nos ha creado un nuevo flujo de trabajo con el mismo nombre y los mismos nodos, es decir, una copia identica.

Le cambiaremos el nombre del flujo a "Hola mundo avanzado".

Ahora vamos a cambiar las propiedades del nodo inject para que esté como estaba al principio. Es decir, para que inyecte un timestamp. Además, le vamos a decir que inyecte el mensaje cada segundo:

image-1681130906869.png

 A continuación, lle vamos a añadir un nodo de función entre el nodo de inject y el de debug:

image-1681130989805.png

Nota: Tan solo tienes que arrastrar el nuevo nodo en medio del cable y soltar. Verás que se marca el cable en lineas discontinuas. Eso significa que se va a cortar el cable y añadir el nodo de función en medio.

A continuación introducimos este código en el bloque de función:

// Crear un objeto "Date" desde el payload
var date = new Date(msg.payload);
// Cambiar el payload para que sea un string formateado
msg.payload = date.toLocaleTimeString('es-ES', { timeZone: 'Europe/Madrid'});
// Devuelve el mensaje formateado
return msg;

Este código lo que hace es coger el timestamp, formatearlo para obtener la hora y devolverlo.

Despliega el flujo y observa la salida de debug.

Ya estás preparado para seguir con el siguiente ejercicio!

NodeRED

4. Interfaz gráfica

A continuación vamos a aprender a crear interfaces gráficas con NodeRED de una manera SUUUUPER sencilla. Para ello vamos a hacer uso de una de las grandes maravillas de NodeRED: los plugins (o módulos).

Los plugins o módulos nos permiten obtener nodos adicionalmente a los que vienen incluidos por defecto en NodeRED, y nos permitirán extender las funcionalidades y simplificarnos según que cosas. Vamos a aprender a instalar y utilizar el módulo de node-red-dashboard y como su propio nombre indica, nos permitirá añadir dashboards con componentes gráficos donde mostrar datos, incluir botones, etiquetas, etc.

Puedes ver más información sobre el plugin en el siguiente enlace: https://flows.nodered.org/node/node-red-dashboard

1. Instalar node-red-dashboard

El proceso de instalación (para este y cualquier otro plugin "oficial" de NodeRED no puede ser más sencillo:

Nos vamos al menu de NodeRED y hacemos click en "Manage palette":

image-1682964547973.png

Veremos que nos sale un menu con dos pestañas, la primera son los nodos (o plugins) que tenemos instalados. La segunda, es donde encontraremos los plugins que podemos descargar, nos vamos a esta última y buscamos "dashboard" en el buscador:

image-1682964543127.png

Vemos que nos sale en tercera posición el que queremos instalar. Hacemos click en Install y listo. Facil, ¿no?

2. Primer ejercicio de prueba con interfaz gráfica

A continuación vamos a realizar una pequeña prueba para verificar que el módulo se ha instalado correctamente, y para conocer brevemente el funcionamiento de los nodos que proporciona este plugin.

Para ello, te pedimos que crees un flujo muy simple donde pintes el valor de timestamp e

nodered_ui_1.png

Una vez desplegado, para acceder al dashboard deberás acceder a la raiz de la URL de tu instancia terminada en /url, por ejemplo:

https://equipo00.taller-nodered.makersupv.com/ui/ 

Y verás algo así:

nodered_ui_2.png

Activa que se inyecte el timestamp cada 1 segundo y observa como crece en el dashboard

NodeRED

5. Recibe los datos del ESP en NodeRED con MQTT

Hasta ahora todo bastante facil, ¿verdad? Vamos a complicarlo un poco más!

Ahora vamos a graficar mediante los nodos de dashboard los datos de los sensores que recibimos mediante MQTT. Para ello deberás usar los nodos mqtt-in y mqtt-out para subscribirte a los topic de MQTT correspondientes.

Vamos a paso a paso para que no te pierdas:

1. Conexión al broker MQTT

En primer lugar nos vamos a conectar al broker servidor MQTT de donde vamos a enviar/recibir datos, al igual que lo hemos hecho con el ESP8266 en Arduino. Recuerda que tanto el dispositivo Arduino como el NodeRED deben estar conectados al mismo servidor MQTT, si no no podrán intercambiar información.

Para ello empieza introduciendo en el workspace un nodo mqtt in y presiona doble click para entrar en la configuración:

mqtt_in.png

Te saldrá totalmente vació y listo para añadiur un nuevo mqtt-broker. Haz click en el botón de editar:

add_new_broker.png

E introduce los datos de conexión para el broker MQTT de MakersUPV:

Datos conexión MQTT
Server MQTT mqtt.makersupv.com
Port 1883
Client ID (blank)
Username makersupv
Password makersupv

Asegurate de poner bien el usuario y contraseña, si no no te funcionará!

Te debería quedar de la siguiente manera:

add_new_broker_2.png

add_new_broker_3.png

Haz click en el botón de Añadir para guardar el broker MQTT. Tan solo tendrás que realizar este procedimiento la primera vez (con el primer nodo que añadas)

2. Subscripción y publicación al tópico MQTT

 Una vez guardado el servidor MQTT, posteriormente rellena el topic de subscripción para el sensor de temperatura:

mqtt_temp.png

Estos son los temas (topics) que debes usar:

Tipo

Descripción Unidades Topic MQTT
Sensor Lectura sensor temperatura DHT11 ºC taller/tXX/sens/DHT11/temp
Sensor Lectura sensor humedad relativa DHT11 %rh taller/tXX/sens/DHT11/hum
Sensor Lectura sensor luminosidad LDR Volts taller/tXX/sens/LDR
Actuador LED Indicador LED Verde   taller/tXX/leds/verde
Actuador LED Indicador LED Rojo   taller/tXX/leds/rojo

Recuerda cambiar t00 por el número de tu equipo

Haz click en Done. Se recomienda que en este punto añadas un nodo de debug y hagas un deploy para comprobar que se están recibiendo los datos del ESP8266 correctamente antes de pasar a los demás.

Una vez te hayas asegurado de que se reciben correctamente los datos, repite el proceso para los demás sensores (humedad y LDR),

Recuerda que puedes usar Copiar y Pegar (Ctrl+C, Ctrl+V) para los nodos

Ah! y para los LEDs... Deberás usar ¿que nodo?

Solución: ¿Que nodo uso para los LEDs?

Para los LEDs deberás usar el nodo mqtt-out, ya que lo que queremos es que el mensaje se mande dirección salida hacia el Arduino. Es decir, queremos usarlo para publicar un mensaje al topic correspondiente.

mqtt_out.png

3. Gauges

Las gauges, o indicadores en español, nos permiten mostrar un dato de manera visual mediante un indicador tipo aguja, similar a por ejemplo el velocimentro de un coche o un manómetro de los analógicos.

gauges.png

Ya los hemos usado anteriormente en el ejemplo con el Timestamp, pero no los hemos configurado. Comenzamos por añadir uno y conectarlo al nodo mqtt-in de la temperatura:

dht_temp.png


Ahora vamos a configurarlo según los requisitos específicos de nuestra aplicación. Para ello haz click en el nodo correspondiente y cambia los valores de la etiqueta, unidades, rango mínimo y máximo, colores del gradiente, etc. También podrás cambiar entre los distintos tipos de indicador (tipo aguja, donut, compás...)

Te recomiendo usar los nodos de Debug para cerciorarte que los datos llegan y en el formato que esperas

editar_gauge.png

Experimenta las opciones que te da el nodo de Gauge hasta que encuentres la opción que más te guste para representar la temperatura! Recuerda que deberás de pinchar en el botón de Deploy para desplegar los cambios cada vez que edites algo.

Comprueba que los datos se grafican como toca y que el gráfico se va actualizando en tiempo real según van variando las condiciones climáticas

Utiliza tu mano para calentar el sensor de temperatura DHT11 y tirale vaho con la boca para ver como aumenta la humedad relativa

Una vez tengas el de temperatura funcionando deberás hacer lo mismo para el sensor de humedad y para el de lumninosidad. 

Cuando hayas acabado, el resultado final debería ser algo parecido a la imagen de arriba, con un Gauge mostrando cada uno de los valores de los sensores.

4. Interruptores/botones

Ahora nos faltaría introducir una manera de encender y apagar los LEDs o actuadores de nuestro circuito. En este ejemplo sencillo que estamos haciendo para el taller son simples LEDs, pero podrían ser perfectamente bombillas, una lámpara, un enchufe inteligente, un relé conectado al motor de la depuradora de casa, la calefacción o cualquier otra cosa, ya pillas la idea...

Para encender y apagar los LED vamos a utilizar el nodo Switch, el cual no es más que un simple interruptor de dos posiciones: ON y OFF.

Será tan facil como añadir un interruptor para cada uno de los LEDs y conectarlo al nodo MQTT de salida correspondiente:

leds.png

A continuación deberás configurar los nodos interruptor para que manden un 1 cuando el estado sea ON y un 0 cuando sea OFF. De la siguiente manera:

led_config.png

Ejecutalo y prueba el resultado.

5. Gráfico temporal

Las gauges están muy bien para ver los datos en tiempo real, pero quizá te interese ver la evolución de la temperatura a lo largo de unas horas, ¿no? (o de unos minutos, para que nos dé tiempo a verlo en la clase)

Vamos a usar los gráficos (graph) para poder representar datos en un eje temporal:

grafico temp.png

Prueba a añadir un nodo Chart

temp_graph.png

Cambia las opciones para que aparezca donde te interese y despliega los cambios. Esperate a que lleguen datos de los sensores y verás como se va rellenando el gráfico en tiempo real.

Cabe destacar que estos gráficos son muy sencillos ya que no guardan los datos en ninguna base de datos y por tanto están bastante limitados. Pero para cosas sencillas nos valen

5. Resultado final

Una vez tengas todo, el resultado final debería ser algo así:

dashboard.png

ui_coimpleta2.png

Te animo a que experimentes... Seguro que no te cuesta nada conseguir un resultado MUUUUUUCHO mejor que el mio!

¿Y si quisieramos guardar las métricas en una base de datos?

Pues eso daría para otra sesión de un par de horitas seguramente, pero NodeRED dispone de plugins creados para almacenar datos en una base de datos temporal tipo InfluxDB por ejemplo, o incluso también permite hacer enlaces con bases de datos SQL y NoSQL como MongoDB, etc.

Otra manera de guardar los datos podría ser en un archivo CSV separados por coma mediante el nodo de guardar en fichero, de esa manera los podríamos tener guardados en un  archivo en el disco, aunque lo suyo para cosas serias es usar una base de datos como dios manda

Solución [No abrir, no seas tramposo]
[
    {
        "id": "5778ea97cd1ed074",
        "type": "tab",
        "label": "ESP8266",
        "disabled": false,
        "info": "Solución ejercicio visualización sensores y actuadores ESP8266",
        "env": []
    },
    {
        "id": "02973140566ef55c",
        "type": "mqtt in",
        "z": "5778ea97cd1ed074",
        "name": "DHT11 Temperatura",
        "topic": "taller/t00/sens/DHT11/temp",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "b5bdeb4155381a5d",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 450,
        "y": 160,
        "wires": [
            [
                "7aa944fea3c07822"
            ]
        ]
    },
    {
        "id": "609bc96d69db82e8",
        "type": "mqtt in",
        "z": "5778ea97cd1ed074",
        "name": "DHT11 Humedad",
        "topic": "taller/t00/sens/DHT11/hum",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "b5bdeb4155381a5d",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 440,
        "y": 220,
        "wires": [
            [
                "9e44099297dcc3a5"
            ]
        ]
    },
    {
        "id": "e0f0357e049277d2",
        "type": "mqtt in",
        "z": "5778ea97cd1ed074",
        "name": "LDR Luminosidad",
        "topic": "taller/t00/sens/LDR",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "b5bdeb4155381a5d",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 450,
        "y": 280,
        "wires": [
            [
                "280c63846cb13519"
            ]
        ]
    },
    {
        "id": "d34f1d5a1ba21375",
        "type": "mqtt out",
        "z": "5778ea97cd1ed074",
        "name": "LED Verde",
        "topic": "taller/t00/leds/verde",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "b5bdeb4155381a5d",
        "x": 830,
        "y": 400,
        "wires": []
    },
    {
        "id": "971b18f52f42468f",
        "type": "mqtt out",
        "z": "5778ea97cd1ed074",
        "name": "LED Rojo",
        "topic": "taller/t00/leds/rojo",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "b5bdeb4155381a5d",
        "x": 820,
        "y": 460,
        "wires": []
    },
    {
        "id": "7aa944fea3c07822",
        "type": "ui_gauge",
        "z": "5778ea97cd1ed074",
        "name": "Temperatura",
        "group": "3de4d1022cadb73f",
        "order": 0,
        "width": "6",
        "height": "3",
        "gtype": "gage",
        "title": "Temperatura",
        "label": "ºC",
        "format": "{{value}}",
        "min": "-10",
        "max": "40",
        "colors": [
            "#00b3b0",
            "#e6e600",
            "#ca3838"
        ],
        "seg1": "",
        "seg2": "",
        "diff": false,
        "className": "",
        "x": 930,
        "y": 160,
        "wires": []
    },
    {
        "id": "9e44099297dcc3a5",
        "type": "ui_gauge",
        "z": "5778ea97cd1ed074",
        "name": "Humedad",
        "group": "3de4d1022cadb73f",
        "order": 1,
        "width": "6",
        "height": "3",
        "gtype": "gage",
        "title": "Humedad",
        "label": "%RH",
        "format": "{{value}}",
        "min": 0,
        "max": "100",
        "colors": [
            "#1500b3",
            "#cbe600",
            "#ca3838"
        ],
        "seg1": "",
        "seg2": "",
        "diff": false,
        "className": "",
        "x": 920,
        "y": 220,
        "wires": []
    },
    {
        "id": "280c63846cb13519",
        "type": "ui_gauge",
        "z": "5778ea97cd1ed074",
        "name": "Luminosidad",
        "group": "3de4d1022cadb73f",
        "order": 2,
        "width": "6",
        "height": "3",
        "gtype": "gage",
        "title": "Luminosidad",
        "label": "units",
        "format": "{{value}}",
        "min": 0,
        "max": "1000",
        "colors": [
            "#000000",
            "#e6e600",
            "#ffffff"
        ],
        "seg1": "",
        "seg2": "",
        "diff": false,
        "className": "",
        "x": 930,
        "y": 280,
        "wires": []
    },
    {
        "id": "34e6bf482f2f4e81",
        "type": "ui_switch",
        "z": "5778ea97cd1ed074",
        "name": "LED Verde",
        "label": "LED Verde",
        "tooltip": "",
        "group": "71d9266564131fe1",
        "order": 0,
        "width": "4",
        "height": "2",
        "passthru": false,
        "decouple": "false",
        "topic": "topic",
        "topicType": "msg",
        "style": "",
        "onvalue": "1",
        "onvalueType": "num",
        "onicon": "",
        "oncolor": "",
        "offvalue": "0",
        "offvalueType": "num",
        "officon": "",
        "offcolor": "",
        "animate": true,
        "className": "",
        "x": 510,
        "y": 400,
        "wires": [
            [
                "d34f1d5a1ba21375"
            ]
        ]
    },
    {
        "id": "6a9f570b1bcbf20c",
        "type": "ui_switch",
        "z": "5778ea97cd1ed074",
        "name": "LED Rojo",
        "label": "LED Rojo",
        "tooltip": "",
        "group": "71d9266564131fe1",
        "order": 1,
        "width": "4",
        "height": "2",
        "passthru": true,
        "decouple": "false",
        "topic": "topic",
        "topicType": "msg",
        "style": "",
        "onvalue": "1",
        "onvalueType": "num",
        "onicon": "",
        "oncolor": "",
        "offvalue": "0",
        "offvalueType": "num",
        "officon": "",
        "offcolor": "",
        "animate": false,
        "className": "",
        "x": 500,
        "y": 460,
        "wires": [
            [
                "971b18f52f42468f"
            ]
        ]
    },
    {
        "id": "b5bdeb4155381a5d",
        "type": "mqtt-broker",
        "name": "Broker MakersUPV",
        "broker": "mqtt.makersupv.com",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    },
    {
        "id": "3de4d1022cadb73f",
        "type": "ui_group",
        "name": "Sensores",
        "tab": "be3445ce783f56f1",
        "order": 1,
        "disp": true,
        "width": "12",
        "collapse": false,
        "className": ""
    },
    {
        "id": "71d9266564131fe1",
        "type": "ui_group",
        "name": "Actuadores",
        "tab": "be3445ce783f56f1",
        "order": 2,
        "disp": true,
        "width": "12",
        "collapse": false,
        "className": ""
    },
    {
        "id": "be3445ce783f56f1",
        "type": "ui_tab",
        "name": "ESP8266",
        "icon": "fa-thermometer-half",
        "disabled": false,
        "hidden": false
    }
]

NodeRED

6. Ejercicios extra para los más valientes [OPCIONAL]

6.1. ¿Y si quisieras encender el LED rojo cuando la temperatura de la sala supere los 30 grados una tarde de agosto cualquiera en Valencia?

PISTA: Utiliza el nodo Switch y el nodo Change

Solución [No abrir, no seas tramposo]

solucion temperatura led.png

6.2. NIVEL CRACK: ¿Te através a cambiar la luminosidad de los leds mediante el nodo Slider de la UI?

Esta vez sin pistas... y sin solución!!

Extra

Extra

Instalar NodeRED en Raspberry Pi