DEV Community

Cover image for Embedded Rust on the ESP32 : Sensor Integration : DHT22 (Temperature and Humidity Sensor)
Vaishnav-sabari-girish
Vaishnav-sabari-girish

Posted on

Embedded Rust on the ESP32 : Sensor Integration : DHT22 (Temperature and Humidity Sensor)

In my previous blog, we interfaced a button.

We shall now get started with interfacing a few sensors. This blog will walk you through interfacing the DHT22 temperature and Humidity Sensor.

Getting Started

Let us create our new project

esp-generate --chip=esp32 dht22_sensor 
Enter fullscreen mode Exit fullscreen mode

Open src/bin/main.rs and type the below code

#![no_std] #![no_main] #![deny( clippy::mem_forget, reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ holding buffers for the duration of a data transfer." )] use esp_backtrace as _; use esp_hal::{ clock::CpuClock, delay::Delay, gpio::{DriveMode, Output, OutputConfig, Pull}, main, }; use esp_println::println; use embedded_dht_rs::dht22; esp_bootloader_esp_idf::esp_app_desc!(); #[main] fn main() -> ! { let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals = esp_hal::init(config); let od_config = OutputConfig::default() .with_drive_mode(DriveMode::OpenDrain) .with_pull(Pull::None); let od_for_dht22 = Output::new( peripherals.GPIO4, esp_hal::gpio::Level::High, od_config ) .into_flex(); od_for_dht22.peripheral_input(); let delay = Delay::new(); let mut dht22 = dht22::Dht22::new(od_for_dht22, delay); loop { delay.delay_millis(2000); println!(""); match dht22.read() { Ok(sensor_reading) => println!( "DHT22 Sensor - Temperature: {} C , Humidity: {} %", sensor_reading.temperature, sensor_reading.humidity ), Err(error) => println!("An error occurred while trying to read the sensor"), } println!("_____________________________________________________"); } } 
Enter fullscreen mode Exit fullscreen mode

Output GIF

Output GIF

Into the code : Line-by-line explanation

#![no_std] 
Enter fullscreen mode Exit fullscreen mode
  • Disables the Rust standard library for embedded programming.
#![no_main] 
Enter fullscreen mode Exit fullscreen mode
  • Replaces the default main entry point with a custom embedded one.
#![deny( clippy::mem_forget, reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ holding buffers for the duration of a data transfer." )] 
Enter fullscreen mode Exit fullscreen mode
  • Prevents the use of mem::forget as it can cause unsafe behavior in this context.
use esp_backtrace as _; 
Enter fullscreen mode Exit fullscreen mode
  • Enables backtrace support on panic (if supported by target). as _ suppresses warnings.
use esp_hal::{ clock::CpuClock, delay::Delay, gpio::{DriveMode, Output, OutputConfig, Pull}, main, }; 
Enter fullscreen mode Exit fullscreen mode
  • Imports required ESP HAL modules:
    • Clock configuration
    • Delay handling
    • GPIO configuration (including open-drain and pull options)
    • main macro
use esp_println::println; 
Enter fullscreen mode Exit fullscreen mode
  • Enables UART-based printing to a terminal.
use embedded_dht_rs::dht22; 
Enter fullscreen mode Exit fullscreen mode
  • Imports DHT22 support from the embedded_dht_rs crate.
esp_bootloader_esp_idf::esp_app_desc!(); 
Enter fullscreen mode Exit fullscreen mode
  • Embeds metadata about the application (like name, version).
#[main] fn main() -> ! { 
Enter fullscreen mode Exit fullscreen mode
  • Entry point of the embedded program that never returns (-> !).
 let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 
Enter fullscreen mode Exit fullscreen mode
  • Configures system with maximum CPU clock speed.
 let peripherals = esp_hal::init(config); 
Enter fullscreen mode Exit fullscreen mode
  • Initializes the HAL and returns access to hardware peripherals.
 let od_config = OutputConfig::default() .with_drive_mode(DriveMode::OpenDrain) .with_pull(Pull::None); 
Enter fullscreen mode Exit fullscreen mode
  • Sets up GPIO pin as Open-Drain with no internal pull-up/down. This is essential for DHT22 communication.
 let od_for_dht22 = Output::new( peripherals.GPIO4, esp_hal::gpio::Level::High, od_config ) .into_flex(); 
Enter fullscreen mode Exit fullscreen mode
  • Initializes GPIO4 with the config above and converts it to a flexible IO pin (Flex), which allows bidirectional control.
 od_for_dht22.peripheral_input(); 
Enter fullscreen mode Exit fullscreen mode
  • Enables input mode for this flexible pin — DHT22 is bidirectional, so the pin needs to receive data too.
 let delay = Delay::new(); 
Enter fullscreen mode Exit fullscreen mode
  • Creates a delay instance for timing control.
 let mut dht22 = dht22::Dht22::new(od_for_dht22, delay); 
Enter fullscreen mode Exit fullscreen mode
  • Initializes the DHT22 driver with the GPIO and delay.
 loop { 
Enter fullscreen mode Exit fullscreen mode
  • Begins infinite polling loop.
 delay.delay_millis(2000); 
Enter fullscreen mode Exit fullscreen mode
  • Waits 2 seconds between each sensor read (recommended minimum delay for DHT22).
 println!(""); 
Enter fullscreen mode Exit fullscreen mode
  • Prints a blank line for readability.
 match dht22.read() { 
Enter fullscreen mode Exit fullscreen mode
  • Tries to read temperature and humidity from the sensor.
 Ok(sensor_reading) => println!( "DHT22 Sensor - Temperature: {} C , Humidity: {} %", sensor_reading.temperature, sensor_reading.humidity ), 
Enter fullscreen mode Exit fullscreen mode
  • If read is successful, prints temperature and humidity.
 Err(error) => println!("An error occurred while trying to read the sensor"), 
Enter fullscreen mode Exit fullscreen mode
  • If read fails, prints a basic error message (you can expand this with {:?} for debugging).
 println!("_____________________________________________________"); 
Enter fullscreen mode Exit fullscreen mode
  • Prints a separator line to visually break up readings.
 } } 
Enter fullscreen mode Exit fullscreen mode
  • Closes loop and function.

Summary:

This ESP32 firmware reads data from a DHT22 sensor connected to GPIO4 and prints temperature and humidity to the serial console every 2 seconds. It uses open-drain GPIO configuration and the embedded_dht_rs crate for protocol handling.

Thank You

Important Links

  1. Getting Started Blog
  2. Interfacing a Button Blog
  3. GitHub Repository

Top comments (0)