Wemos D1 mini no siempre manda todos los datos mqtt

Buenas,

Tengo un Wemos d1 mini al que le he conectado una sensor dht22, alimentado con una batería 18650 de la cual monitoreo la tensión con la entrada analógica. Los datos obtenidos del sensor, temperatura y humedad, y la tensión de la batería los mando cada 5 minutos por mqtt (entre mensaje y mensaje el esp8266 entra en modo deep sleep) a un servidor que tengo montado con mosquitto en una raspberry pi3 y a su vez se muestran con node-red en una dashboard y también se guarda en una base de datos mariabd.
El problema que tengo es que algunas veces, bastantes, no me llegan los datos, todos o algunos de ellos. A veces solo se "salta" un envío, cada 5 minutos, y a veces puedo estar media hora, una hora, dos horas o mas sin recibir nada y sin hacer nada vuelvo a recibir.

Mi pregunta, mas que saber porque esta pasando esto, que si alguien lo sabe lo agradeceré, si no mas bien si alguien tiene alguna idea de que puedo hacer para para saber que puede estar pasando. A priori no puedo conectar al monitor serie, el montaje esta en el exterior y me gustaría resolverlo así, que es como debe funcionar.

Este es código

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

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

// Update these with values suitable for your network.

const char* ssid = "xxxxxxxxxxxxxx";
const char* password = "yyyyyyyyyyyyyyyyy";
const char* mqtt_server = "192.168.1.10";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
//definim el DHT
#define DHTPIN D3  //definim al pina al que va conectat
#define DHTTYPE DHT22 //definim el tipus de sensor 
DHT dht(DHTPIN, DHTTYPE); //definim ñes variables per inicialitzar el sensor

void setup_wifi() {

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

  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 reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
    } 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() {
  
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  dht.begin(); //inicialitzem el sensor
  if (!client.connected()) 
    reconnect();
  client.loop();
    float h = dht.readHumidity(); //llegim i guardem a h la humitat relativa
    float t = dht.readTemperature();  //llegim i guardem a f la temperatura
    int b= analogRead(A0);
    float bat=2*(b*(3.1/1033.0));
    Serial.println("Publish message: ");
    Serial.print("Temperatura: ");
    Serial.print(String(t));
    Serial.println("ºC");
    Serial.print("Humitat: ");
    Serial.print(String(h));
    Serial.println("%");
    Serial.print("b= ");
    Serial.println(b);
    Serial.print("bat= ");
    Serial.println(bat);
    char t_out[8];
    char h_out[8];
    char bat_out[8];
    dtostrf(t, 6, 2, t_out);  //convertim el float en una array chart per poder enviarla
    snprintf (msg, 50, t_out); //creem el missatge a enviar
    client.publish("/casa/exterior/temp",msg); //Publiquem el missatge al topic corresponent
    dtostrf(h, 6, 2, h_out);  //convertim el float en una array chart per poder enviarla
    snprintf (msg, 50, h_out);  //creem el missatge a enviar
    client.publish("/casa/exterior/hum",msg); //Publiquem el missatge al topic corresponent
    dtostrf(bat, 6, 2, bat_out);  //convertim el float en una array chart per poder enviarla
    snprintf (msg, 50, bat_out);  //creem el missatge a enviar
    client.publish("/casa/exterior/bat",msg); //Publiquem el missatge al topic corresponent
    delay(1000);
    ESP.deepSleep(300000000, WAKE_RF_DEFAULT);
}

void loop() {

}

El código aun tengo que pulirlo....

He buscado en google mucho, pero no acabo de encontrar información con este problema.

Espero que me haya explicado bien, en todo caso si alguien quiere saber mas, que no dude en pedir mas info.

Adjunto también imagen del montaje

El problema es el DHT22 y es algo que alguien hace poco tiempo trajo para comentar y luego varios descubrimos que nos pasaba y no advertíamos la causa. No recuerdo quien, pero otro forero sugirió que como a el le sucedía tambien, la única solución que encontró fue alimentarlo con un pin del Arduinoy cuando detecta falla lo reinicia y eso hace que funcione y se reestablezcan las lecturas.
Yo tmb tengo un sistema Hassio o Home Assitant y me pasa lo mismo. Tuve que hacer lo mismo. Cuando no lee datos, hago un pulso a LOW del pin que esta conectado al VCC del DHT22 y lo reinicio y a los 2 segundos responde.

Creo que es este hilo Sensor DHT22 se tiene que reiniciar para que marque temperatura

Extraigo la solución que te va a servir

