Overview

The DHT20 is a high-precision temperature and humidity sensor that uses I2C communication. Unlike older DHT sensors that use a single-wire protocol, the DHT20 provides more accurate readings and faster response times.

±0.5°C
Temperature Accuracy
±3% RH
Humidity Accuracy
I2C
Communication Protocol
1.8V - 5.5V
Operating Voltage
Real-World Applications

The DHT20 is perfect for:

  • Weather Stations: Monitor local climate conditions
  • Smart Homes: Control HVAC systems based on room conditions
  • Greenhouses: Maintain optimal growing conditions
  • Server Rooms: Prevent equipment overheating
  • Healthcare: Monitor patient room conditions
  • Industrial: Process control and monitoring

Prerequisites

Before starting this lesson, make sure you have:

Completed Lessons
  • Lesson 1: Blinking LED (Digital Output)
  • Lesson 2: Buzzer (PWM Control)
  • Lesson 5: Light Sensor (I2C Introduction)
  • Basic understanding of variables and functions
Hardware Requirements
  • Vumbua Synapse Kit with DHT20 sensor
  • USB Type-C cable
  • Computer with Arduino IDE
  • Optional: Breadboard and jumper wires
Important: I2C Experience Required

This lesson builds upon I2C knowledge from Lesson 5. If you haven't worked with I2C before, review Lesson 5 (Light Sensor) to understand:

  • What I2C communication is
  • How to use the Wire library
  • Basic I2C address scanning
  • I2C read/write operations

Learning Objectives

By the end of this lesson, you will be able to:

  • Understand the DHT20 sensor specifications and capabilities
  • Configure I2C communication on the Vumbua Synapse Kit
  • Read temperature and humidity data from DHT20
  • Convert raw sensor data to meaningful values
  • Display readings on Serial Monitor with proper formatting
  • Create a basic weather station application
  • Implement data logging functionality
  • Troubleshoot common I2C communication issues
  • Understand temperature-humidity relationships
  • Calculate dew point and heat index

Understanding the DHT20 Sensor

Sensor Technology

The DHT20 uses advanced capacitive humidity sensing and thermistor temperature sensing technology. It's factory calibrated and provides stable, reliable measurements.

Key Features

DHT20 Advantages:

Feature Specification Benefit
Communication Standard I2C Easy integration, multiple devices on same bus
Temperature Range -40°C to 80°C Suitable for extreme environments
Humidity Range 0% to 100% RH Full range measurement capability
Resolution 0.01°C / 0.024% RH High precision measurements
Response Time 8 seconds (humidity) Fast enough for most applications
Comparison with DHT11/DHT22

The DHT20 is superior to older DHT sensors:

Sensor Protocol Accuracy Speed Price
DHT11 Single-Wire ±2°C / ±5% RH Slow $
DHT22 Single-Wire ±0.5°C / ±2% RH Medium $$
DHT20 I2C ±0.5°C / ±3% RH Fast $$

I2C Protocol Basics

What is I2C?

I2C (Inter-Integrated Circuit) is a synchronous, multi-master, multi-slave, packet-switched, single-ended, serial communication bus. It's widely used for connecting low-speed peripherals to processors.

I2C on Vumbua Synapse Kit

On the Vumbua board, I2C uses:

  • SDA (Serial Data): Pin D4
  • SCL (Serial Clock): Pin D3
  • Pull-up resistors: Built-in (4.7kΩ)
  • Speed: Up to 400kHz (Fast Mode)
I2C Communication Flow

Communication with DHT20 follows this sequence:

  1. Master (Vumbua) sends START condition
  2. Master sends slave address + write bit (0x38)
  3. DHT20 acknowledges address reception
  4. Master sends command byte (measurement request)
  5. DHT20 processes measurement (takes ~80ms)
  6. Master sends START condition again
  7. Master sends slave address + read bit (0x38)
  8. Master reads 6 bytes of data
  9. Master sends STOP condition
Wire Library Functions

We'll use these key functions from the Wire library:

Wire.begin();              // Initialize I2C as master
Wire.beginTransmission(address); // Start talking to device
Wire.write(data);          // Send data byte
Wire.endTransmission();    // Stop transmitting
Wire.requestFrom(address, quantity); // Request data
Wire.available();          // Check if data is available
Wire.read();               // Read a byte

Pin Connections

