SHT31 Temperature and Humidity Sensor with ESP32 ESP-IDF

In this tutorial, we will learn to interface SHT31 temperature and humidity sensor using ESP32 and ESP-IDF. This guide will include a brief description of the sensor, connection with ESP32 board and then setting up a project in VS Code with ESP-IDF extension to acquire the sensor data and display it on the console.

Before we move ahead, make sure you have the latest version of VS Code installed on your system with the ESP-IDF extension configured.

SHT31 Sensor Module Introduction

The SHT31 sensor module is used in electronic projects to measure ambient temperature and relative humidity. The module uses the SHT31 chip by Sensirion to output sensor data with great accuracy and covers a good range to be used for temperature and humidity measurements. On top of that, it is low cost and compact in nature, which uses I2C communication protocol to send data over to the microcontroller. This protocol is based on a synchronous, multi-master multi-slave system where the ESP32 board acts as the master and the SHT31 sensor acts as the slave. With its broad operating voltage range of 2.15 to 5.5V, it is a stellar choice to be used with microcntrollers.

The diagram below shows the SHT31 Sensor Module featuring the I2C interface with the SHT31 sensor chip highlighted at one side.

SHT31 Sensor Module showing the SHT31 chip

SHT31 Sensor Module Pinout

The diagram below shows the pinout of the SHT31 sensor module.

SHT31 Sensor Module Pinout

As you can see in the diagram above, the SHt31 sensor consists of six pins. Two are power supply pins. two are I2C communication pins, while the other two are I2C address selection (AD) and alert output (AL) pins.

VINThis is the power supply pin which is connected with 3.3V of ESP32. You can supply power in the range of 2.4-5.5V
GNDThis is the ground pin
SCLThis is the serial clock pin which will produce the clock signal
SDAThis is the serial data pin which is used for sending and receiving data
ADThis pin is the I2C address selection pin. This pin allows the user to change the I2C address of the sensor module. By default, when this pin is in a low state, the I2C address is 0x44. When the state of this pin is high, the I2C address changes to 0x45.
ALThis pin is the alert output pin. It acts as a trigger to monitor the temperature and humidity readings. When these readings are not within the user defined range, the state of this pin goes to high. It stays high until the readings go back to the range set.

Specifications

Let us look at some key specifications of the SHT31 sensor module.

  • Supply voltage of 2.4 – 5.5V
  • Average supply current of 1.7uA
  • Maximum supply current of 1500uA

Humidity Measurements

  • Typical relative humidity accuracy of 2 %RH
  • Operating relative humidity range of 0–100 %RH
  • Response time (τ63%) of 8s

Temperature Measurements

  • Typical temperature accuracy of 0.2°C
  • Operating temperature range of -40–125°C
  • Response time (τ63%) is less than 2s

ESP32 I2C Pins

We will be using I2C interface to get SHT31 sensor readings with ESP32 and ESP-IDF. Now let’s discuss I2C pins of ESP32. The diagram below shows the pinout for the ESP32, where the default I2C pins are highlighted in red. These are the default I2C pins of the ESP32 DEVKIT module. However, if you want to use other GPIO pins as I2C pins then you will have to set them in code.

ESP32 Pinout I2C Pins

Refer to the following article to know more about ESP32 GPIO pins:

You can check this complete guide on ESP32 I2C communication:

Interfacing SHT31 Sensor Module with ESP32

We will need the following components to connect our ESP32 board with the SHT31 Sensor Module.

  1. ESP32 board
  2. SHT31 Sensor Module
  3. Connecting Wires
  4. Breadboard

The connection of SHT31 Sensor Module with the ESP32 board is straightforward as it just involves the connection of the 4 pins (GND, VCC, SDA, and SCL) with ESP32. We have to connect the VCC terminal with 3.3V pin, ground with the ground (common ground), SCL of the sensor with SCL of ESP32 board, and SDA of the sensor with the SDA pin of the ESP32 board. We will use the default I2C pins of ESP32 board to connect with the sensor module.

In ESP32, the default I2C pin for SDA is GPIO21 and for SCL is GPIO22.

The connections between the devices are specified in the table below:

SHT31 Sensor ModuleESP32
GNDGND
VCC3.3V
SDAGPIO21(I2C SDA)
SCLGPIO22 (I2C SCL)
SHT31 with ESP32 connection diagram

Measure SHT31 Readings with ESP32 and ESP-IDF

We will build and create a project in VS Code with ESP-IDF extension. The code will read temperature and humidity values by using the I2C device library and sht3x.h. We will use SHT3x library written by UncleRus.

SHT31 with ESP32

Create Example Project

Open your VS Code and head over to View > Command Palette. Type ESP-IDF: New Project in the search bar and press enter.

Specify the project name and directory. We have named our project ‘SHT31.’ For the ESP-IDF board, we have chosen the custom board option. For ESP-IDF target, we have chosen ESP32 module. Click ‘Choose Template’ button to proceed forward.

In the Extension, select ESP-IDF option:

ESP-IDF in VS Code New Project 2

We will click the ‘sample_project’ under the get-started tab. Now click ‘Create project using template sample_project.’

