Introduction: ESP32 and OLED Display: Internet Clock - DHT22

About: Engineer, writer and forever student. Passionate to share knowledge of electronics with focus on IoT and robotics.
This Instructable is competing o contest: "GIFs Challenge 2017", If you like it, please give your vote by clicking at the above banner. Thanks a lot! ;-)

This tutorial is a continuation of a journey to learn more about this great IoT device, the ESP32.

On my last tutorial: IOT Made Simple: Playing With the ESP32 on Arduino IDE, we explored:

  • Digital Output: Blinking a LED
  • Digital Input: Reading a Touch Sensor
  • Analog Input: Reading a variable voltage from a potentiometer
  • Analog Output: Controlling a LED brightness
  • Analog Output: Controlling a Servo Position
  • Reading Temperature/Humidity Data with a Digital sensor
  • Connecting to the Internet and getting local time
  • Receiving data from a simple local web page, turning on/off a LED
  • Transmitting data to a simple local webPage

Now let's included an OLED to present locally the data captured by DHT sensor (Temperature & Humidity) as well the local time.

Step 1: BoM - Bill of Material

Step 2: ESP32 Driver and Library Installation

We will use the Arduino IDE to program our ESP32, same way we do with the ESP8266 family.

Install Drivers:

It is important that you have installed on your computer, the updated CP210x USB to UART Driver. Enter in this link: usb-to-uart-bridge-vcp-drivers and install the proper driver for your OS.

Install Library:

The novelty here is that Expressif itself in its GitHub, will give us the proper directions for library installation: arduino-esp32. Follow the instructions for your OS.

After that, restart Arduino IDE and it's done! You must see several boards on "TOOLS" Menu. Select the appropriate for you. In general, the "generic" ESP32 DEV MODULE works fine.

When you open the Arduino IDE for the first time, you will note that the default upload speed is 921,600 bauds. This can provoque instability. Change it to 115,200 bauds!

Step 3: HW Installation

We will start from the HW assembled on my last tutorial. We will faster here, but if want more details, please visit:

IOT Made Simple: Playing With the ESP32 on Arduino IDE

In short:

  • Connect the ESP32 on 2 protoboards as shown in above diagram. This will be necessary for you to have access to all its pins
  • Connect a 10K ohm potentiometer extreme pins between +3.3V and GND. Its middle pin should be connected to ESP32 GPIO 36
  • Connect a LED (anode) to ESP32 GPIO 02 and its cathode to GND via a 330 ohm resistor (LED optional)
  • Install the DHT22 as shown (looking the sensor with the "grid" face you, count the 4 legs from left to right):
    1. Pin VCC ==> 3.3V
    2. Pin Data ==> GPIO 23
    3. N/C
    4. PIN GND ==> GND
  • Also, connect a 10K ohm resistor between DHT22 VCC and Data.

For testing the LED you can use the code: ESP32_Blink

For testing the Potentiometer (Analog input), you can use the codes: Analog_Input

For testing the DHT, first install the libraries as described on next step.

Step 4: DHT22 Libraries Instalattion

First, you need to have the Adafrut Library installed on your IDE. Go to their GitHub and download the updated version of this library: DHT-sensor-library

Unzip the file, rename it to DHT and move the complete folder to your Arduino Library directory

When I used for the first time I got a message:

fatal error: Adafruit_Sensor.h: No such file or directory

After some digging, I found that it is also necessary to have the Adafruit Unified Sensor Library also installed. So, I did it from Arduino IDE Library Manager (see picture above). After that, everything worked fine, same as we use to do with Arduino and NodeMCU.

Let's do some tests with this sensor. You can use the "DHT tester.ino" example sketch that it is included in the library, or do your own.

I wrote a simple code for test the sensor that can be downloaded from my GitHub: ESP32_DHT

Step 5: Installing the OLED Display

For this tutorial, I will use a 128 x 32 I2C OLED display. In principle, once you have the library installed, the ESP32 would also work with a 128 x 64 OLED display.

Once this device is a I2C display, you will need to connect 4 pins with the ESP32:

  • SDA ==> GPIO 21
  • SCL ==> GPIO 22
  • VCC ==> 3.3V
  • GND ==> GND
See the above electrical diagram for proper conection.

Now, install the library. We will use here the Daniel Eighhoen version. Open the library manager and search for "OLED". See the above picture. I have the 3.2.7 version installed.

Open SSD1306SimpleDemo, on Examples Menu and replace the code:

SSD1306  display(0x3c, D3, D5);

with:

SSD1306  display(0x3c, 21, 22);

Below a GIF showing the Simple Demos partially working. Note that this demo was designed for a 128 x 64 display, so you realize that in my case, where I used 128 x 32, the graphics are shrunk.

Step 6: Creating and Installing New Fonts

You can easily create and install new fonts on your display. I created a new font that can give me around 2 lines of 20 characters each on the 128 X 32 OLED display.

How to create it:

Go to SSD1306 Font Converter, a great tool also developed by Daniel Eighhoen. There, you must choose:

  • Font Family,
  • Type (Plan Bold, etc),
  • Size (10, 20, etc.) and
  • Library version (in our case should be >=3.0.0).

Press Create and voilá! A "C Font" file is created in the proper window.

  • Go there and copy the text into a new IDE tab.
  • Name it for example: "modified_font.h"
  • In your main .ino file include a new line at the beginning:

#include "modified_font.h"

The above foto shows a new "Hello World", using this new font. A clean code can be download from my GitHub:

ESP32_SSD1306_Test

Note that you must have the 2 files on your Arduino IDE if you use a modified font

Step 7: Displaying Temperature and Humidity Locally

Let's now display on the OLED, the temperature, and humidity captured by the DHT22 sensor.