The DHT20 sensor has 4 pins that connect to the Vumbua Synapse Kit:

VCC
Power Supply (3.3V or 5V)
3.3V on Vumbua
SDA
Serial Data (I2C)
Pin D4
SCL
Serial Clock (I2C)
Pin D3
GND
Ground
GND on Vumbua
Important: On Vumbua Synapse Kit

The DHT20 is already pre-connected to the Vumbua board:

  • SDA: Connected to D4
  • SCL: Connected to D3
  • VCC: Connected to 3.3V
  • GND: Connected to GND

You don't need to make any physical connections - just write the code!

I2C Address: 0x38

Understanding I2C Address 0x38

The DHT20 has a fixed I2C address of 0x38 (hexadecimal). In decimal, this is 56.

Address Format

I2C addresses are 7-bit values (0-127). When using the Wire library, we provide the address as a byte. The library handles the 8th bit (read/write flag) automatically.

Address in code: 0x38 (hexadecimal) or 56 (decimal)

Scanning for I2C Devices

Use this code to scan for all I2C devices connected to your Vumbua:

i2c_scanner.ino
// I2C Scanner for Vumbua Synapse Kit
// Scans for devices on I2C bus

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(1000);
  
  Serial.println("\nI2C Scanner for Vumbua Synapse Kit");
  Serial.println("=================================");
}

void loop() {
  byte error, address;
  int deviceCount = 0;
  
  Serial.println("Scanning I2C bus...");
  
  for (address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    
    if (error == 0) {
      Serial.print("Device found at address 0x");
      if (address < 16) Serial.print("0");
      Serial.print(address, HEX);
      Serial.print(" (");
      Serial.print(address);
      Serial.println(" decimal)");
      deviceCount++;
    }
  }
  
  if (deviceCount == 0) {
    Serial.println("No I2C devices found!");
  } else {
    Serial.print("Found ");
    Serial.print(deviceCount);
    Serial.println(" device(s)");
  }
  
  Serial.println("\nExpected: DHT20 at 0x38 (56 decimal)");
  Serial.println("Scanning again in 10 seconds...");
  delay(10000);
}

Library Installation

We'll use the DFRobot DHT20 Library for easy communication with the sensor.

Method 1: Arduino Library Manager (Recommended)
  1. Open Arduino IDE
  2. Go to Tools → Manage Libraries...
  3. Search for "DFRobot DHT20"
  4. Click on "DFRobot DHT20" by DFRobot
  5. Click "Install"
Method 2: Manual Installation
  1. Download the library from: github.com/DFRobot/DFRobot_DHT20
  2. Extract the ZIP file
  3. In Arduino IDE: Sketch → Include Library → Add .ZIP Library...
  4. Select the extracted folder
  5. Click "Open"
Verify Installation

Create a new sketch and add:

#include <DFRobot_DHT20.h>

If it compiles without errors, the library is installed correctly.

Basic Reading: Temperature & Humidity

Let's write our first program to read data from the DHT20 sensor:

dht20_basic.ino
/*
  Vumbua Synapse Kit - Lesson 6: Basic DHT20 Temperature & Humidity
  Reads temperature and humidity from DHT20 sensor at I2C address 0x38
*/

#include <DFRobot_DHT20.h>

// Create DHT20 object with default I2C address 0x38
// On Vumbua: SDA = D4, SCL = D3
DFRobot_DHT20 dht20;

void setup() {
  // Initialize Serial communication
  Serial.begin(115200);
  
  // Wait for Serial port to connect (for boards with native USB)
  while (!Serial) {
    delay(10);
  }
  
  Serial.println("Vumbua Synapse Kit - DHT20 Temperature & Humidity Sensor");
  Serial.println("=====================================================");
  Serial.println();
  
  // Initialize DHT20 sensor
  Serial.println("Initializing DHT20 sensor...");
  
  while (dht20.begin() != 0) {
    Serial.println("DHT20 initialization failed! Please check:");
    Serial.println("1. I2C connections (SDA=D4, SCL=D3)");
    Serial.println("2. Power supply (3.3V)");
    Serial.println("3. I2C address (should be 0x38)");
    Serial.println();
    delay(3000);
  }
  
  Serial.println("DHT20 initialized successfully!");
  Serial.println("I2C Address: 0x38");
  Serial.println();
  
  // Print header for data table
  Serial.println("Temperature (°C)   Temperature (°F)   Humidity (%RH)");
  Serial.println("---------------------------------------------------");
}

