Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

ESP8266 NodeMCU Automated Soil Moisture Monitoring and Watering System

View and Edit Project In Cirkit DesignerImage of ESP8266 NodeMCU Automated Soil Moisture Monitoring and Watering System

Circuit Documentation

Summary

This circuit is designed to monitor and control the watering of soil using a NodeMCU V3 ESP8266 microcontroller. It includes two soil moisture sensors to measure the moisture level of the soil at different depths, an HC-SR04 ultrasonic sensor to monitor the water level in a reservoir, and a water pump to irrigate the soil when necessary. The system is powered by a 5V battery and is capable of activating an alarm if the water level is too low.

Component List

NodeMCU V3 ESP8266

Soil Moisture Sensor (x2)

HC-SR04 Ultrasonic Sensor

5V Battery

Water Pump

Wiring Details

NodeMCU V3 ESP8266

Soil Moisture Sensor

HC-SR04 Ultrasonic Sensor

5V Battery

Water Pump

Documented Code

// Soil Moisture Sensor Pins and Variables
#define topSoilVcc D1          // GPIO pin to power the top soil sensor
#define bottomSoilVcc D2       // GPIO pin to power the bottom soil sensor
#define soilMoisturePin A0     // Analog pin to read moisture level (shared by both sensors)
int topMoistureValue;          // Store moisture sensor value for the top soil
int bottomMoistureValue;       // Store moisture sensor value for the bottom soil
int moistureThreshold = 300;   // Threshold value for soil moisture

// Ultrasonic Sensor Pins and Variables
#define trigPin D5             // Trig pin of Ultrasonic Sensor
#define echoPin D6             // Echo pin of Ultrasonic Sensor
long duration;
int distance;
int waterLevelThreshold = 20;  // Set threshold for low water level in cm

// Water Pump Pin
#define pumpRelay D7           // Relay module controlling the pump

// Alarm Pin (Buzzer or LED for low water alert)
#define alarmPin D8            // Alarm pin for low water level

// Timing Variables
unsigned long previousMillis = 0;  // Store the last time sensor was checked
const long interval = 10800000;    // 3 hours interval in milliseconds (10800000)

// Total Water Used Calculation
int pumpIterations = 0;            // Number of times the pump has been activated

void setup() {
  Serial.begin(9600);

  // Pin modes
  pinMode(pumpRelay, OUTPUT);
  digitalWrite(pumpRelay, LOW);  // Ensure pump is initially off
  
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  pinMode(alarmPin, OUTPUT);
  digitalWrite(alarmPin, LOW);   // Ensure alarm is initially off

  // Set soil sensor VCC control pins as outputs
  pinMode(topSoilVcc, OUTPUT);
  pinMode(bottomSoilVcc, OUTPUT);

  // Ensure both sensors are initially off
  digitalWrite(topSoilVcc, LOW);
  digitalWrite(bottomSoilVcc, LOW);
}

// Function to read top soil moisture level
int readTopSoilMoisture() {
  digitalWrite(bottomSoilVcc, LOW);    // Ensure bottom sensor is off
  digitalWrite(topSoilVcc, HIGH);      // Power the top soil sensor
  delay(500);                          // Give time for sensor to stabilize
  int value = analogRead(soilMoisturePin);  // Read the value from analog pin
  digitalWrite(topSoilVcc, LOW);       // Turn off the top soil sensor
  return value;
}

// Function to read bottom soil moisture level
int readBottomSoilMoisture() {
  digitalWrite(topSoilVcc, LOW);       // Ensure top sensor is off
  digitalWrite(bottomSoilVcc, HIGH);   // Power the bottom soil sensor
  delay(500);                          // Give time for sensor to stabilize
  int value = analogRead(soilMoisturePin);  // Read the value from analog pin
  digitalWrite(bottomSoilVcc, LOW);    // Turn off the bottom soil sensor
  return value;
}

// Function to read water level using the ultrasonic sensor
int readWaterLevel() {
  // Send a trigger pulse
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // Read echo time
  duration = pulseIn(echoPin, HIGH);

  // Calculate the distance in cm
  int distance = duration * 0.034 / 2;
  Serial.print("Water level distance: ");
  Serial.print(distance);
  Serial.println(" cm");

  return distance;
}

// Function to activate the pump for watering
void activatePump() {
  Serial.println("Turning on the water pump...");
  digitalWrite(pumpRelay, HIGH);  // Turn on the pump
  delay(10000);                   // Pump water for 10 seconds
  digitalWrite(pumpRelay, LOW);   // Turn off the pump
  pumpIterations++;               // Count the pump cycle
  Serial.println("Pump turned off.");
}

// Function to check water level and raise alarm if low
bool checkWaterLevelAndAlarm() {
  int waterLevel = readWaterLevel();
  if (waterLevel > waterLevelThreshold) {
    Serial.println("Water level is too low! Raising alarm...");
    digitalWrite(alarmPin, HIGH);  // Turn on alarm (Buzzer or LED)
    return false;  // Break the loop and stop watering
  } else {
    Serial.println("Water level is sufficient.");
    digitalWrite(alarmPin, LOW);   // Turn off alarm
    return true;  // Continue with the process
  }
}

// Main loop function
void loop() {
  // Timing control: Check every 3 hours
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    pumpIterations = 0;  // Reset pump iteration count for this cycle

    // Read the soil moisture levels
    topMoistureValue = readTopSoilMoisture();
    bottomMoistureValue = readBottomSoilMoisture();
    Serial.print("Top Soil Moisture Level: ");
    Serial.println(topMoistureValue);
    Serial.print("Bottom Soil Moisture Level: ");
    Serial.println(bottomMoistureValue);

    // Check if either top or bottom soil moisture is below the threshold
    if (topMoistureValue < moistureThreshold || bottomMoistureValue < moistureThreshold) {
      Serial.println("Moisture level is below threshold, checking water level...");

      // Continue watering while either sensor is below the threshold
      while (topMoistureValue < moistureThreshold || bottomMoistureValue < moistureThreshold) {
        // Check water level before each iteration
        if (!checkWaterLevelAndAlarm()) {
          Serial.println("Watering process aborted due to low water level.");
          break;  // Break