On our loop() function, we will have:

void loop() 
{
  getDHT();
  displayData();
  delay(2000);
}

The function getDHT() is the one used before. The new function here is the displayData(), that is shown below:

/***************************************************
* Display Data
****************************************************/
void displayData() 
{
  display.clear();   // clear the display

  display.drawString(0, 0,  "temp: ");
  display.drawString(40, 0,  String(localTemp));
  display.drawString(90, 0,  "oC");
  display.drawString(0, 32, "hum:  ");
  display.drawString(40, 32,  String(localHum));
  display.drawString(90, 32,  "%");

  display.display();   // write the buffer to the display
  delay(10);
}

The above photo shows the final result, You can download the complete file from my GitHub: ESP32_DHT22_SSD1306

Step 8: Including Time Stamp

Usually, it is very important when capturing data with sensors, to also register the time, when it was collected.

Let's use the NTPClient library for that:

  • Go To Library Manager and search for "NTP"
  • Locate and Install NTPClient Library from Fabrice Weinberg
  • Open the NTP Client Example: Basic or advanced.

Change the line:

#include <ESP8266WiFi.h>
by:
#include <WiFi.h>

Enter with your WiFi network credentials. At Serial monitor, you must see the actual time. At basic version, a European time will be shown. At advanced version, you can change it.

Now, let's merge this TimeStamp code with the one developed before. The result is shown in above photos.

The complete code can be downloaded from my GitHub: ESP32_Time_Stamp_DHT22_SSD1306

Step 9: Selecting Multiple Displays

On last step we put all together, having a fixed display with 3 information:

  1. Temperature
  2. Humidity
  3. Local Time

But, how we can have each one of that information be shown one at a time at the display?

We will need a "page selection" mechanism. There are several different mechanisms to be used. Usually with multiple buttons, selecting menus.

Just for fun, let's try something not usual here. The potentiometer!

We will turn the potentiometer like we do with a radio dial, and depend on the value read, we will define one specific "display" to be shown at OLED.

Let's define 4 possible displays:

  1. display 0 ==> Display OFF
  2. display 1 ==> Local Time
  3. display 2 ==> Temperature
  4. display 3 ==> Humidity
  5. display 4 ==> All info dsplay

The Analog Input can read 4,095 diferent values. We need only 5, so let's define ranges for that:

  1. 0000 - 0999: ==> display 0 ==> Display OFF
  2. 1000 - 1999: ==> display 1 ==> Local Time
  3. 2000 - 2999: ==> display 2 ==> Temperature
  4. 3000 - 3999: ==> display 3 ==> Humidity
  5. 4000 - 4095: ==> display 4 ==> All info dsplay

Let's define a int variable that will receive as content: 0, 1, 2, 3, 4 5, depending of screen to be shown:

int displayNum = 0;

Now we need to create a function, getDisplay(), that will read the value of potentiometer, returning the correct display number (displayNum will be a local variable inside this function).

The function will look like:

/***************************************************
* Get display
****************************************************/
int getDisplay()
{
  int displayNum = 0;
  int analog_value = analogRead(ANALOG_PIN_0);
  if      (analog_value <= 999)                         displayNum = 0;
  else if (analog_value > 1000 && analog_value <= 1999) displayNum = 1;
  else if (analog_value > 2000 && analog_value <= 2999) displayNum = 2;
  else if (analog_value > 3000 && analog_value <= 3999) displayNum = 3;
  else if (analog_value > 4000 )                        displayNum = 4;
 
  return displayNum;
}

And the displayData() function, will display the selected display (or screen):

/***************************************************
* Display Data
****************************************************/
void displayData(int displayNum) 
{
  String formattedTime = timeClient.getFormattedTime();
  display.clear();   // clear the display
  switch (displayNum) 
  {
    case 0:
      display.clear();
      break;
    case 1:
      display.setFont(ArialMT_Plain_24);
      display.drawString(20, 31,  String(formattedTime));
      break;
    case 2:
      display.setFont(ArialMT_Plain_24);
      display.drawString(0, 31,  "T:");
      display.drawString(30, 31,  String(localTemp));
      display.drawString(100, 31,  "oC");
      break;
    case 3:
      display.setFont(ArialMT_Plain_24);
      display.drawString(0, 31,  "H:");
      display.drawString(30, 31,  String(localHum));
      display.drawString(100, 31,  "%");
      break;
    case 4:
      display.setFont(Open_Sans_Condensed_Light_20);
      display.drawString(0, 0,  "t:");
      display.drawString(10, 0,  String(localTemp));
      display.drawString(47, 0,  "oC");
      display.drawString(75, 0, "h:");
      display.drawString(85, 0,  String(localHum));
      display.drawString(120, 0 ,  "%");
      display.setFont(ArialMT_Plain_24);
      display.drawString(20, 31,  String(formattedTime));
      break;
    default: 
      display.clear();
      break;
  }
  display.display();   // write the buffer to the display
  delay(10);
}

Both functions will be included in our loop() function:

void loop() 
{
  getDHT();
  timeClient.update();
  displayData(getDisplay());
  delay(2000);
}

The complete file can be downloaded from my GitHub: ESP32_Time_Stamp_DHT22_SSD1306_Multiple_Displays

Below a gif with our display selector:

Step 10: Conclusion

There is a lot left to be explored with this great IoT device. We will return soon with new tutorials! Keep following MJRoBot tutorials!

As always, I hope this project can help others find their way in the exciting world of electronics, robotics, and IoT!

Please visit my GitHub for updated files: ESP32 SSD1306

For more projects, please visit my blog: MJRoBot.org

Saludos from the south of the world!

See you at my next instructable!

Thank you,

Marcelo

GIFs Challenge 2017

Participated in the
GIFs Challenge 2017