void loop() {
  // Read temperature and humidity from DHT20
  float temperatureC = dht20.getTemperature();
  float humidity = dht20.getHumidity();
  
  // Convert Celsius to Fahrenheit
  float temperatureF = temperatureC * 9.0 / 5.0 + 32.0;
  
  // Display readings with nice formatting
  Serial.print("    ");
  printFormatted(temperatureC, "°C", 6);
  Serial.print("        ");
  printFormatted(temperatureF, "°F", 6);
  Serial.print("        ");
  printFormatted(humidity, "%", 6);
  Serial.println();
  
  // Wait 2 seconds before next reading
  delay(2000);
}

// Helper function to print formatted values
void printFormatted(float value, const char* unit, int width) {
  if (value >= 100.0) {
    Serial.print(value, 1);
  } else if (value >= 10.0) {
    Serial.print(" ");
    Serial.print(value, 1);
  } else {
    Serial.print("  ");
    Serial.print(value, 1);
  }
  Serial.print(unit);
  
  // Pad with spaces for alignment
  int printed = 3 + strlen(unit); // 3 digits + unit
  for (int i = printed; i < width; i++) {
    Serial.print(" ");
  }
}
Testing the Program
  1. Upload the code to your Vumbua Synapse Kit
  2. Open Serial Monitor (Tools → Serial Monitor)
  3. Set baud rate to 115200
  4. You should see initialization messages
  5. After successful initialization, temperature and humidity readings will appear every 2 seconds
  6. Try breathing on the sensor to see humidity increase
  7. Hold the sensor in your hand to see temperature rise
Common Issues

If you see "DHT20 initialization failed":

  • Check that the DHT20 library is installed
  • Verify I2C connections (SDA=D4, SCL=D3)
  • Run the I2C scanner to confirm address 0x38
  • Ensure the sensor is getting power (3.3V)
  • Try adding a 0.1μF capacitor between VCC and GND

Advanced Serial Monitor Display

Let's create a more informative display with additional calculations:

dht20_advanced.ino
/*
  Vumbua Synapse Kit - Lesson 6: Advanced DHT20 Display
  Shows temperature, humidity, dew point, heat index, and comfort level
*/

#include <DFRobot_DHT20.h>

DFRobot_DHT20 dht20;

// Variables for smoothing readings
float tempSamples[10];
float humSamples[10];
int sampleIndex = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(10);
  }
  
  Serial.println("Initializing DHT20 sensor...");
  
  while (dht20.begin() != 0) {
    Serial.println("DHT20 initialization failed!");
    delay(3000);
  }
  
  Serial.println("\nDHT20 Weather Station Ready!");
  Serial.println("=============================\n");
  
  // Initialize smoothing arrays
  for (int i = 0; i < 10; i++) {
    tempSamples[i] = 0;
    humSamples[i] = 0;
  }
}

