En este post te mostraré cómo leer la temperatura y humedad del sensor DHT22 usando la tarjeta ESP8266 para más tarde enviarla a un servidor MQTT.
Del mismo modo vamos a suscribirnos a un tópico y encenderemos o apagaremos un led dependiendo del mensaje recibido.
Requisitos
Esto es parte de una serie de posts que vengo haciendo sobre el internet de las cosas con ESP8266.
Te recomiendo leer cómo usar el DHT22 con la ESP8266, y del mismo modo te invito a ver una comunicación simple a través de MQTT con la Raspberry y la tarjeta NodeMCU ESP8266.
Este post es más que nada una unión de ambos posts, así que te recomiendo ampliamente que leas lo anterior mencionado.
Circuito
Debido a que vamos a encender y apagar el LED que la tarjeta ya trae, no necesitamos conectar algo externo. Lo que sí necesitamos es conectar el sensor:
Lo demás se hará por WiFi.
Enviar temperatura y humedad por MQTT
Cada 2 segundos vamos a estar leyendo los valores del sensor y los vamos a publicar así:
// Si han pasado más de 2 segundos desde la última vez, enviar un mensaje
if (millis() - ultimaVez > TIEMPO_ESPERA)
{
humedad = sensor.readHumidity();
temperaturaEnGradosCelsius = sensor.readTemperature();
// En ocasiones puede devolver datos erróneos; por eso lo comprobamos
if (isnan(temperaturaEnGradosCelsius) || isnan(humedad))
{
ultimaVez = millis();
return;
}
// Formatear la temperatura y humedad
sprintf(mensaje, "Temperatura: %.2f. Humedad: %.2f", temperaturaEnGradosCelsius, humedad);
clienteMqtt.publish("jardin/temperatura", mensaje);
ultimaVez = millis();
}
Estoy usando la función sprintf
porque necesito concatenar los valores de una forma sencilla, y no quiero usar strcat
o cosas de esas.
Encender o apagar led por MQTT
Por otro lado, vamos a ver las funciones que permitirán que, dependiendo del mensaje recibido, se apague o encienda un LED:
/*
No tengo idea, pero parece que está invertido y al escribir un HIGH
se apaga
Relaciondo: https://github.com/nodemcu/nodemcu-devkit-v1.0/issues/16
*/
void apagarLed()
{
digitalWrite(PIN_LED, HIGH);
}
void encenderLed()
{
digitalWrite(PIN_LED, LOW);
}
// La función que será llamada cuando se reciba un
// mensaje en el tópico al que nos vamos a suscribir
void callback(char *topico, byte *cargaUtil, unsigned int longitudDeDatos)
{
if (longitudDeDatos <= 0)
return;
char primerCaracter = (char)cargaUtil[0];
if (primerCaracter == '0')
apagarLed();
else if (primerCaracter == '1')
encenderLed();
}
Lo que necesitamos en el mensaje es un 1 o un 0 y dependiendo de ello se apagará o encenderá el LED.
Código fuente completo
Ahora veamos el código fuente completo. Te repito de nuevo que deberías leer los posts que menciono anteriormente, pues aquí solo los estoy uniendo:
/*
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
Blog: https://parzibyte.me/blog
Ayuda: https://parzibyte.me/blog/contrataciones-ayuda/
Contacto: https://parzibyte.me/blog/contacto/
Copyright (c) 2020 Luis Cabrera Benito
Licenciado bajo la licencia MIT
El texto de arriba debe ser incluido en cualquier redistribucion
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "DHT.h"
#define NOMBRE_RED "parzibyte"
#define PASSWORD_RED "hunter2"
#define DIRECCION_SERVIDOR_MQTT "192.168.1.79"
#define PUERTO_SERVIDOR_MQTT 1883
#define USUARIO_MQTT "" // En mi caso es vacío
#define PASSWORD_MQTT "" // En mi caso es vacío
#define TIEMPO_ESPERA 2000 // Cada cuánto leer del sensor
/*
Nota importante: si usas el pin D8 (como lo recomiendo)
recuerda desconectar el lector del mismo cada vez que reinicies
o quieras subir el código, pues el mismo "interfiere" con el
monitor serial
*/
#define PIN_CONEXION D8 // A cuál pin está conectado el lector
#define TIPO_SENSOR DHT22 // Puede ser DHT11 también
#define PIN_LED LED_BUILTIN
DHT sensor(PIN_CONEXION, TIPO_SENSOR);
WiFiClient clienteWiFi;
PubSubClient clienteMqtt(clienteWiFi);
// El mensaje que se envía al servidor. Debe ser lo suficientemente
// grande
char mensaje[500] = "";
int ultimaVez = millis(); // Para enviar cada X segundos pero sin usar delay
float humedad, temperaturaEnGradosCelsius = 0;
/*
No tengo idea, pero parece que está invertido y al escribir un HIGH
se apaga
Relacionado: https://github.com/nodemcu/nodemcu-devkit-v1.0/issues/16
*/
void apagarLed()
{
digitalWrite(PIN_LED, HIGH);
}
void encenderLed()
{
digitalWrite(PIN_LED, LOW);
}
// La función que será llamada cuando se reciba un
// mensaje en el tópico al que nos vamos a suscribir
void callback(char *topico, byte *cargaUtil, unsigned int longitudDeDatos)
{
if (longitudDeDatos <= 0)
return;
char primerCaracter = (char)cargaUtil[0];
if (primerCaracter == '0')
apagarLed();
else if (primerCaracter == '1')
encenderLed();
}
void setup()
{
pinMode(PIN_LED, OUTPUT);
apagarLed();
sensor.begin();
// Conexión WiFi
WiFi.begin(NOMBRE_RED, PASSWORD_RED);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
}
// Y ahora intentamos conectarnos al servidor MQTT
clienteMqtt.setServer(DIRECCION_SERVIDOR_MQTT, PUERTO_SERVIDOR_MQTT);
// Establecer la función que se invoca al recibir mensajes
clienteMqtt.setCallback(callback);
while (!clienteMqtt.connected())
{
if (!clienteMqtt.connect("ClienteESP8266", USUARIO_MQTT, PASSWORD_MQTT))
{
delay(2000);
}
}
// Después de habernos conectado al servidor MQTT nos suscribimos
clienteMqtt.subscribe("casa/sala/iluminacion");
}
// Ahora viene el loop, al cual se entra en caso de que en el setup
// todo haya ido bien
void loop()
{
// Procesar los mensajes entrantes en caso de que existan
clienteMqtt.loop();
// Si han pasado más de 2 segundos desde la última vez, enviar un mensaje
if (millis() - ultimaVez > TIEMPO_ESPERA)
{
humedad = sensor.readHumidity();
temperaturaEnGradosCelsius = sensor.readTemperature();
// En ocasiones puede devolver datos erróneos; por eso lo comprobamos
if (isnan(temperaturaEnGradosCelsius) || isnan(humedad))
{
ultimaVez = millis();
return;
}
// Formatear la temperatura y humedad
sprintf(mensaje, "Temperatura: %.2f. Humedad: %.2f", temperaturaEnGradosCelsius, humedad);
clienteMqtt.publish("jardin/temperatura", mensaje);
ultimaVez = millis();
}
delay(10);
}
Los tópicos son:
Para recibir mensajes casa/sala/iluminacion
Para enviar mensajes jardin/temperatura
Probando
En caso de que todo vaya bien, podemos controlar el LED desde el servidor. Se enciende con:
mosquitto_pub -h localhost -t "casa/sala/iluminacion" -m "1"
Y se apaga con:
mosquitto_pub -h localhost -t "casa/sala/iluminacion" -m "0"
Por otro lado, si nos suscribimos al tópico de la temperatura, debemos ver algo así:
Y así es como podemos conectar todavía más cosas usando este protocolo.
Por cierto, si no sabes cómo configurar mosquitto en la Raspberry mira este post.
Hola, gracias por el articulo, segui los pasos que mencionas en este articulo y la verdad que el esp8266 funciona de maravillas, ahora bien,
Como se soluciona, el inconveniente de:
/*
Nota importante: si usas el pin D8 (como lo recomiendo)
recuerda desconectar el lector del mismo cada vez que reinicies
o quieras subir el código, pues el mismo “interfiere” con el
monitor serial
*/
Ya que cada cierto tiempo debo desconectar el pin D8 para que vuelva a comunicarse, lo que representa un inconveniente. Muchas Gracias
Use otro pin o desconéctelo cada que reinicie o quiera subir el código