Mostrando las entradas con la etiqueta ESP8266. Mostrar todas las entradas
Mostrando las entradas con la etiqueta ESP8266. Mostrar todas las entradas

domingo, 13 de enero de 2019

Leer y escribir en una memoria SD

Después de mucho tiempo voy a dedicarle un post a las memorias SD. Las memorias SD nos van a permitir escribir y leer datos de forma no volátil y que perduren a través del tiempo sin necesidad de utilizar la memoria EEPROM. Esto tiene muchas ventajas como la gran capacidad de almacenamiento, el reemplazo rápido de la memoria, el uso de un sistema de archivos nos permite exportar e importar datos con una computadora, etc.

Para esto vamos a utilizar una librería que viene incluida con el software de arduino y algún módulo que nos facilite el cableado entre el microcontrolador y la tarjeta de memoria, en mi caso voy a utilizar alguna de las pantallas que tengo que ya vienen con lectores de memorias SD, aunque no vamos a sacar imágenes de la memoria para mostrar en la pantalla, si vamos a cargar una página web y a almacenar datos en la tarjeta.

Primero vamos a ver el ejemplo del almacenamiento de datos, utilizando el siguiente código:

#include <SPI.h>
#include <SD.h>

const int selectorChip = 4;

void setup() {
  
  Serial.begin(9600);
  while(!Serial)
  {
    ;
  }

  Serial.println("inicializando tarjeta SD");

  //intentamos inicializar la memoria
  if(!SD.begin(selectorChip))
  {
    Serial.println("Fallo el inicio de la tarjeta.");
    //no hace nada más
    return;
  }
  Serial.println("Tarjeta iniciada.");
}

void loop()
{
  //genero los datos
  String datos = "milisegundos desde encendido: " + String(millis());
  //abro el archivo en modo escritura
  File archivo = SD.open("datos.txt", FILE_WRITE);
  //si se abrió correctamente guardo los datos.
  if(archivo)
  {
    archivo.println(datos);
    archivo.close();
  }
  else
  {
    Serial.println("error al intentar abrir el archivo datos.txt");
  }
}


Para el siguiente ejemplo vamos a utilizar un ESP8266 y el código ya utilizado en esta entrada


#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>

#include <SPI.h>
#include <SD.h>
File archivo;

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String HTMLpage = "";

void setup() {

  Serial.begin(115200);
  pinMode(2, OUTPUT);

  Serial.print("Inicializando tarjeta SD");

  if (!SD.begin(4)) {
    Serial.println("Fallo al incializar");
    return;
  }
  Serial.println("Tarjeta iniciada con exito");

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a");
  Serial.println(red);
  Serial.print("Dirección IP:");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", paginaWeb());
  });

  servidorweb.begin();
}

void loop() {
  
  servidorweb.handleClient();
  
}

String paginaWeb()
{
  String pagina = "";
  archivo = SD.open("pagina.txt");
  if(archivo)
  {
    //leo el archivo mientras esté disponible
    while(archivo.available())
    {
      //leo cada byte del archivo mientras esté disponible
      pagina +=archivo.read();
    }

    //cierro el archivo
    archivo.close();
    return pagina;
  }
}


Si queremos cargar otras páginas lo único que tenemos que hacer es "llamar" distintos archivos y modificar la función para que recupere otras cosas.

Hay que aclarar que la librería "SD" para el ESP8266 no es la misma que usamos normalmente para los arduinos, por lo que hay que especificar la ruta de la librería de la siguiente forma:

#include "c:\SD.h"

También lo que se puede hacer es poner la librería en la misma carpeta que el programa y de ahí "llamarla" colocando:

#include "SD.h"

En lugar de:

#include <SD.h>

De esta forma lo que conseguimos es que el preprocesador busque dentro de la carpeta del programa en lugar de la carpeta en donde se guardan las librerías normalmente.