void loop() {
  // Read raw values
  float tempC = dht20.getTemperature();
  float humidity = dht20.getHumidity();
  
  // Store samples for smoothing
  tempSamples[sampleIndex] = tempC;
  humSamples[sampleIndex] = humidity;
  sampleIndex = (sampleIndex + 1) % 10;
  
  // Calculate smoothed values
  float smoothedTemp = calculateAverage(tempSamples, 10);
  float smoothedHum = calculateAverage(humSamples, 10);
  
  // Convert temperature
  float tempF = smoothedTemp * 9.0 / 5.0 + 32.0;
  
  // Calculate additional metrics
  float dewPoint = calculateDewPoint(smoothedTemp, smoothedHum);
  float heatIndex = calculateHeatIndex(tempF, smoothedHum);
  float absoluteHumidity = calculateAbsoluteHumidity(smoothedTemp, smoothedHum);
  
  // Clear screen (simulate with newlines)
  for (int i = 0; i < 50; i++) Serial.println();
  
  // Display header
  Serial.println("╔═══════════════════════════════════════════════════════╗");
  Serial.println("║           VUMBUA WEATHER STATION - DHT20             ║");
  Serial.println("╚═══════════════════════════════════════════════════════╝");
  Serial.println();
  
  // Temperature display
  Serial.print("🌡  Temperature:   ");
  Serial.print(smoothedTemp, 1);
  Serial.print("°C  (");
  Serial.print(tempF, 1);
  Serial.println("°F)");
  
  // Humidity display
  Serial.print("💧  Humidity:      ");
  Serial.print(smoothedHum, 1);
  Serial.print("% RH  (Absolute: ");
  Serial.print(absoluteHumidity, 2);
  Serial.println(" g/m³)");
  
  // Dew point display
  Serial.print("💎  Dew Point:     ");
  Serial.print(dewPoint, 1);
  Serial.println("°C");
  
  // Heat index display
  Serial.print("🔥  Heat Index:    ");
  Serial.print(heatIndex, 1);
  Serial.println("°F");
  
  Serial.println();
  
  // Comfort level indicator
  Serial.print("🏠  Comfort Level: ");
  int comfort = getComfortLevel(smoothedTemp, smoothedHum);
  switch (comfort) {
    case 0:
      Serial.println("Perfect! 🎯");
      break;
    case 1:
      Serial.println("Comfortable 😊");
      break;
    case 2:
      Serial.println("Acceptable 🙂");
      break;
    case 3:
      Serial.println("Uncomfortable 😓");
      break;
    case 4:
      Serial.println("Dangerous! ⚠️");
      break;
  }
  
  Serial.println();
  Serial.println("═══════════════════════════════════════════════════════");
  Serial.println("Next reading in 3 seconds...");
  
  delay(3000);
}

// Calculate average of array
float calculateAverage(float arr[], int size) {
  float sum = 0;
  for (int i = 0; i < size; i++) {
    sum += arr[i];
  }
  return sum / size;
}

// Calculate dew point in °C
float calculateDewPoint(float tempC, float humidity) {
  float a = 17.27;
  float b = 237.7;
  float alpha = ((a * tempC) / (b + tempC)) + log(humidity / 100.0);
  return (b * alpha) / (a - alpha);
}

// Calculate heat index in °F
float calculateHeatIndex(float tempF, float humidity) {
  // Rothfusz regression
  float hi = 0.5 * (tempF + 61.0 + ((tempF - 68.0) * 1.2) + (humidity * 0.094));
  
  if (hi > 80) {
    hi = -42.379 + 2.04901523 * tempF + 10.14333127 * humidity
         - 0.22475541 * tempF * humidity - 6.83783 * 0.001 * tempF * tempF
         - 5.481717 * 0.01 * humidity * humidity
         + 1.22874 * 0.001 * tempF * tempF * humidity
         + 8.5282 * 0.0001 * tempF * humidity * humidity
         - 1.99 * 0.000001 * tempF * tempF * humidity * humidity;
    
    if (humidity < 13 && tempF >= 80 && tempF <= 112) {
      hi -= ((13 - humidity) * 0.25) * sqrt((17 - abs(tempF - 95)) / 17);
    } else if (humidity > 85 && tempF >= 80 && tempF <= 87) {
      hi += ((humidity - 85) * 0.1) * ((87 - tempF) * 0.2);
    }
  }
  
  return hi;
}

// Calculate absolute humidity in g/m³
float calculateAbsoluteHumidity(float tempC, float humidity) {
  float tempK = tempC + 273.15;
  float saturationPressure = 6.1078 * pow(10, (7.5 * tempC) / (tempC + 237.3));
  float vaporPressure = (humidity / 100.0) * saturationPressure;
  float absoluteHumidity = (216.7 * vaporPressure) / tempK;
  return absoluteHumidity;
}

// Determine comfort level (0-4)
int getComfortLevel(float tempC, float humidity) {
  // Ideal indoor conditions: 20-25°C, 40-60% RH
  if (tempC >= 20 && tempC <= 25 && humidity >= 40 && humidity <= 60) {
    return 0; // Perfect
  } else if (tempC >= 18 && tempC <= 27 && humidity >= 30 && humidity <= 70) {
    return 1; // Comfortable
  } else if (tempC >= 15 && tempC <= 30 && humidity >= 20 && humidity <= 80) {
    return 2; // Acceptable
  } else if (tempC >= 10 && tempC <= 35 && humidity >= 10 && humidity <= 90) {
    return 3; // Uncomfortable
  } else {
    return 4; // Dangerous
  }
}

Data Processing & Analysis

Understanding the Metrics
Perfect Conditions

