Enrique Albertos
Published © LGPL

DHT11 Arduino Library and ThingSpeak

DHT11 Temp and Humidity library from scratch to send data to ThinkSpeak with an AZDelivery ESP8266 ESP-12F NodeMCU Lua Amica V2

BeginnerFull instructions provided1 hour250
DHT11 Arduino Library and ThingSpeak

Things used in this project

Hardware components

AZDelivery ESP8266 ESP-12F NodeMCU Lua Amica V2
×1
AZ-Delivery Logic Analyzer
×1
AZ-Delivery DHT11 Breakout Module
×1
DHT11 Temperature & Humidity Sensor (4 pins)
DHT11 Temperature & Humidity Sensor (4 pins)
×1
Resistor 10k ohm
Resistor 10k ohm
×1

Software apps and online services

ThingSpeak API
ThingSpeak API
PulseView
Arduino IDE
Arduino IDE

Story

Read more

Schematics

Schematics

Schmatics image

Schematics fritzing

Code

ESP8266DHT11.ino

C/C++
Reads Relative Humidity and Temperature from a DHT11 sensor and writes it to a ThinkSpeak cloud service
/**
  Name: esp8266DHT11
  Purpose: Reads Relative Humidity and Temperature from a DHT11 sensor
  and writes it to a ThinkSpeak cloud service

  @author Enrique Albertos
  @version 1.0 25/10/2020
*/

#include "DHT11.h"

#include "ThingSpeak.h"
#include "secrets.h"
#include <ESP8266WiFi.h>

// DHT11 sensor
DHT11 dht11;


// ThingSpeak connection
char ssid[] = SECRET_SSID;   // your network SSID (name)
char pass[] = SECRET_PASS;   // your network password
unsigned long myChannelNumber = SECRET_CH_ID;  // your channel number
const char * myWriteAPIKey = SECRET_WRITE_APIKEY; // your channel write API Key

WiFiClient  client;

void setup()
{
  Serial.begin(115200); // for debugging
  // Begin ThinkSpeak connection
  WiFi.mode(WIFI_STA);
  ThingSpeak.begin(client);  // Initialize ThingSpeak

  Serial.println();
  Serial.println("Status\tHumidity (%)\tTemperature (C)");

  // Initialize DHT11 sensor
  dht11.setup(D1);   // sensor in D1
}

void loop()
{
  checkWifiConnection();
  DHT11::Dht11_data_type sensorData = dht11.readSensor();
  logData(&sensorData);
  if (DHT11::ERROR_NONE == sensorData.error) {
     sendDataToThingSpeak(&sensorData);
  }
  delay(120000); // Wait 120 seconds to update the channel again
}

/*
 * Check if wifi is connected
 * if not reconnect
 * 
 * @params void
 * @retun void
 */
void checkWifiConnection(void) {
  // Connect or reconnect to WiFi
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(SECRET_SSID);
    while (WiFi.status() != WL_CONNECTED) {
      WiFi.begin(ssid, pass);  // Connect to WPA/WPA2 network.
      Serial.print(".");
      int counter = 0;
      // wait for connection established
      while ((WiFi.status() != WL_CONNECTED ) && (counter < 10)) {
        delay(1000);
        counter++;
      }
    }
    Serial.println("\nConnected.");
  }
}

/*
 * Sends sensor data to Thing speak
 * 
 * @params sensor data record reference
 * @retun void
 */
void sendDataToThingSpeak(DHT11::Dht11_data_type *sensorData) {
  // Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different
  // pieces of information in a channel.  Here, we write to field 1.
  ThingSpeak.setField(1, sensorData->temperature);
  ThingSpeak.setField(2, sensorData->humidity);
  int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
  if (x == 200) {
    Serial.println("Temp Channel update successful.");
  }
  else {
    Serial.println("Problem updating temp channel. HTTP error code " + String(x));
  }
}

/*
 * Logs sensor data to serial log
 * 
 * @params void
 * @retun void
 */
void logData(DHT11::Dht11_data_type *sensorData){
  Serial.print(sensorData->status);/* status of communication */
  Serial.print("\t");
  Serial.print(sensorData->humidity, 0);
  Serial.print("\t\t");
  Serial.println(sensorData->temperature, 2);
}

DHT11.h

C/C++
DHT11 sensor library header
DHT11 Temperature & Humidity Sensor library for Arduino.