John_Florian:
Saludos a todos, tengo una solución a dicho problema. El sensor en sí debe de recibir energía unos segundos despues para que el microcontrolador lo detecte. Lo que hice fue utilizando un Nodemcu es controlarlo por una de sus salida dándole un delay con millis de 2 o más segundos para poner esa salida en "HIGH" luego coloque una resistencia Pull Up de 220 ohm desde los 3.3v a el pin que determinemos como salida, ya que la potencia que brinda uno de esos pines no es suficiente para que trabaje estable. Probando sin la resistencia me di cuenta que cuando presionas el botón de reset funciona bien pero al quitarle la alimentación daba un error, para compensar esa caída de tensión utilice la resistencia de 220 ohm desde los 3.3v a el pin que determinemos como salida con el delay.

Primero gracias por la rápida respuesta.

En realidad este no es el problema que tengo, aunque es bueno saberlo, el DHT lo tengo siempre alimentado y algunas de las veces que no me llegan todos los datos, el único dato que me llega es el de la temperatura y de todas formas si el problema fueran los datos del dht, el dato de la tensión de batería si debería llegarme y en muchos casos no lo hace.

esto es, en bruto, lo que llega al servidor mosquitto, donde se ve lo que te comento:

2020-4-10 17:54:15
 22.00
 56.10
  4.22
2020-4-10 17:59:15
2020-4-10 18:4:15
 22.20
 57.20
  4.20
2020-4-10 18:9:15
 22.00
 56.40
  4.21
2020-4-10 18:14:15
 21.60
2020-4-10 18:19:15
 21.50
 57.80
  4.20
2020-4-10 18:24:15
 21.50
 58.80
  4.20
2020-4-10 18:29:15
 21.30
2020-4-10 18:34:15
 21.30
 58.10
  4.21
......
2020-4-10 20:39:15
 18.90
 76.40
  4.16
2020-4-10 20:44:15
2020-4-10 20:49:16
 19.00
 76.10
  4.16
2020-4-10 20:54:16
2020-4-10 20:59:16
2020-4-10 21:4:16
2020-4-10 21:9:16
 18.90
 77.00
  4.13
2020-4-10 21:14:16
2020-4-10 21:19:16
 18.90
 75.40
  4.14
2020-4-10 21:24:16

Entre cada marca de tiempo debería haber 3 valores, temperatura, humedad y tensión de batería, respectivamente. Pero en algunos casos o no recibe nada o solo la temperatura. Por ejemplo entre las 18:14 y las 18:19 solo hay temperatura, igual que entre 18:29 y 18:34 o 18:54 y 18:59, entre otros y luego hay momentos como por ejemplo de 20:54 a 21:09, entre otros, que no recibe nada y luego vuelve a recibir normal.

Creo que así queda mejor explicado, no tenía muy claro como explicarlo...

adjunto el archivo de los datos en bruto que recibe el mosquitto, por si son de interés.

log-exterior-10-04-2020.txt (3.19 KB)

Hi,
En la foto se ve que estas usando un protoboard. Esta usando el protoboard o es solamente para demostrar como esta alambrado.

La imagen es la que hice cuando lo monte primero en la protoboard, ahora no esta en la protoboard, esta montado en una placa soldado. No tengo fotos del montaje final.

Hi,
Cuando puedas baja una foto. Que tipo de tarjeta usas. son de las que son de las que montas los componentes y son soldable o es una tarjeta "PCB" hecha especial para tu projecto.

Es una placa de prototipos, en cuanto pueda subo una foto.

Hi,
La razon de ver como eata montado es que algunas veces olvidadn anadirle condesadores y esto te puede traer problemas de ruido. Al sensor yo le anadiria un condensador de como 10uf y otro de .1uf en paralelo a se conectas a los 5 voltios. Esto te elimina ruidos que se puedan producir en la tarjeta.

No he puesto condensadores, aunque viendo lo que me dices los pondré. De todas formas no creo que ese sea el problema, porque mando 3 datos, 2 del dht y otro (la tensión de la batería) que entra al pin analógico del wemos, entiendo que si fuera problema del sensor me fallarían unos datos u otros, pero no todos, o solo uno de los que me da es dht... La verdad es que estoy un poco perdido, no se por donde puede venir...
No he entendido muy bine como conector los condesadores que me comentas, entiendo que el de 10uf entre la señal y la alimentación del sensor, es así? y el de .1uf no entiendo donde tendría que ponerlo, entre los 5V y la GND?

Hi,
El de .1uf esta en paralelo al de 10uf. En oras palabras los conectas los dos a los pines de grund y al de lo5 voltios. Si lo entiendo tu esta usando baterias para alimentar el sensor y el micro. Esto es correcto.

snprintf (msg, 50, t_out); //creem el missatge a enviar
client.publish("/casa/exterior/temp",msg);

Porque usas una variables de 50 chars para enviar solo 8?