20-25°C
40-60% RH

Comfortable

18-27°C
30-70% RH

Uncomfortable

Outside ideal range

Dew Point: Temperature at which air becomes saturated and dew forms. Higher dew points feel more humid.

Heat Index: "Feels like" temperature that combines air temperature and relative humidity. Important for understanding perceived temperature.

Absolute Humidity: Actual amount of water vapor in the air (g/m³). Unlike relative humidity, it doesn't depend on temperature.

Data Smoothing Techniques

Environmental sensors often have noise in their readings. We use smoothing techniques to get more stable values:

  • Moving Average: Average of last N readings (used in our code)
  • Exponential Moving Average: Gives more weight to recent readings
  • Median Filter: Takes middle value of sorted readings
  • Kalman Filter: Advanced statistical filter (best for dynamic systems)
Temperature-Humidity Relationship

Warmer air can hold more moisture. This is why:

  • Relative humidity changes with temperature even if moisture content is constant
  • Cold rooms often feel "drier" even with same absolute humidity
  • Air conditioning reduces both temperature and humidity
  • Heating increases temperature but decreases relative humidity

Formula: RH = (actual water vapor / saturation vapor pressure) × 100%

Project 1: Complete Weather Station

Combine DHT20 with other sensors to create a complete weather station:

weather_station.ino
/*
  Vumbua Synapse Kit - Complete Weather Station
  Combines DHT20 with other sensors for comprehensive monitoring
*/

#include <DFRobot_DHT20.h>
#include <Wire.h>

DFRobot_DHT20 dht20;

// Weather data structure
struct WeatherData {
  float temperatureC;
  float temperatureF;
  float humidity;
  float dewPoint;
  float heatIndex;
  unsigned long timestamp;
};

WeatherData currentWeather;
const int MAX_RECORDS = 100;
WeatherData weatherHistory[MAX_RECORDS];
int historyIndex = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);
  
  initializeDHT20();
  
  Serial.println("🌤️ Vumbua Weather Station v1.0 🌤️");
  Serial.println("================================");
}

void loop() {
  // Read sensor data
  readWeatherData();
  
  // Store in history
  weatherHistory[historyIndex] = currentWeather;
  historyIndex = (historyIndex + 1) % MAX_RECORDS;
  
  // Display current conditions
  displayCurrentWeather();
  
  // Display statistics every 10 readings
  static int displayCount = 0;
  if (++displayCount % 10 == 0) {
    displayStatistics();
  }
  
  delay(5000); // Read every 5 seconds
}

void initializeDHT20() {
  Serial.print("Initializing DHT20 at address 0x38...");
  
  if (dht20.begin() == 0) {
    Serial.println(" OK");
    
    // Optional: Read sensor information
    uint16_t version = dht20.readDeviceID();
    Serial.print("Device ID: 0x");
    Serial.println(version, HEX);
  } else {
    Serial.println(" FAILED");
    Serial.println("Please check:");
    Serial.println("1. I2C connections (SDA=D4, SCL=D3)");
    Serial.println("2. Power supply (3.3V)");
    Serial.println("3. Run I2C scanner to verify address");
    delay(10000);
  }
}

void readWeatherData() {
  currentWeather.temperatureC = dht20.getTemperature();
  currentWeather.temperatureF = currentWeather.temperatureC * 9.0 / 5.0 + 32.0;
  currentWeather.humidity = dht20.getHumidity();
  currentWeather.timestamp = millis();
  
  // Calculate derived values
  currentWeather.dewPoint = calculateDewPoint(currentWeather.temperatureC, currentWeather.humidity);
  currentWeather.heatIndex = calculateHeatIndex(currentWeather.temperatureF, currentWeather.humidity);
}

