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
- I am slightly allergic to global variables
- 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 returntrue
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 anif
inprepareJsonObject()
that runsmeasure_environment()
, and because of the timer inmeasure_environment()
it could well returnfalse
there, because the timer isn't ready yet.I suspect it is not
dht_sensor.measure()
that returnsfalse
, but thatmeasure_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
orfalse
: the sensor not working, or the timer not being ready.