Greenhouse Monitoring: Auto-Adjusting Fan/Shade Based on Temperature, Humidity, and Light
Intermediate1/8/2026- Author: IoTSpark Maker

Greenhouse Monitoring: Auto-Adjusting Fan/Shade Based on Temperature, Humidity, and Light

Uses an ESP32 + DHT22 + LDR light sensor to monitor greenhouse temperature, humidity, and light, automatically switching on a cooling fan when it's too hot and closing a shade when sunlight is intense — via two relays, saving energy.

esp32greenhousedht22light-sensorrelaysmart-farmsmart-agriculture
0 steps6 components

Project Overview: Smart Greenhouse Monitoring

The "Greenhouse Monitoring: auto-adjusting fan/shade based on temperature/humidity/light" project is a fun IoT application using an ESP32, a DHT22 sensor, and an LDR light sensor to monitor and control the greenhouse environment. The goal is to automate the cooling fan and shade whenever temperature or light exceed set thresholds, saving energy and keeping growing conditions optimal.

What Will You Learn?

  • How to use an ESP32 to collect data from sensors.
  • How to wire up and program a DHT22 sensor to measure temperature and humidity.
  • How to use an LDR light sensor to detect light levels.
  • How to drive relays to automatically switch the fan and shade.
  • How to manage data and optimize energy use in a greenhouse system.

Key Features

  • Temperature & Humidity Monitoring: Uses a DHT22 sensor to track environmental conditions.
  • Light Sensing: An LDR sensor determines the greenhouse's light level.
  • Automatic Control: The system turns on the cooling fan when it's hot and closes the shade when light is intense.
  • ESP32 Integration: An ESP32 microcontroller connects and drives the sensors and relays.
  • Energy Optimization: Minimizes power consumption while keeping ideal growing conditions for plants.

Why Is This Project Worth Building?

This project doesn't just teach core IoT concepts — it gives you hands-on skills in programming and designing automated systems. Applying technology to smart agriculture is becoming more common and meaningful for improving crop yield and quality. It also focuses on saving energy, helping protect the environment and support sustainable development. As technology advances rapidly, IoT solutions in agriculture will keep opening up new opportunities for farmers and researchers alike.

Detailed guide

Uses an ESP32 + DHT22 + LDR light sensor to monitor greenhouse temperature, humidity, and light, automatically switching on a cooling fan when it's too hot and closing a shade when sunlight is intense — via two relays, saving energy.

1. Introduction

A greenhouse helps control the microclimate for plants, but manually watching temperature, humidity, and light is labor-intensive and easy to get wrong when the weather shifts suddenly. This project uses an ESP32 with a DHT22 sensor (temperature/humidity) and an LDR light-sensor module (light) to continuously monitor conditions inside the greenhouse, then automatically switches on a cooling fan when the temperature crosses a threshold and closes a shade when sunlight is too intense, via 2 independent relays driving 2 separate loads (fan and motor/shade).

The system uses hysteresis (a different on-threshold than off-threshold) to avoid the relay rapidly cycling on/off when the sensor reading hovers near the threshold — keeping the fan and shade running longer and reducing wear on the relay contacts.

2. Components Needed

ComponentQtyReference Price
ESP32 DevKit V1 (30-pin)1~90,000 - 120,000₫
DHT22 (AM2302) — Temperature & Humidity1~45,000 - 60,000₫
LDR Module — Photoresistor Light Sensor1~10,000 - 15,000₫
1-Channel Relay Module — 5V (fan control)1~20,000 - 30,000₫
1-Channel Relay Module — 5V (shade/motor control)1~20,000 - 30,000₫
Jumper wires, breadboard, 5V power supply for the relays/fan1 set~20,000 - 40,000₫

Safety note:

  • The fan/shade motor typically runs off its own AC or DC power through the relay's NO/COM contact — never feed mains power directly into the ESP32.

  • If switching an AC load, have an experienced electrician handle the wiring and isolation.

3. Wiring Diagram

DHT22ESP32
VCC3V3
GNDGND
DATAGPIO27
LDR moduleESP32
VCC3V3
GNDGND
AO (Analog Out)GPIO34 (ADC1_CH6, input-only)
Relay 1 (Cooling Fan)ESP32
VCCVIN (5V)
GNDGND
INGPIO26
Relay 2 (Shade)ESP32
VCCVIN (5V)
GNDGND
INGPIO25