void displayCurrentWeather() {
  // Clear screen (simulate)
  for (int i = 0; i < 30; i++) Serial.println();
  
  Serial.println("┌─────────────────────────────────────────────┐");
  Serial.println("│           CURRENT WEATHER CONDITIONS         │");
  Serial.println("├─────────────────────────────────────────────┤");
  
  Serial.print("│ Temperature: ");
  Serial.print(currentWeather.temperatureC, 1);
  Serial.print("°C (");
  Serial.print(currentWeather.temperatureF, 1);
  Serial.println("°F)           │");
  
  Serial.print("│ Humidity:    ");
  Serial.print(currentWeather.humidity, 1);
  Serial.println("% RH                     │");
  
  Serial.print("│ Dew Point:   ");
  Serial.print(currentWeather.dewPoint, 1);
  Serial.println("°C                       │");
  
  Serial.print("│ Heat Index:  ");
  Serial.print(currentWeather.heatIndex, 1);
  Serial.println("°F                       │");
  
  // Display comfort indicator
  Serial.print("│ Comfort:     ");
  float comfortScore = calculateComfortScore(currentWeather.temperatureC, currentWeather.humidity);
  displayComfortBar(comfortScore);
  Serial.println(" │");
  
  Serial.println("└─────────────────────────────────────────────┘");
  Serial.println();
}

void displayComfortBar(float score) {
  int bars = map(score, 0, 100, 0, 20);
  Serial.print("[");
  for (int i = 0; i < 20; i++) {
    if (i < bars) {
      Serial.print("█");
    } else {
      Serial.print(" ");
    }
  }
  Serial.print("] ");
  Serial.print((int)score);
  Serial.print("%");
}

float calculateComfortScore(float tempC, float humidity) {
  // Calculate distance from ideal point (22.5°C, 50% RH)
  float tempDiff = abs(tempC - 22.5);
  float humDiff = abs(humidity - 50.0);
  
  // Normalize differences (max penalty: 15°C diff or 50% RH diff)
  float tempPenalty = min(tempDiff / 15.0 * 50, 50);
  float humPenalty = min(humDiff / 50.0 * 50, 50);
  
  // Start from 100%, subtract penalties
  return 100 - (tempPenalty + humPenalty) / 2;
}

void displayStatistics() {
  if (historyIndex == 0) return;
  
  float minTemp = 1000, maxTemp = -1000, sumTemp = 0;
  float minHum = 1000, maxHum = -1000, sumHum = 0;
  int count = 0;
  
  for (int i = 0; i < historyIndex; i++) {
    if (weatherHistory[i].temperatureC < minTemp) minTemp = weatherHistory[i].temperatureC;
    if (weatherHistory[i].temperatureC > maxTemp) maxTemp = weatherHistory[i].temperatureC;
    if (weatherHistory[i].humidity < minHum) minHum = weatherHistory[i].humidity;
    if (weatherHistory[i].humidity > maxHum) maxHum = weatherHistory[i].humidity;
    
    sumTemp += weatherHistory[i].temperatureC;
    sumHum += weatherHistory[i].humidity;
    count++;
  }
  
  float avgTemp = sumTemp / count;
  float avgHum = sumHum / count;
  
  Serial.println("📊 WEATHER STATISTICS (Last " + String(count) + " readings)");
  Serial.println("=========================================");
  Serial.print("Temperature: Avg ");
  Serial.print(avgTemp, 1);
  Serial.print("°C (Min ");
  Serial.print(minTemp, 1);
  Serial.print("°C, Max ");
  Serial.print(maxTemp, 1);
  Serial.println("°C)");
  
  Serial.print("Humidity:    Avg ");
  Serial.print(avgHum, 1);
  Serial.print("% (Min ");
  Serial.print(minHum, 1);
  Serial.print("%, Max ");
  Serial.print(maxHum, 1);
  Serial.println("%)");
  Serial.println();
}

// Include the calculation functions from previous examples
float calculateDewPoint(float tempC, float humidity) {
  // Same as previous implementation
  float a = 17.27;
  float b = 237.7;
  float alpha = ((a * tempC) / (b + tempC)) + log(humidity / 100.0);
  return (b * alpha) / (a - alpha);
}

float calculateHeatIndex(float tempF, float humidity) {
  // Same as previous implementation
  float hi = 0.5 * (tempF + 61.0 + ((tempF - 68.0) * 1.2) + (humidity * 0.094));
  
  if (hi > 80) {
    // Rothfusz regression (same as before)
    hi = -42.379 + 2.04901523 * tempF + 10.14333127 * humidity
         - 0.22475541 * tempF * humidity - 6.83783 * 0.001 * tempF * tempF
         - 5.481717 * 0.01 * humidity * humidity
         + 1.22874 * 0.001 * tempF * tempF * humidity
         + 8.5282 * 0.0001 * tempF * humidity * humidity
         - 1.99 * 0.000001 * tempF * tempF * humidity * humidity;
    
    if (humidity < 13 && tempF >= 80 && tempF <= 112) {
      hi -= ((13 - humidity) * 0.25) * sqrt((17 - abs(tempF - 95)) / 17);
    } else if (humidity > 85 && tempF >= 80 && tempF <= 87) {
      hi += ((humidity - 85) * 0.1) * ((87 - tempF) * 0.2);
    }
  }
  
  return hi;
}