EDITO: Veo que la librería sugiere ese tamaño de buffer. Asi que mi consulta no tiene sentido.

surbyte:
Porque usas una variables de 50 chars para enviar solo 8?

Usé un ejemplo que tenia chars de 50 y así se quedo de momento. Aun tengo que pulir el código, pero como así me funcionaba bien lo deje así, cuando ya este funcionando bien al 100%, me dedicare a limpiar el código.

tauro0221:
Hi,
El de .1uf esta en paralelo al de 10uf. En oras palabras los conectas los dos a los pines de grund y al de lo5 voltios. Si lo entiendo tu esta usando baterias para alimentar el sensor y el micro. Esto es correcto.

Estoy usando una batería 18650 con un cragador TP5046, que se carga con una placa solar y un booster de 5V para alimentar el circuito. Estoy a la espera que me llegue una DC-DC de 1,9-5V a 3,3V para alimentar todo a 3,3V y eliminar el booster, esta consumiendo todo el tiempo y si puedo usar 3,3V creo que no tiene mucho sentido usarlo.

Adjunto una foto del montaje, aun no tiene los condensadores, pero se los voy a montar ahora, en la foto no ve el sensor porque va montado por fuera de la caja, conecta en la tira de 4 pines hembra que hay en un lateral. Agradeceré cualquier otro comentario que me ayude a dejarlo mejor.

De nuevo gracias por las respuestas.

Para mi nada tiene que ver los condensadores. Pero prueba.
Lo que te pasa a ti es exactamente lo que me pasa a mi. Tengo mi sistema muy parecido.
Envía datos MQTT y de tanto en tanto 1 día o dia y medio deja de hacerlo. Si lo desconectas vuelve a funcionar.
Solución lo que te puse antes.

Ahora le agregué el Deep_Sleep o sea de modo similar a tu caso.

A tu código le falta información en el loop, el ejemplo similar de la librería viene con esto

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("outTopic", msg);
  }
}

Dejemos de lado que envia Hello world y un valor y que lo hace cada 2 segundos.
En tu caso lo duermes pero no veo la rutina que envia y lo reinicia.

He puesto los 2 condensadores, en principio me iba bien, pero hace poco ha vuelto a fallar, se ha perdido un envío de todos los datos, de todas formas como parece que siempre es bueno poner los C no vienen mal.

En realidad el código que dices que falta esta en el setup en vez de en el loop, vi un par de ejemplos buscando info y me pareció una buena idea, de hecho nunca llega a entrar en el loop, al final del setup entra en modo deepsleep.

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  dht.begin(); //inicialitzem el sensor
  if (!client.connected()) 
    reconnect();
  client.loop();
    float h = dht.readHumidity(); //llegim i guardem a h la humitat relativa
    float t = dht.readTemperature();  //llegim i guardem a f la temperatura
    int b= analogRead(A0);
    float bat=2*(b*(3.1/1033.0));
    Serial.println("Publish message: ");
    Serial.print("Temperatura: ");
    Serial.print(String(t));
    Serial.println("ºC");
    Serial.print("Humitat: ");
    Serial.print(String(h));
    Serial.println("%");
    Serial.print("b= ");
    Serial.println(b);
    Serial.print("bat= ");
    Serial.println(bat);
    char t_out[8];
    char h_out[8];
    char bat_out[8];
    dtostrf(t, 6, 2, t_out);  //convertim el float en una array chart per poder enviarla
    snprintf (msg, 50, t_out); //creem el missatge a enviar
    client.publish("/casa/exterior/temp",msg); //Publiquem el missatge al topic corresponent
    dtostrf(h, 6, 2, h_out);  //convertim el float en una array chart per poder enviarla
    snprintf (msg, 50, h_out);  //creem el missatge a enviar
    client.publish("/casa/exterior/hum",msg); //Publiquem el missatge al topic corresponent
    dtostrf(bat, 6, 2, bat_out);  //convertim el float en una array chart per poder enviarla
    snprintf (msg, 50, bat_out);  //creem el missatge a enviar
    client.publish("/casa/exterior/bat",msg); //Publiquem el missatge al topic corresponent
    delay(1000);
    ESP.deepSleep(300000000, WAKE_RF_DEFAULT);
}

void loop() {

}

Con este código y un puente entre D0 y RST para que se "despierte" pasado el tiempo, en mi caso 5 minutos, me funciona perfecto, bueno quitando el problema que nos ocupa, que tampoco es muy grabe, pero tengo curiosidad por saber porque puede estar pasando...

Me he dado cuenta que parece que falla mas al final del día y de madrugada, cuando la temperatura es mas baja, pero también falla durante el día, así que no creo que sea el problema.