Important note:

  • The relay module's coil runs on 5V — its VCC must come from the ESP32's VIN (5V) pin, NOT the 3V3 pin, or the relay won't get enough voltage to close its contacts reliably (a very common wiring mistake).

  • The relay's IN pin is active-low: a LOW level activates the contact.

4. Example #1 — Reading the Sensors and Printing JSON over Serial

#include <DHT.h>

#define DHTPIN     27
#define DHTTYPE    DHT22
#define LDR_PIN    34

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
}

void loop() {
  float humidity = dht.readHumidity();
  float tempC = dht.readTemperature();
  int lightRaw = analogRead(LDR_PIN);

  if (isnan(humidity) || isnan(tempC)) {
    Serial.println("Loi doc DHT22!");
  } else {
    Serial.print("Nhiet do: "); Serial.print(tempC); Serial.println(" *C");
    Serial.print("Do am: "); Serial.print(humidity); Serial.println(" %");
    Serial.print("Anh sang (raw ADC): "); Serial.println(lightRaw);
  }

  delay(2000); // DHT22 can toi thieu 2s giua 2 lan doc
}

5. Example #2 — Controlling a Relay with a Fixed Threshold (No Hysteresis)

#define RELAY_FAN_PIN 26
#define RELAY_ON  LOW
#define RELAY_OFF HIGH

const float TEMP_THRESHOLD = 32.0;

void setup() {
  pinMode(RELAY_FAN_PIN, OUTPUT);
  digitalWrite(RELAY_FAN_PIN, RELAY_OFF);
}

void loop() {
  float tempC = 33.5; // thay bang gia tri doc tu DHT22 thuc te
  if (tempC > TEMP_THRESHOLD) {
    digitalWrite(RELAY_FAN_PIN, RELAY_ON); // bat quat
  } else {
    digitalWrite(RELAY_FAN_PIN, RELAY_OFF); // tat quat
  }
  delay(2000);
}

6. Example #3 — The Real Application: Full Greenhouse Monitoring with Hysteresis

/*
  Giam sat nha kinh: nhiet do / do am / anh sang tu dong dieu chinh quat/mai che
  Board: ESP32 DevKit V1 (30 pins)
  Cam bien: DHT22 (nhiet do/do am), LDR module (anh sang)
  Co cau chap hanh: Relay 1 kenh x2 (quat lam mat, mai che/motor bong)

  Wiring (khop voi diagram tren IoTLabs Maker):
    DHT22   DATA -> GPIO27      VCC -> 3V3   GND -> GND
    LDR     AO   -> GPIO34 (ADC1_CH6, input-only)   VCC -> 3V3   GND -> GND
    Relay1 (quat)     IN -> GPIO26   VCC -> VIN(5V)  GND -> GND
    Relay2 (mai che)  IN -> GPIO25   VCC -> VIN(5V)  GND -> GND

  Nguong dieu khien (co the tuy chinh qua Serial hoac hard-code):
    - Bat quat khi nhiet do > TEMP_FAN_ON
    - Bat mai che (che nang) khi anh sang (LDR) > LIGHT_SHADE_ON (sang gat)
*/

#include <DHT.h>

#define DHTPIN     27
#define DHTTYPE    DHT22
#define LDR_PIN    34
#define RELAY_FAN_PIN   26
#define RELAY_SHADE_PIN 25

// Relay module active-low: LOW = kich hoat (dong tiep diem)
#define RELAY_ON  LOW
#define RELAY_OFF HIGH

const float TEMP_FAN_ON   = 32.0;  // *C - bat quat khi vuot nguong
const float TEMP_FAN_OFF  = 29.0;  // *C - tat quat (hysteresis tranh dong tat lien tuc)
const int   LIGHT_SHADE_ON  = 2800; // ADC raw (0-4095), cang lon = cang toi -> tuy module
const int   LIGHT_SHADE_OFF = 1800;

DHT dht(DHTPIN, DHTTYPE);

bool fanState = false;
bool shadeState = false;

unsigned long lastRead = 0;
const unsigned long READ_INTERVAL_MS = 2000; // DHT22 lay mau toi thieu 2s/lan

void applyRelay(int pin, bool on) {
  digitalWrite(pin, on ? RELAY_ON : RELAY_OFF);
}