De todas formas al ser tantos archivos que comparten el mismo nombre lo mejor va a ser modificar lo lo que diga SD por SD-esp de los siguientes ítem:
  • La carpeta (SD) 
  • El archivo SD.h (SD/src/SD.h)
  • El archivo SD.cpp (SD/src/SD.cpp)
  • La línea 53 del archivo SD.cpp (SD/src/SD.cpp)
  • La línea 15 del archivo File.cpp (SD/src/File.cpp)
Entonces en lugar de utilizar "#include <SD.h>" usaremos "#include <SD-esp.h>" (hay que modificar eso del programa).

Otro punto que hay que aclarar es la extensión del archivo, dado que la librería trabaja (por lo que tengo entendido) con nombres de archivo del estilo 8.3, es decir que el nombre puede tener un máximo de 8 caracteres y la extensión de 3, es por eso que no podemos utilizar un archivo ".html", pero como al final de cuentas a página es sólo texto, podemos utilizar un archivo de texto normal.

domingo, 30 de diciembre de 2018

Servidor web con ESP8266

Hoy les traigo la continuación del servidor simple, la idea es poder interactuar con el micro a través de una interfaz web. En este ejemplo vamos a encender y apagar el led del ESP8266 de forma remota, también se pueden agregar hojas de estilo y me imagino que también se puede agregar código en javaScript (después de todo lo que hay que hacer es mandar texto al navegador para que lo interprete), el único cuidado que hay que tener es escribir el html, el css y lo que necesiten uno a continuación del otro.

Para recuperar variables de la página web hay que hacerlo de la siguiente forma:

  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", HTMLpage);
  });

con el ".arg()" recuperamos el valor de la variable que pongamos entre paréntesis, luego podremos trabajar en función de eso.

El código total quedaría de la siguente forma:


#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String HTMLpage =

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)<br>"
      " con el micro ESP8266 para controlar<br>"
      " el led integrado en la placa."
    "</h3>"
    "<form action=\"/\" method=\"post\">"
      "<td><button name=\"estado\" type=\"submit\" class = \"button\" value=\"ON\">ON</button></td>"
      "<td><button name=\"estado\" type=\"submit\" class = \"button\" value=\"OFF\">OFF</button></td>"
    "</form>"
  "<html>";

void setup() {

  Serial.begin(115200);
  pinMode(2, OUTPUT);

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a");
  Serial.println(red);
  Serial.print("Dirección IP:");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", HTMLpage);
  });

  servidorweb.begin();
}

void loop() {
  
  servidorweb.handleClient();
  
}

Recordemos que la página va a estar montada sobre la dirección ip 192.168.4.1, por lo que hay que ingresar ahí para ver la página. Si bien la página y el código son muy sencillos, como mencioné antes, se puede agregar javaScript y css para que la página sea más interesante, pero hay que tener en cuenta que si queremos agregar librerías o frameworks de JS la memoria del microcontrolador va a empezar a escasear. En teoría se podría agregar una memoria externa (ej. una microSD) para almacenar la página web con todas las librerías y demás. A continuación les dejo cómo luce la página que acabamos de hacer.


Básicamente cuando presionamos los botones se "manda" al argumento "estado" el valor "ON" u "OFF" el cuál el servidor va a procesar para prender o apagar el led. Como los estados del ESP8266 están negados el estado low va a encender el led y el high lo va a apagar.

domingo, 16 de diciembre de 2018

ESP8266 y ILI9341

Hoy les traigo cómo utilizar el display gráfico (y a color!) basado en el driver ILI9341, el display gráfico en cuestión es uno de 2,2" y cuenta con un lector de memorias SD (que de momento no vamos a utilizar). Se maneja bajo el protocolo de comunicación SPI. La diferencia más notoria entre este display y el SPFD5408 es la velocidad con que se maneja, si bien el SPFD5408, al igual que el ILI9341, admite el uso de SPI como protocolo de comunicación lo que pude ver es que la velocidad con la que se refresca la pantalla es muchísimo más alta. Otra clara ventaja es que usa menos pines (aunque no probé el SPI de la SPFD5408, en su configuración "base" de hardware la cantidad de pines es menor), aunque no todo son ventajas, el ILI9341 no cuenta con una una entrada táctil, por lo que debemos desarrollar algo para que poder interactuar con el micro de ser necesario.