ESP-IDF in VS Code New Project 3

You will get a notification that the project has been created. To open the project in a new window, click ‘Yes.’

This opens the project that we created inside the EXPLORER tab. There are several folders inside our project folder. This is the same for every project which you will create through ESP-IDF Explorer.

  • First, let’s add the necessary header files for the libraries required for this project. Create a new folder called ‘components’ and add the following three sub-folders under it:
  1. esp_idf_lib_helpers
  2. i2cdev
  3. sht3x

Add the sht3x, esp_idf_lib_helpers, and i2cdev folders in ‘components’ folder by copying from this link as listed below:

ESP32 SHT31 Sensor Module ESP-IDF Project Setup Components

Now go to main and create a new file named ‘Kconfig.projbuild‘ under the main folder. Copy the file from this destination in this newly created file.

ESP32 SHT31 Sensor Module ESP-IDF Project Kconfig.projbuild

SHT31 MenuConfig Settings ESP-IDF

Now let’s head over to the menuconfig. Open the ESP-IDF SDK Configuration Editor. Scroll down and open the Example configuration. Here we can set the configuration parameter according to our needs. This includes the demo mode, the I2C address of SHT3x, SCL GPIO pin and SDA GPIO pin. Here you can view that we have set the demo mode as High level, I2C address of SHT3x as 0x44 (default), SCL GPIO as 22 and SDA GPIO as 21. You can alter these parameters according to your requirement and then click the Save button found at the top.

ESP32 SHT31 Sensor Module ESP-IDF Project SDK Configuration editor

Alternatively, we can also set this config value with menuconfig. Open menuconfig by typing idf.py menuconfig in the terminal. This command opens the Espressif IoT Development Framework Configuration. Head over to Example configuration and set the parameters accordingly.

  • Now head over to the main.c file. The main folder contains the source code meaning the main.c file will be found here. Go to main > main.c and open it. Copy the code given below in that file and save it.

ESP32 SHT31 Display Readings Code

This is an example sketch for the driver sht3x. It allows the users to select different demos, and implements the tasks in either periodic mode or single shot mode. In single shot mode, the user can either select high level demo or low level demo from the menuconfig.

If CONFIG_EXAMPLE_SHT3X_DEMO_HL is selected, then the high level function sht3x_meaure() is used to obtain the sensor data for every cycle. The sensor readings are triggered in single shot mode, after every 5 seconds.

However, if CONFIG_EXAMPLE_SHT3X_DEMO_LL is selected, then the sensor data is measured one at a time, every 5 seconds, in single shot mode with high repeatability. Then it waits for the output and then retrieves them.

If CONFIG_SHT3X_DEMO_PERIODIC is selected, then the SHT3x sensor is started in periodic mode, which takes a measurement every second. The user task obtains the sensor data measurements after every 2 seconds.

/**
 * Simple example with SHT3x sensor.
 *
 * It shows different user task implementations in *single shot mode* and
 * *periodic mode*. In *single shot* mode either low level or high level
 * functions are used.
 */

#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_system.h>
#include <sht3x.h>
#include <string.h>
#include <esp_err.h>

/* float is used in printf(). you need non-default configuration in
 * sdkconfig for ESP8266, which is enabled by default for this
 * example. see sdkconfig.defaults.esp8266
 */

#ifndef APP_CPU_NUM
#define APP_CPU_NUM PRO_CPU_NUM
#endif

static sht3x_t dev;

#if defined(CONFIG_EXAMPLE_SHT3X_DEMO_HL)

/*
 * User task that triggers a measurement every 5 seconds. Due to power
 * efficiency reasons it uses *single shot* mode. In this example it uses the
 * high level function *sht3x_measure* to perform one measurement in each cycle.
 */
void task(void *pvParameters)
{
    float temperature;
    float humidity;

    TickType_t last_wakeup = xTaskGetTickCount();

    while (1)
    {
        // perform one measurement and do something with the results
        ESP_ERROR_CHECK(sht3x_measure(&dev, &temperature, &humidity));
        printf("SHT3x Sensor: %.2f °C, %.2f %%\n", temperature, humidity);

        // wait until 5 seconds are over
        vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(5000));
    }
}

#elif defined(CONFIG_EXAMPLE_SHT3X_DEMO_LL)

/*
 * User task that triggers a measurement every 5 seconds. Due to power
 * efficiency reasons it uses *single shot* mode. In this example it starts the
 * measurement, waits for the results and fetches the results using separate
 * functions
 */
void task(void *pvParameters)
{
    float temperature;
    float humidity;

    TickType_t last_wakeup = xTaskGetTickCount();

    // get the measurement duration for high repeatability;
    uint8_t duration = sht3x_get_measurement_duration(SHT3X_HIGH);

    while (1)
    {
        // Trigger one measurement in single shot mode with high repeatability.
        ESP_ERROR_CHECK(sht3x_start_measurement(&dev, SHT3X_SINGLE_SHOT, SHT3X_HIGH));

        // Wait until measurement is ready (constant time of at least 30 ms
        // or the duration returned from *sht3x_get_measurement_duration*).
        vTaskDelay(duration);

        // retrieve the values and do something with them
        ESP_ERROR_CHECK(sht3x_get_results(&dev, &temperature, &humidity));
        printf("SHT3x Sensor: %.2f °C, %.2f %%\n", temperature, humidity);

        // wait until 5 seconds are over
        vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(5000));
    }
}

