Electronic – Why does making this change to the DHT11 code cause it not to work

cesp8266sensor

Note: This might not be a programming question. If it turns out that it is, I will close it.

I am using an ESP8266 to build some air quality web servers.
One of the sensors I am using is the DHT11 (temperature and humidity).
I have some working code that relies on global variables and I want to convert it into code that does not use globals.
Initially I just rewrote everything using code that, as far as I can tell, is perfectly valid. Then the sensor did not work. So I decided to modify the working code step by step to see which change causes it to fail. The code failed on the very first change!

I am no C expect, but what I have done seems pretty innocuous. For this reason, I don't think this is a programming question, but rather a question about some (unknown to me) quick with the DHT11.

Working code:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h> 
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <dht_nonblocking.h>
#define DHT_SENSOR_TYPE DHT_TYPE_11

ESP8266WiFiMulti wifiMulti; 
ESP8266WebServer server(80);

static const int DHT_SENSOR_PIN = 12;
DHT_nonblocking dht_sensor( DHT_SENSOR_PIN, DHT_SENSOR_TYPE );

static float global_temp;
static float global_humidity;
static unsigned long global_dht_measure_time = millis( );

static bool measure_environment( float *temperature, float *humidity )
{
  /* Measure once every 3 seconds. */
  if( millis( ) - global_dht_measure_time > 3000ul )
  {
    if( dht_sensor.measure( temperature, humidity ) == true )
    {
      global_dht_measure_time = millis( );
      return( true );
    }
  }

  return( false );
}

String prepareJsonObject()
{

  String res =
    String("{") +
    "\"Temperature\": " + String(global_temp) + "," +
    "\"Humidity\": " + String(global_humidity) + "," +
    "\"MeasureTime\": " + String(millis( ) - global_dht_measure_time) +
    "}";

  return res;
}

void handleRoot() {
  Serial.println("Handling Root");
  server.send(200, "application/json", prepareJsonObject());
}

void handleNotFound(){
  server.send(404, "text/plain", "404: The requested page was not found");
}

void setup(void){
  Serial.begin(115200);
  delay(10);
  Serial.println('\n');

  wifiMulti.addAP("ssid", "***");

  Serial.println("Connecting ...");
  int i = 0;
  while (wifiMulti.run() != WL_CONNECTED) {
    delay(250);
    Serial.print('.');
  }
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID()); 
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("AirSensor1")) {
    Serial.println("mDNS responder started");
  } else {
    Serial.println("Error setting up MDNS responder!");
  }

  server.on("/", HTTP_GET, handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
//  Serial.println("Entering loop");
  if( measure_environment( &global_temp, &global_humidity ) == true )
  {
    Serial.print( "T = " );
    Serial.print( global_temp, 1 );
    Serial.print( " deg. C, H = " );
    Serial.print( global_humidity, 1 );
    Serial.println( "%" );
  }
  server.handleClient();
  MDNS.update();
//  Serial.println("Exiting loop");
}

Not working code:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h> 
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <dht_nonblocking.h>
#define DHT_SENSOR_TYPE DHT_TYPE_11

ESP8266WiFiMulti wifiMulti; 
ESP8266WebServer server(80);

static const int DHT_SENSOR_PIN = 12;
DHT_nonblocking dht_sensor( DHT_SENSOR_PIN, DHT_SENSOR_TYPE );

static float global_temp;
static float global_humidity;
static unsigned long global_dht_measure_time = millis( );

static bool measure_environment( float *temperature, float *humidity )
{
  Serial.println( "Measuring DHT" );
  /* Measure once every 3 seconds. */
  if( millis( ) - global_dht_measure_time > 3000ul )
  {
    if( dht_sensor.measure( temperature, humidity ) == true )
    {
      global_dht_measure_time = millis( );
      return( true );
    }
    Serial.println( "DHT Failure" );
  }
  return( false );
}

String prepareJsonObject()
{
  if( measure_environment( &global_temp, &global_humidity ) == true )
  {
    Serial.print( "T = " );
    Serial.print( global_temp, 1 );
    Serial.print( " deg. C, H = " );
    Serial.print( global_humidity, 1 );
    Serial.println( "%" );
  }
  String res =
    String("{") +
    "\"Temperature\": " + String(global_temp) + "," +
    "\"Humidity\": " + String(global_humidity) + "," +
    "\"MeasureTime\": " + String(millis( ) - global_dht_measure_time) +
    "}";

  return res;
}

void handleRoot() {
  Serial.println("Handling Root");
  server.send(200, "application/json", prepareJsonObject());
}

void handleNotFound(){
  server.send(404, "text/plain", "404: The requested page was not found");
}

void setup(void){
  Serial.begin(115200);
  delay(10);
  Serial.println('\n');

  wifiMulti.addAP("ssid", "***");

  Serial.println("Connecting ...");
  int i = 0;
  while (wifiMulti.run() != WL_CONNECTED) {
    delay(250);
    Serial.print('.');
  }
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID()); 
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("AirSensor1")) {
    Serial.println("mDNS responder started");
  } else {
    Serial.println("Error setting up MDNS responder!");
  }

  server.on("/", HTTP_GET, handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
  //Serial.println("Entering loop");

  server.handleClient();
  MDNS.update();
  //Serial.println("Exiting loop");
}

In both cases, the web server starts up fine, but the modified code returns zeros (the initial values) for temp and humidity. This is because the call to 'dht_sensor.measure' fails and returns false so the values are not updated.

All I did is change the location of the call to 'measure_environment' to the function that handles the root request, rather than the main loop. The expected effect being that the sensor only gets used when a client is asking for the data. For some reason this causes the sensor not to work.

My initial thought was that the sensor library requires frequent calls to measure but then that was refuted when I changed to working code measurement interval to 1 minute, and everything worked fine.

Yes, I can simply use the working code and forget about it but

  1. I am slightly allergic to global variables
  2. I just want to know what I have done to upset the DHT11!

Best Answer

I'll have a belated go:

The measure_environment() function has a timer in it, so it will not return true and set values on every call, but only for one call out of all calls during three seconds.

Having it at the top of the loop() guarantees it will do its job every three seconds, and after the first three seconds the variables will always be set to something.

In the version where you call it from handleClient(), handleRoot(), prepareJsonObject(), there is an if in prepareJsonObject() that runs measure_environment(), and because of the timer in measure_environment() it could well return false there, because the timer isn't ready yet.

I suspect it is not dht_sensor.measure() that returns false, but that measure_environment() does.

Anyway, I don't think it is a good idea to have the timer in the function itself, as the calling code can't tell what the reason is for the function's returning true or false: the sensor not working, or the timer not being ready.

Related Topic