Features:
- Support for DHT11
/******************************************************************
  DHT Temperature & Humidity Sensor library for Arduino.

  Features:
  - Support for DHT11

  @author Enrique Albertos
  @version 1.0 25/10/2020
  Changes:
   2020-10-24: Initial version

 ******************************************************************/

#ifndef dht11_h
#define dht11_h
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif

class DHT11
{
  public:
    typedef enum {
      ERROR_NONE = 0,
      ERROR_TIMEOUT,
      ERROR_CHECKSUM
    }
    Dht11_error_type;

    struct Dht11_data_type {
      float temperature = NAN;
      float humidity = NAN;
      Dht11_error_type error = DHT11::ERROR_TIMEOUT;
      const char* status = "TIMEOUT ERROR";
    };

    void setup(int pin);

    Dht11_data_type readSensor();

  protected:
    int pin;


  private:

    unsigned long lastReadTime;
    boolean sendStartSignal(void);
    const char *getStatusString(const Dht11_error_type error);

    int busyWait(const int pin, const int finalState, const int timeout);
    boolean waitForStartBit(void);
    boolean waitForStartSignalResponse(void);
    boolean readDht11DataRecord(Dht11_data_type *dataRead);
    uint8_t readByte(const int pin, const int timeoutForStartToTransmitData_us, const int timeoutForData_us,const int bitZeroLength_us);

};

#endif /*dht11_h*/

DHT11.cpp

C/C++
DHT Temperature & Humidity Sensor library for Arduino.

Features:
- Support for DHT11
- returns humidity and temperature decimal values
/******************************************************************
  DHT Temperature & Humidity Sensor library for Arduino.

  Features:
  - Support for DHT11
  - returns humidity and temperature decimal values

  @author Enrique Albertos
  @version 1.0 25/10/2020
  Changelog:
   2020-10-24: Initial version
 ******************************************************************/

#include "DHT11.h"
const uint8_t BIT_MASK[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
const char STATUS_OK[]      = "OK";
const char TIMEOUT_ERROR[]  = "TIMEOUT ERROR";
const char CHECKSUM_ERROR[] = "CHECKSUM ERROR";
const char *statusString[3] = {STATUS_OK, TIMEOUT_ERROR, CHECKSUM_ERROR};

const int timeLengthWakeupSignal_ms = 18; // 18 milliseconds
const int timeoutForResponseSignal_us = 90; // 80us response signal
const int timeoutForStartData_us = 90; // 90us start data
const int timeoutForStartToTransmitData_us = 60; // 50 us start to transmit data
const int timeoutForData_us = 80; // 70 us for "1" bit-data
const int zeroLength_us = 30; // 26-28 us
/////////////////////////////////////////////////////
// PUBLIC METHODS
/////////////////////////////////////////////////////

void DHT11::setup(int pin)
{
  DHT11::pin = pin;
  DHT11::lastReadTime = millis() - 3000;
}

/**
   Read sensor data.

   @param void
   @return Dht11_data_type record with the last reading
*/
DHT11::Dht11_data_type DHT11::readSensor(void)
{
  static Dht11_data_type dataRead;

  // Start communication short circuit is used
  if (sendStartSignal()
      && waitForStartSignalResponse()
      && waitForStartBit()
      && readDht11DataRecord(&dataRead)) {
    return dataRead;
  } else {
    return dataRead;
  }

}

/////////////////////////////////////////////////////
// PRIVATE METHODS
/////////////////////////////////////////////////////

const char *DHT11::getStatusString(const Dht11_error_type error) {
  return statusString[error];
}

/**
   Waits until digital port chanes to final state or timeput occurs

   @param pin to check
   @param state to wait for
   @param maximum time to wait
   @return the elapsed time to reach the final state if less than timeout
   or the elapsed time that forced the timeout

*/
int DHT11::busyWait(const int pin, const int finalState, const int timeout) {
  int elapsedTime = 0;
  int startTime = micros();
  while ( digitalRead(pin) != finalState && elapsedTime < timeout ) {
    elapsedTime = micros() - startTime;
  }
  return elapsedTime;
}

/**
   MCU Sends Start Signal to DHT as this is a blind cycle that makes DHT11
   to change from the low-power-consumption mode to the running-mode

   Consists of a pulse of at least 18 ms voltage-length
   @param void
   @return true if there no problem
*/
boolean DHT11::sendStartSignal(void) {
  digitalWrite(pin, LOW); // MCU Send start signal
  pinMode(pin, OUTPUT);
  delay(timeLengthWakeupSignal_ms); // at least 18 ms
  // MCU Pulls up voltage
  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH); // Switch to receive data
  return true;
}