Project 2: Indoor Comfort Monitor

Create a comfort monitoring system that provides visual feedback:

comfort_monitor.ino
/*
  Vumbua Synapse Kit - Indoor Comfort Monitor
  Uses LED and buzzer to indicate comfort levels
*/

#include <DFRobot_DHT20.h>

DFRobot_DHT20 dht20;

// LED pins for visual feedback
const int LED_GREEN = 8;
const int LED_YELLOW = 9;
const int LED_RED = 10;
const int BUZZER = 3;

void setup() {
  Serial.begin(9600);
  
  // Initialize DHT20
  while (dht20.begin() != 0) {
    Serial.println("DHT20 initialization failed!");
    delay(2000);
  }
  
  // Setup LED pins
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_YELLOW, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  
  // Startup sequence
  startupSequence();
  
  Serial.println("Comfort Monitor Ready!");
  Serial.println("======================");
}

void loop() {
  // Read temperature and humidity
  float tempC = dht20.getTemperature();
  float humidity = dht20.getHumidity();
  
  // Determine comfort level
  int comfortLevel = checkComfortLevel(tempC, humidity);
  
  // Update indicators
  updateIndicators(comfortLevel);
  
  // Display information
  displayComfortInfo(tempC, humidity, comfortLevel);
  
  delay(3000);
}

void startupSequence() {
  digitalWrite(LED_GREEN, HIGH);
  delay(200);
  digitalWrite(LED_YELLOW, HIGH);
  delay(200);
  digitalWrite(LED_RED, HIGH);
  delay(200);
  
  tone(BUZZER, 1000, 100);
  delay(100);
  tone(BUZZER, 1500, 100);
  delay(100);
  tone(BUZZER, 2000, 100);
  
  digitalWrite(LED_GREEN, LOW);
  digitalWrite(LED_YELLOW, LOW);
  digitalWrite(LED_RED, LOW);
}

int checkComfortLevel(float tempC, float humidity) {
  // Level 0: Perfect (20-25°C, 40-60% RH)
  if (tempC >= 20 && tempC <= 25 && humidity >= 40 && humidity <= 60) {
    return 0;
  }
  
  // Level 1: Good (18-27°C, 30-70% RH)
  if (tempC >= 18 && tempC <= 27 && humidity >= 30 && humidity <= 70) {
    return 1;
  }
  
  // Level 2: Acceptable (15-30°C, 20-80% RH)
  if (tempC >= 15 && tempC <= 30 && humidity >= 20 && humidity <= 80) {
    return 2;
  }
  
  // Level 3: Poor (10-35°C, 10-90% RH)
  if (tempC >= 10 && tempC <= 35 && humidity >= 10 && humidity <= 90) {
    return 3;
  }
  
  // Level 4: Dangerous (outside above ranges)
  return 4;
}

void updateIndicators(int level) {
  // Turn off all LEDs first
  digitalWrite(LED_GREEN, LOW);
  digitalWrite(LED_YELLOW, LOW);
  digitalWrite(LED_RED, LOW);
  
  // Turn on appropriate LED(s)
  switch (level) {
    case 0: // Perfect - Green steady
      digitalWrite(LED_GREEN, HIGH);
      noTone(BUZZER);
      break;
      
    case 1: // Good - Green blinking
      digitalWrite(LED_GREEN, HIGH);
      delay(500);
      digitalWrite(LED_GREEN, LOW);
      noTone(BUZZER);
      break;
      
    case 2: // Acceptable - Yellow steady
      digitalWrite(LED_YELLOW, HIGH);
      tone(BUZZER, 1000, 100);
      break;
      
    case 3: // Poor - Yellow blinking
      digitalWrite(LED_YELLOW, HIGH);
      tone(BUZZER, 1500, 200);
      delay(500);
      digitalWrite(LED_YELLOW, LOW);
      delay(500);
      break;
      
    case 4: // Dangerous - Red blinking fast with alarm
      digitalWrite(LED_RED, HIGH);
      tone(BUZZER, 2000, 300);
      delay(300);
      digitalWrite(LED_RED, LOW);
      tone(BUZZER, 1500, 300);
      delay(300);
      break;
  }
}