void setup() {
  Serial.begin(115200);
  delay(300);
  Serial.println();
  Serial.println(F("=== Giam sat nha kinh IoTLabs - Boot OK ==="));

  pinMode(RELAY_FAN_PIN, OUTPUT);
  pinMode(RELAY_SHADE_PIN, OUTPUT);
  applyRelay(RELAY_FAN_PIN, false);
  applyRelay(RELAY_SHADE_PIN, false);

  dht.begin();
  Serial.println(F("DHT22 + LDR + 2 Relay san sang. Bat dau vong lap giam sat."));
}

void loop() {
  unsigned long now = millis();
  if (now - lastRead < READ_INTERVAL_MS) {
    return;
  }
  lastRead = now;

  float humidity = dht.readHumidity();
  float tempC = dht.readTemperature();
  int lightRaw = analogRead(LDR_PIN);

  bool dhtOk = !(isnan(humidity) || isnan(tempC));

  if (!dhtOk) {
    // Cam bien loi/chua on dinh -> bao cao degrade, khong dieu khien mu quang theo du lieu rac
    Serial.print(F("{\"temp_c\":null,\"humidity\":null,\"light_raw\":"));
    Serial.print(lightRaw);
    Serial.print(F(",\"fan\":"));
    Serial.print(fanState ? "true" : "false");
    Serial.print(F(",\"shade\":"));
    Serial.print(shadeState ? "true" : "false");
    Serial.println(F(",\"status\":\"dht_error\"}"));
    return;
  }

  // Hysteresis dieu khien quat theo nhiet do
  if (!fanState && tempC > TEMP_FAN_ON) {
    fanState = true;
    applyRelay(RELAY_FAN_PIN, true);
  } else if (fanState && tempC < TEMP_FAN_OFF) {
    fanState = false;
    applyRelay(RELAY_FAN_PIN, false);
  }

  // Hysteresis dieu khien mai che theo anh sang (raw ADC cang cao = cang toi tuy module)
  if (!shadeState && lightRaw > LIGHT_SHADE_ON) {
    shadeState = true;
    applyRelay(RELAY_SHADE_PIN, true);
  } else if (shadeState && lightRaw < LIGHT_SHADE_OFF) {
    shadeState = false;
    applyRelay(RELAY_SHADE_PIN, false);
  }

  Serial.print(F("{\"temp_c\":"));
  Serial.print(tempC, 1);
  Serial.print(F(",\"humidity\":"));
  Serial.print(humidity, 1);
  Serial.print(F(",\"light_raw\":"));
  Serial.print(lightRaw);
  Serial.print(F(",\"fan\":"));
  Serial.print(fanState ? "true" : "false");
  Serial.print(F(",\"shade\":"));
  Serial.print(shadeState ? "true" : "false");
  Serial.println(F(",\"status\":\"ok\"}"));
}

7. Common Issues

IssueCauseFix
DHT22 keeps returning NaNReading too fast (under 2s apart), no pull-up resistor on the DATA line, or the wire is too longMake sure there's a delay of at least 2000ms between reads; add a 10kΩ pull-up resistor between DATA and VCC if using a bare sensor
The relay doesn't close its contact even though the GPIO is set LOWThe relay's VCC is wired to 3V3 instead of VIN (5V) — not enough voltage to energize the coilPower the relay from the ESP32's VIN (5V) pin, not 3V3
The fan/shade keeps switching on/off rapidly (relay chattering)The on and off thresholds are the same, and the sensor reading hovers around that valueUse hysteresis: set the off-threshold a few degrees lower than the on-threshold (as in example #3)
The LDR reading stays the same regardless of light/dark conditionsReading the DO (digital) pin instead of AO (analog), or the module's onboard potentiometer isn't adjustedUse analogRead() on the AO pin; adjust the module's potentiometer if you need a wider sensing range

8. Summary

This greenhouse monitoring system automates the two most important responses in greenhouse agriculture: cooling when it's too hot and shading when sunlight is too intense, without needing someone watching continuously. The hysteresis mechanism protects relay lifespan and avoids unnecessary control oscillation.

You can extend it by sending the JSON data over MQTT/WiFi to a dashboard for remote monitoring, or adding a soil-moisture sensor for automatic irrigation — turning this into a complete smart greenhouse system.