#else // CONFIG_SHT3X_DEMO_PERIODIC
/*
 * User task that fetches latest measurement results of sensor every 2
 * seconds. It starts the SHT3x in periodic mode with 1 measurements per
 * second (*SHT3X_PERIODIC_1MPS*).
 */
void task(void *pvParameters)
{
    float temperature;
    float humidity;
    esp_err_t res;

    // Start periodic measurements with 1 measurement per second.
    ESP_ERROR_CHECK(sht3x_start_measurement(&dev, SHT3X_PERIODIC_1MPS, SHT3X_HIGH));

    // Wait until first measurement is ready (constant time of at least 30 ms
    // or the duration returned from *sht3x_get_measurement_duration*).
    vTaskDelay(sht3x_get_measurement_duration(SHT3X_HIGH));

    TickType_t last_wakeup = xTaskGetTickCount();

    while (1)
    {
        // Get the values and do something with them.
        if ((res = sht3x_get_results(&dev, &temperature, &humidity)) == ESP_OK)
            printf("SHT3x Sensor: %.2f °C, %.2f %%\n", temperature, humidity);
        else
            printf("Could not get results: %d (%s)", res, esp_err_to_name(res));

        // Wait until 2 seconds (cycle time) are over.
        vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(2000));
    }
}

#endif

void app_main()
{
    ESP_ERROR_CHECK(i2cdev_init());
    memset(&dev, 0, sizeof(sht3x_t));

    ESP_ERROR_CHECK(sht3x_init_desc(&dev, CONFIG_EXAMPLE_SHT3X_ADDR, 0, CONFIG_EXAMPLE_I2C_MASTER_SDA, CONFIG_EXAMPLE_I2C_MASTER_SCL));
    ESP_ERROR_CHECK(sht3x_init(&dev));

    xTaskCreatePinnedToCore(task, "sh301x_test", configMINIMAL_STACK_SIZE * 8, NULL, 5, NULL, APP_CPU_NUM);
}

We will define CONFIG_SHT3X_DEMO_PERIODIC and explain the working of that part.

How the Code Works?

Firstly, we will start by including the necessary libraries for this project. This includes the SHT3x library to access the APIs for configuring the sht3x device and obtaining sensor measurements.

#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_system.h>
#include <sht3x.h>
#include <string.h>
#include <esp_err.h>

First we will create the device descriptor ‘dev’ of sht3x_t.

static sht3x_t dev;

Then for the user task implementation in periodic mode, we have the following task() function.

void task(void *pvParameters)
{
    float temperature;
    float humidity;
    esp_err_t res;

    ESP_ERROR_CHECK(sht3x_start_measurement(&dev, SHT3X_PERIODIC_1MPS, SHT3X_HIGH));


    vTaskDelay(sht3x_get_measurement_duration(SHT3X_HIGH));

    TickType_t last_wakeup = xTaskGetTickCount();

    while (1)
    {
        // Get the values and do something with them.
        if ((res = sht3x_get_results(&dev, &temperature, &humidity)) == ESP_OK)
            printf("SHT3x Sensor: %.2f °C, %.2f %%\n", temperature, humidity);
        else
            printf("Could not get results: %d (%s)", res, esp_err_to_name(res));

        // Wait until 2 seconds (cycle time) are over.
        vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(2000));
    }
}

It initiates the periodic sensor data measurements at one measurement per second. This is done by calling the function sht3x_start_measurement(). This function takes in three parameters: the pointer to the object descriptor structure, the measurement mode, and the repeatability.

ESP_ERROR_CHECK(sht3x_start_measurement(&dev, SHT3X_PERIODIC_1MPS, SHT3X_HIGH));

After starting the sht3x measurement, we add a delay until the measurement is ready.

vTaskDelay(sht3x_get_measurement_duration(SHT3X_HIGH));

Inside the infinite while loop, we obtain the sensor measurements through sht3x_get_results() for both temperature and humidity values. These are printed on the ESP-IDF terminal after every 2 seconds.

    while (1)
    {
        // Get the values and do something with them.
        if ((res = sht3x_get_results(&dev, &temperature, &humidity)) == ESP_OK)
            printf("SHT3x Sensor: %.2f °C, %.2f %%\n", temperature, humidity);
        else
            printf("Could not get results: %d (%s)", res, esp_err_to_name(res));

        // Wait until 2 seconds (cycle time) are over.
        vTaskDelayUntil(&last_wakeup, pdMS_TO_TICKS(2000));
    }

Compiling the Sketch

To flash your chip, type the following command in the serial terminal. Remember to replace the COM port with the one through which your board is connected.

idf.py -p COMX flash monitor

After the code is successfully flashed, you can view the temperature and humidity readings on the console.

ESP32 SHT31 Sensor Module ESP-IDF Project Display Readings on Console

You may also like to read:

Leave a Comment