void displayComfortInfo(float tempC, float humidity, int level) {
  static int lastLevel = -1;
  
  if (level != lastLevel) {
    Serial.println("\n--- Comfort Level Changed ---");
    lastLevel = level;
  }
  
  Serial.print("Temp: ");
  Serial.print(tempC, 1);
  Serial.print("°C, Hum: ");
  Serial.print(humidity, 1);
  Serial.print("%, Level: ");
  
  switch (level) {
    case 0: Serial.println("PERFECT 🎯"); break;
    case 1: Serial.println("GOOD 👍"); break;
    case 2: Serial.println("ACCEPTABLE 👌"); break;
    case 3: Serial.println("POOR ⚠️"); break;
    case 4: Serial.println("DANGEROUS 🚨"); break;
  }
}

Advanced I2C Topics

I2C Clock Stretching

The DHT20 uses clock stretching during measurements. This means:

  • Sensor pulls SCL line LOW when busy
  • Master (Vumbua) must wait for SCL to go HIGH again
  • Measurement takes ~80ms, during which sensor stretches clock
  • Wire library handles this automatically

Why clock stretching matters: Ensures master doesn't try to read data before sensor is ready.

Multiple I2C Devices

You can connect multiple I2C devices to the same bus:

  • DHT20: Address 0x38
  • Light Sensor (from Lesson 5): Different address
  • OLED Display: Typically 0x3C or 0x3D
  • Each device must have unique address
Multiple Device Example
Wire.begin();  // Initialize I2C once

// Read from DHT20 (0x38)
Wire.beginTransmission(0x38);
// ... DHT20 commands ...

// Read from another device
Wire.beginTransmission(OTHER_ADDRESS);
// ... Other device commands ...
I2C Speed Settings

By default, Wire library uses 100kHz. You can change this:

Wire.begin();          // Default 100kHz
Wire.setClock(400000); // Set to 400kHz (Fast Mode)

Note: DHT20 supports up to 400kHz. Higher speeds mean:

  • Faster communication
  • More susceptible to noise
  • Shorter maximum cable length

Troubleshooting Guide

  1. Check connections: SDA=D4, SCL=D3, VCC=3.3V, GND=GND
  2. Verify power: Use multimeter to check 3.3V at VCC pin
  3. Check pull-up resistors: Vumbua has built-in 4.7kΩ resistors
  4. Try different I2C speed: Add Wire.setClock(100000); in setup()
  5. Test with known working sensor: Rule out hardware issues

  1. Check sensor placement: Avoid direct sunlight, heat sources, or drafts
  2. Allow warm-up time: Sensors need 1-2 minutes to stabilize
  3. Verify library version: Use latest DFRobot_DHT20 library
  4. Add delay between readings: DHT20 needs ~1.5 seconds between measurements
  5. Check for electrical noise: Add 0.1μF capacitor between VCC and GND

  1. Check power supply stability: Use separate 3.3V regulator if needed
  2. Reduce I2C speed: Try 100kHz instead of 400kHz
  3. Check cable length: Keep I2C cables short (< 20cm)
  4. Add stronger pull-ups: Add external 2.2kΩ resistors on SDA/SCL
  5. Implement error recovery: Add retry logic in your code
Error Recovery Code
// Retry logic example
int retries = 3;
while (retries > 0) {
    if (dht20.begin() == 0) {
        break; // Success
    }
    retries--;
    delay(100);
}
if (retries == 0) {
    // Handle permanent failure
}

Video Tutorial

Video Tutorial Coming Soon!

We're preparing a detailed video walkthrough for DHT20 sensor with Vumbua Synapse Kit.

Subscribe to our YouTube channel to be notified when it's available.

Subscribe to OLSPACE

Resources & Downloads

Project Ideas
  • Smart Greenhouse: Control fans and lights based on temperature/humidity
  • Baby Room Monitor: Alert if temperature/humidity goes outside safe range
  • Wine Cellar Monitor: Maintain optimal storage conditions
  • Weather Data Logger: Record data to SD card for analysis
  • HVAC Control System: Automatically adjust heating/cooling