Me acabao de dar cuenta que los comentarios del código no están en español, creo que se entiende, pero si no fuera el caso y alguien quiere saber algo en concreto le traduzco lo que necesite saber.

Hi,
Una cosa que yo veo que cuando to inicializa el DT22 no tiene un delay antes de leerlo. Si mas no recuerdo alguien recomendaba del delay pero no he podido encontrar el link pero yo hice uno reloj que te da la hora, la temepratura y tuve que anadirle el delay. Trata de anadirle el delay cuando el micro despierta. Otra cosa es que hay otra prueba que se le hace al sensor una vez que lo inizializas. Voy a tratar de encontrar el sketch y te lo paso para que lo trates para ver si resuelve tu problema..

Le pondré un delay, pero no creo que resuelva, porque entiendo que si fuera problema del sensor, le dato de la tensión de batería si que lo tendría que mandar siempre, a no ser que el sensor me dejara el wemos totalmente colgado, que no creo...

Espero al sketch que me comentas para cambiar el código todo de una vez.

También había pensado, aunque creo que no tiene mucho sentido, que tengo al final justo antes de pasar a deepsleep un delay de 1s, quizás podría ponerlo de mas por si algo esta a medias, pero entiendo que si llega hasta allí es porque todo lo anterior ya lo ha acabado, por eso creo que no tiene ningún sentido. Que pensáis?

Hasta ahora desde que he puesto los C solo me ha fallado una vez y antes en este tiempo ya habría fallado varias veces, parece que los C algo han mejorado. Mañana con toda la noche grabando sabre si realmente ha mejorado o no.

Hi,
Encontre el sketch que es escrito por "Written by ladyada, public domain" yo soy un seguidor de el y con este sketch nunca he tenido problemas.Otra cosa es que el traata de recobrar si falla al leer el sensro y si falla te da un mesaje. Esto te ayuda en para determinar si el sensor falla.

Es una buena practica de siempre anadirle un condensador de por lo menos de 470uf al voltaje Vcc y uno de .1uf lo mas cercano posible a los pines del Vcc y ground del microprocessor. Ahora mismo en tu tarjeta no tiene ninguno posiblemente no resuelva tu problema perro siempre es buena practica como ya lo he mencionado.

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

// REQUIRES the following Arduino libraries:
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// - Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

#include "DHT.h"

#define DHTPIN 2     // Digital pin connected to the DHT sensor
// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --
// Pin 15 can work but DHT must be disconnected during program upload.

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  Serial.println(F("DHTxx test!"));

  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));
}

No sabia que los C tenía que ponerlos cerca de los pines de alimentación y sin querer los he puesto pegados a los pines, así que perfecto! Gracias.

Mañana probare de modificar el código con el sketch que me has pasado y ya os contare.

Gracias

Hi,
Adjunto una foto de una de las tarjetas que yo diseno y las mando hacer a EpressPCB. Es para que te sirva de ejemplo para la proxima vez que tenga que hacer una tarjata tomes en consideracion los condesadores y para que el uso de ellos. En ella puedes ver los condesadores. La tarjeta tiene su puente y le sigue un condensador, va al regulador de 5 voltios, un condensador para filtrar el voltaje de 5 voltios.y Le sigue el regulador de 3.3 voltios al final otro condensador de filtro. Ambos reguladores son the 5 amperios y estan montados en un heatsink. Tambien puedes ver el condesador de .1uf en los pines de Vcc y ground. Los condensadores tienen sus propositos y depende donde los usas.

Buenas,

A ver, ya he implementado el delay de 2s entre la inicialización de DHT y la lectura del mismo y tambien he implementado la detección del error de lectura, cuando falle me va a mandar un mqtt que también voy a guardar en la BBDD y así tengo controlado cuando falla.

dht.begin(); //inicialitzem el sensor
  if (!client.connected()) 
    reconnect();
  client.loop();
    delay (2000);
    float h = dht.readHumidity(); //llegim i guardem a h la humitat relativa
    float t = dht.readTemperature();  //llegim i guardem a f la temperatura
    if (isnan(h) || isnan(t)) {
    //Serial.println(F("Failed to read from DHT sensor!"));
    snprintf (msg, 50, "1");  //creem el missatge a enviar
    client.publish("/casa/exterior/errorDHT",msg); //Publiquem el missatge al topic corresponent
    //return;
    }

De todas formas, no se si por poner los C o simplemente por haber tocado, pero he pasado de una media de 13 fallos al día a 3 ayer y 1 hoy en lo que llevamos de día, así que algo ya ha mejorado. Veremos con todas las mejoras si elimino o no el problema. me he hecho un excel para controlar mejor los fallos con los datos de la BBDD. Ya os contare.