/**
   Once DHT detects the start signal, it will send out a low-voltage-level
   response signal, which lasts 80us. So we will wait for the DHT11 to be ready.

   @param void
   @return true if there no problem
*/
boolean DHT11::waitForStartSignalResponse(void) {
  return busyWait(pin, LOW, timeoutForStartData_us) < timeoutForStartData_us;
}

/**
   DHT sends oit response signal and keeps it for 80 us
   then DHT pulls up voltage and keeps it for 80 us

   @param void
   @return true if there no problem
*/
boolean DHT11::waitForStartBit(void) {
  if ( busyWait(pin, HIGH, timeoutForResponseSignal_us) < timeoutForResponseSignal_us) { // DHT sends oit response signal and keeps it for 80 us
    return (busyWait(pin, LOW, timeoutForStartData_us) < timeoutForStartData_us); // then DHT pulls up voltage and keeps it for 80 us
  }
  return false;
}

/*
   Read 8 bits in a byte from the line

   @param pointer to the record to be actualized
   @param int pin,
   @param int timeout For Start To Transmit Data in us
   @param int timeout For Data in us,
   @param int bit Zero Length in us
   @return the read byte if any or FF if there is any problem reading
*/
uint8_t DHT11::readByte(const int pin,
                        const int timeoutForStartToTransmitData_us,
                        const int timeoutForData_us,
                        const int bitZeroLength_us) {
  uint8_t data = 0;
  for (int i = 7; i >= 0; i--) {
    if (busyWait(pin, HIGH, timeoutForStartToTransmitData_us) < timeoutForStartToTransmitData_us) { // wait for RAISING
      int bitLength = busyWait(pin, LOW, timeoutForData_us) ; // wait for FALLING
      if (bitLength > timeoutForData_us) {
        return 0xFF;
      }
      if (bitLength > bitZeroLength_us) { // 1 bit value, toggle bit
        data |= BIT_MASK[i];
      }
    }
  }
  return data;
}


/*
   Read the 40 bits in a Dht11 data record

   @param pointer to the record to be actualized
   @return true if there no problem
*/
boolean DHT11::readDht11DataRecord(DHT11::Dht11_data_type * dataRead)
{
  uint8_t integralRh = readByte(pin, timeoutForStartToTransmitData_us, timeoutForData_us, zeroLength_us);

  uint8_t decimalRh = readByte(pin, timeoutForStartToTransmitData_us, timeoutForData_us, zeroLength_us);

  uint8_t integralTemp = readByte(pin, timeoutForStartToTransmitData_us, timeoutForData_us, zeroLength_us);

  uint8_t decimalTemp = readByte(pin, timeoutForStartToTransmitData_us, timeoutForData_us, zeroLength_us);

  uint8_t checksum = readByte(pin, timeoutForStartToTransmitData_us, timeoutForData_us, zeroLength_us);

  // Verify checksum: integral RH + decimal RH + integral Temp data + decimal Temp data
  if ( (integralRh + decimalRh + integralTemp + decimalTemp ) != checksum ) {
    dataRead->error = ERROR_CHECKSUM;
    dataRead->status =  statusString[ERROR_CHECKSUM];
    return false;
  }

  dataRead->error = ERROR_NONE;
  dataRead->status =  statusString[ERROR_NONE];
  dataRead->temperature = (float)integralTemp +  (float)decimalTemp / 10.0;
  dataRead->humidity = (float)integralRh +  (float)decimalRh / 10.0;
  return true;
}

Secrets.h

C/C++
Use this file to store all of the private credentials and connection details
// Use this file to store all of the private credentials 
// and connection details

#define SECRET_SSID "MySSID"    // replace MySSID with your WiFi network name
#define SECRET_PASS "MyPassword"  // replace MyPassword with your WiFi password

#define SECRET_CH_ID 0000000      // replace 0000000 with your channel number
#define SECRET_WRITE_APIKEY "XYZ"   // replace XYZ with your channel write API Key

Credits

Enrique Albertos

Enrique Albertos

9 projects • 12 followers
Pedestrian.

Comments