Como vamos a utilizar el ESP8266 para usar con este módulo vamos a necesitar una librería especial para este micro. El mapa de los pines utilizados es el siguiente:

DISPLAY        NodeMCU

SDO/MISO      D6 (no conecta si no se "lee" el display)
LED                 VIN (or 5V, see below)
SCK                 D5
SDI/MOSI       D7
DC (RS/AO)   D3
RESET            D4 (o RST, depende de la configuración)
CS                   D8 (o RST, depende de la configuración)
GND               GND (0V)
VCC               5V or 3.3V

Como es muy sencillo utilizar este display con los códigos de ejemplo que vienen con la librería debería bastar para que puedan entender la base. De todas formas les comento que esta librería posee un archivo que sirve para realizar algunas configuraciones, como por ejemplo:

*qué driver tiene la pantalla (en nuestro caso es la ILI9341)
*configuraciones especiales para ciertos drivers
*modificar los pines que se utilizan para la comunicación (los pines que se pueden evitar usar)
*qué fuentes se utilizan
*la frecuencia del SPI

Hay bastantes configuraciones disponibles con esta librería para adaptarla al proyecto que deseemos (más que nada para la optimización de la memoria del microcontrolador, y velocidad de la pantalla).

Algunos de los comandos útiles para el uso de este display son los siguientes:

  • drawPixel(x, y, color): este comando dibuja un pixel en la posición X e Y (que son del tipo UINT) y de color especificado en esa variable (también UINT, el color va a ser de 16 bits, 5 rojos, 6 verdes y 5 azules, utiliza la codificación RGB565 y se pueden generar con este programita)
  • fillScreen(color): útil para llenar toda la pantalla con un color.
  • drawLine(x0, y0, x1, y1, color): dibuja una línea entre los puntos (x0, y0) y (x1, y1) del color especificado.
  • draw/fillRect(x, y, medidaX, medidaY, color): dibuja un rectángulo con punto de inicio en (x, y) y de medidas de medidaX y medidaY, si es draw lo dibuja sin fondo, y si es fill es con fondo, el color hace referencia al color de lo que dibuja.
  • draw/fillRect(x, y, r, color): dibuja un círculo con centro en (x, y) de radio r y con el color pasa lo mismos que con el punto anterior.
  • drawString(texto, x, y, fuente): escribe el texto con puntos iniciales en (x, y) y con una fuente que como un valor genérico podría ser el 2.

Hay una lista muy larga de comandos que habría que explicar uno a uno, pero con los explicados arriba debería bastar para entender la dinámica básica del funcionamiento de la librería.

domingo, 4 de noviembre de 2018

Servidor web simple con ESP8266

Hola nuevamente, en esta publicación voy a explicar cómo hacer un servidor web muy simple que sólo muestra texto estático (mejor dicho html), si bien esto es básico, creo que hay que empezar por algo.
Aclaro, no voy a explicar cómo hacer páginas web, sólo voy a explicar cómo montar una en el micro ESP8266, para aprender pueden ir aquí.

Las librerías que vamos a usar son la "ESP8266WebServer", viene con las dependencias del ESP8266 para arduino por lo que no hace falta instalarlo aparte, "DNSServer" que sirve para administrar las conexiones de los clientes y la "ESP8266WiFi" que se encarga de configurar el micro para que funcione correctamente.


#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String pagina = 

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)"
      " con el micro ESP8266"
    "</h3>"
  "<html>";

void setup() {

  Serial.begin(115200);

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a: ");
  Serial.println(red);
  Serial.print("Direccion IP: ");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    servidorweb.send(200, "text/html", pagina);
  });

  servidorweb.begin();

}

void loop() {
  
  servidorweb.handleClient();
}


Como podemos ver se debe declarar el objeto:

ESP8266WebServer servidorweb(80);

y es el que vamos a utilizar cuando hagamos referencia a la librería. Luego se define el nombre de la red a la que nos vamos a conectar, la contraseña y por último definimos lo que va a ser la página web en sí.
Como podemos observar la página está escrita de una forma poco convencional:

String pagina = 

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)"
      " con el micro ESP8266"
    "</h3>"
  "<html>";

pero esto es equivalente a escribir todo en una sola línea (si bien acá aparece en 3, es por el formato de la página):


String pagina= "<!DOCTYPEhtml><html><head><title>Tutorial de 

servidor web</title></head><h3>Esto es un servidor web (de ejemplo)

con el micro ESP8266</h3><html>";

Cuál de las dos formas se use va a quedar a su gusto, para mi se ve más claro de la primera forma porque tiene una estructura tabulada y ordenada, lo que lo hace más fácil de visualizar.

Luego de definir la página web, vamos a dar inicio al programa, inicializando el puerto serie (cambiar la velocidad acá no infiere en nada) e inicializar la conexión a la red wifi predefinida, esperamos a que se conecte y damos notificación por el puerto serie de que se conectó a la red deseada y dejamos la dirección IP que el router le asignó. Todo esto básico y ya lo hicimos en otro post.

A continuación tenemos la siguiente porción de código (cuya sintaxis no es la normal):

  servidorweb.on("/", []()
  {
    servidorweb.send(200, "text/html", pagina);
  });

acá lo que estamos haciendo es indicarle al servidor cómo responder ante el "llamado" del cliente bajo la ruta "/", en este caso el servidor va a ejectuar la línea:

servidorweb.send(200, "text/html", pagina);

y lo que va a hacer es enviar como respuesta la página que tenemos almacenada en la variable "pagina" (vale aclarar que en lugar de poner "/" podríamos poner "/encender" y vamos a usar esa otra ruta, incluso podríamos declarar ambas, más adelante hablaremos de ello en más detalle). Una vez indicado cómo tiene que respoder podemos dar inicio al servidor web bajo el comando:

servidorweb.begin();

En el loop lo que tenemos que hacer es revisar constantemente si hay algún cliente esperando, y esto lo vamos a hacer con la siguiente línea:

servidorweb.handleClient();

Esta última línea debemos llamarla constantemente para que se manejen los clientes de forma regular.

domingo, 9 de julio de 2017

Sensor de humedad HIH-4000

Hoy les traigo el sensor de humedad HIH-4000, cuenta con una resolución de 31.483 mV por cada porcentaje de humedad relativa. Sus aplicaciones van desde la meteorología hasta (según la hoja de datos) equipamientos médicos.
Si se mira de frente (con la parte expuesta hacia nosotros) tenemos a la izquierda masa, en el centro la tensión de salida y a la derecha vcc. Se alimenta con 5V y entre el pin que va a masa y el de salida deberíamos agregarle una resistencia de 80Kohms.

El sensor recuadrado en rojo es la parte expuesta, y de
izquierda a derecha tenemos: GND, Salida, VCC
Este sensor tiene una respuesta bastante lineal, por lo que podemos tomar desde 0% hasta el 100% de humedad el incremento de la tensión que mencioné más arriba, pero para una humedad relativa de 0% tenemos 0,826V
A continuación les dejo un breve programa capaz de manejar los datos.

void setup()
{
  Serial.begin(9600);
}

void loop() 
{
  int humedad = 0, vout = 0;
  vout = analogRead(a0);
  humedad = ((vout - 0.826)/0.0315);
  Serial.println(humedad);  
}

Como el sensor se alimenta con 5V y tiene una tensión de salida que varía entre 0V y casi 4V es difícil implementarlo de forma directa (es decir sin ningún circuito adicional) con el microcontrolador ESP8266, recordemos que este micro se alimenta con 3,3V y es capaz de "leer" tensiones analógicas de hasta 1V. Con esto en mente, si alimentamos nuestro ESP8266 con 5V que luego regulamos, podríamos tomar esa tensión sin regular para alimentar el sensor de humedad, y si al pin de salida le agregamos un divisor resistivo con una atenuación de 1 a 4 podríamos usarlo sin ningún problema en ese microcontrolador. De más está decir que este sensor es de muchísima mejor calidad que la familia DHT.

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):