Introduction: Connecting a DHT11/DHT22 Sensor to the Cloud With an ESP8266-based Board

In the previous article, I connected my ESP8266-based NodeMCU board to a Cloud4RPi service. Now, it’s time for a real project!

Supplies

Hardware requirements:

Software and services:

Step 1: Measure Temperature and Humidity

I already had a DHT11 sensor, so I decided to use it for temperature and humidity measurements. Let’s choose an Arduino library to read sensor data.

Arduino registry contains several libraries, from which I selected the most popular one.

According to their GitHub repository, we are also required to add an Adafruit Unified Sensor package.

Step 2: Create and Configure Project

I already described how to create a PlatformIO project and install libraries in the first part. My project is called “MyNodeMCU”. The structure is shown above.

This project is a slightly modified Cloud4RPi example.
I decided to store the device token and Wi-Fi credentials in the configuration file instead of code.

The platform.io file looks as follows:

[platformio]
default_envs = nodemcuv2

[env:nodemcuv2] platform = espressif8266 framework = arduino board = nodemcuv2</p>

Step 3: Install Libraries

Libraries installation is quite simple. You can do it from the IDE’s graphical interface, or by adding required library names to the lib_deps section of the platform.io file:

; ...<br>lib_deps =
    cloud4rpi-esp-arduino
    Adafruit Unified Sensor
    DHT sensor library
build_flags =
    -D MQTT_MAX_PACKET_SIZE=1024
    -D MQTT_MAX_TRANSFER_SIZE=128
    -D CLOUD4RPI_DEBUG=0
    -D SSID_NAME=\"__YOUR_WIFI__\"
    -D SSID_PASSWORD=\"__YOUR_WIFI_PASS__\"
    -D CLOUD4RPI_TOKEN=\"__YOUR_DEVICE_TOKEN__\"

Added libraries will be automatically installed into a project’s subfolder.

The main.cpp header looks as follows:

#include <Arduino.h>
#include <ESP8266WiFi.h> #include <Cloud4RPI.h> #include "DHT.h"

Step 4: Connect a DHT11 Sensor

Adafruit provides a DHTtester.ino example of a sensor connection.

This code initializes a sensor and defines a structure to store the measurement result (in case it was successful):

<p>#define DHTPIN 2      // Digital pin connected to the DHT sensor<br>#define DHTTYPE DHT11 // DHT 11  
// ...  
DHT dht(DHTPIN, DHTTYPE);
dht.begin();
// ...
struct DHT_Result {
   float h;
   float t;  
};
DHT_Result dhtResult;</p>

The next function shows how to read sensor data and store it in the data structure described above

<p>void readSensors() {<br>    float h = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float t = dht.readTemperature();</p><p>    // Check if any reads failed and exit
    if (isnan(h) || isnan(t)) {
        Serial.println(F("Failed to read from DHT sensor!"));
        return;
    }
    dhtResult.h = h;
    dhtResult.t = t;
}</p>

Step 5: Sending Data to the Cloud

Once we have that data, the next step is to send it to the Cloud4RPi service.

The Cloud4RPi for Arduino page describes the library API, which is a set of methods used to:

  • create, read and update variables,
  • send variable values into the cloud using the MQTT protocol.

The library supports three variable types: Bool, Numeric, and String.

The library workflow starts with creating an API instance using the Device Token from the cloud4rpi.io website (refer to the article’s part 1 for details).

#if defined(CLOUD4RPI_TOKEN)
Cloud4RPi c4r(CLOUD4RPI_TOKEN); #else Cloud4RPi c4r("!!!_NO_DEVICE_TOKEN_!!!"); #endif

Then, declare variables for DHT11 readings:

c4r.declareNumericVariable("DHT11_Temp");
c4r.declareNumericVariable("DHT11_Hum");

Then, get data from the sensor, save them into variables and publish the data to Cloud4RPi:

c4r.setVariable("DHT11_Temp", dhtResult.t);
c4r.setVariable("DHT11_Hum", dhtResult.h); c4r.publishData();

Temperature and humidity does not change quickly, so sending more than one value per 5 minutes is not required.

Step 6: Diagnostics

Cloud4RPi supports diagnostic data along with variable values. I used uptime, Wi-Fi signal strength, and IP address as diagnostic data:

c4r.declareDiagVariable("IP_Address");
c4r.declareDiagVariable("RSSI"); // WiFi signal strength c4r.declareDiagVariable("Uptime");

Note: The millis function I use to obtain uptime resets to zero every ~50 days. Which is more than enough for my project.

The following code sets diagnostic variable values:

c4r.setDiagVariable("RSSI", (String)WiFi.RSSI() + " dBm");
c4r.setDiagVariable("IP_Address", WiFi.localIP().toString()); c4r.setDiagVariable("Uptime", uptimeHumanReadable(currentMillis)); c4r.publishDiag();

The uptimeHumanReadable function converts milliseconds to a convenient form:

String uptimeHumanReadable(unsigned long milliseconds) {
static char uptimeStr[32]; unsigned long secs = milliseconds / 1000; unsigned long mins = secs / 60; unsigned int hours = mins / 60; unsigned int days = hours / 24; secs -= mins * 60; mins -= hours * 60; hours -= days * 24; sprintf(uptimeStr,"%d days %2.2d:%2.2d:%2.2d", (byte)days, (byte)hours, (byte)mins, (byte)secs); return String(uptimeStr); }

The function outputs a string like this 5 days 10:23:14 instead of a strange big number.

Step 7: Start and Debug the Project

After compiling the created code and flashing it into NodeMCU, the device connects to a cloud service and starts sending data.

You can increase logging verbosity by setting the CLOUD4RPI_DEBUG preprocessor variable to 1 (add -D CLOUD4RPI_DEBUG=1 to build_flags section in platform.io file).

Next, open the cloud4rpi.io site and notice the new device online. Open it to see all variable values received from the device: sensor and diagnostics.

Step 8: Dashboard Configuration

At this step, the data connection to the cloud is operational. Now, let’s configure the visual representation of the data.

I used the Dashboard configuration UI to create the following dashboard.

The dashboard is shareable, so I instantly share it with my friend.

Step 9: Conclusion

The full project’s code is available in the gist.

That’s all for now!

Questions and suggestions are welcome in the comments.