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

ESP32C3 Smart Irrigation System with OLED Display and Soil Moisture Sensor

View and Edit Project In Cirkit DesignerImage of ESP32C3 Smart Irrigation System with OLED Display and Soil Moisture Sensor

Circuit Documentation

Summary

This circuit is designed to automate the watering of plants using a capacitive soil moisture sensor, an ESP32C3 microcontroller, and a 5V mini water pump. The system reads the soil moisture level and activates the water pump when the moisture level falls below a predefined threshold. The circuit also includes an OLED display for real-time monitoring and pushbuttons for user interaction.

Component List

  1. ESP32C3 Supermini

    • Description: A microcontroller with Wi-Fi and Bluetooth capabilities.
    • Pins: GPIO05, GPIO06, GPIO07, GPIO08, GPIO09, GPIO10, GPIO20, GPIO21, GPIO00, GPIO01, GPIO02, GPIO03, GPIO04, 3.3V, GND, +5V
  2. 0.96" OLED

    • Description: A small OLED display for visual output.
    • Pins: GND, VDD, SCK, SDA
  3. DFRobot Capacitive Soil Moisture Sensor (V1.0)

    • Description: A sensor to measure soil moisture levels.
    • Pins: A, VCC, GND
  4. Pushbutton (4 units)

    • Description: Buttons for user input.
    • Pins: Pin 3 (out), Pin 4 (out), Pin 1 (in), Pin 2 (in)
  5. 5V Mini Water Pump

    • Description: A small water pump for irrigation.
    • Pins: positive pin, negative pin
  6. 5V Battery

    • Description: Power source for the circuit.
    • Pins: +, -

Wiring Details

ESP32C3 Supermini

0.96" OLED

DFRobot Capacitive Soil Moisture Sensor (V1.0)

Pushbuttons

5V Mini Water Pump

5V Battery

Code Documentation

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include <AT24C256.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define AT24C256_ADDRESS 0x50
AT24C256 eeprom(AT24C256_ADDRESS);

// EEPROM Address Constants
#define EEPROM_DRY_VALUE_ADDR 0
#define EEPROM_WET_VALUE_ADDR (EEPROM_DRY_VALUE_ADDR + sizeof(int))
#define EEPROM_LOW_THRESHOLD_ADDR (EEPROM_WET_VALUE_ADDR + sizeof(int))
#define EEPROM_HIGH_THRESHOLD_ADDR (EEPROM_LOW_THRESHOLD_ADDR + sizeof(int))
#define EEPROM_PUMP_DURATION_ADDR (EEPROM_HIGH_THRESHOLD_ADDR + sizeof(int))
#define EEPROM_WAIT_DURATION_ADDR (EEPROM_PUMP_DURATION_ADDR + sizeof(int))

// Pin definitions
#define SOIL_SENSOR_PIN A4     // ADC pin for soil moisture sensor
#define PUMP_PIN 10            // Pump control pin
#define MODE_BTN 0             // Mode button pin
#define SELECT_BTN 1           // Select button pin
#define UP_BTN 2               // Up button pin
#define DOWN_BTN 3             // Down button pin

// Screen states
enum Screen {
  MAIN_SCREEN,
  CALIBRATION,
  SET_THRESHOLD,
  SET_DURATION,
  MANUAL
};

enum CalibrationOption {
  DRY,
  WET
};

enum ThresholdOption {
  LOW_THRESHOLD,
  HIGH_THRESHOLD
};

enum DurationOption {
  PUMP_DURATION,
  WAIT_DURATION
};

// Variables
Screen currentScreen = MAIN_SCREEN;
CalibrationOption currentCalibrationOption = DRY;
ThresholdOption currentThresholdOption = LOW_THRESHOLD;
DurationOption currentDurationOption = PUMP_DURATION;
int moistureValue = 0;
int moisturePercent = 0;
int threshold_low = 30;
int threshold_high = 80;
int pumpDuration = 10000;    // 10 seconds in milliseconds
int waitDuration = 20000;    // 20 seconds in milliseconds
bool isPumping = false;
bool canPump = true;         
unsigned long pumpStartTime = 0;
unsigned long waitStartTime = 0;
unsigned long lastReadTime = 0;

// Calibration values
int dryValue = 3460;    
int wetValue = 1240;    

// Change tracking
bool calibrationChanged = false;
bool thresholdChanged = false;
bool durationChanged = false;

void saveToEEPROM() {
  EEPROM.put(EEPROM_DRY_VALUE_ADDR, dryValue);
  EEPROM.put(EEPROM_WET_VALUE_ADDR, wetValue);
  EEPROM.put(EEPROM_LOW_THRESHOLD_ADDR, threshold_low);
  EEPROM.put(EEPROM_HIGH_THRESHOLD_ADDR, threshold_high);
  EEPROM.put(EEPROM_PUMP_DURATION_ADDR, pumpDuration);
  EEPROM.put(EEPROM_WAIT_DURATION_ADDR, waitDuration);
}

void loadFromEEPROM() {
  int storedDryValue, storedWetValue, storedLowThreshold, 
      storedHighThreshold, storedPumpDuration, storedWaitDuration;

  EEPROM.get(EEPROM_DRY_VALUE_ADDR, storedDryValue);
  EEPROM.get(EEPROM_WET_VALUE_ADDR, storedWetValue);
  EEPROM.get(EEPROM_LOW_THRESHOLD_ADDR, storedLowThreshold);
  EEPROM.get(EEPROM_HIGH_THRESHOLD_ADDR, storedHighThreshold);
  EEPROM.get(EEPROM_PUMP_DURATION_ADDR, storedPumpDuration);
  EEPROM.get(EEPROM_WAIT_DURATION_ADDR, storedWaitDuration);

  // Validate stored values to prevent using uninitialized EEPROM
  if (storedDryValue > 0 && storedDryValue < 4096) dryValue = storedDryValue;
  if (storedWetValue > 0 && storedWetValue < 4096) wetValue = storedWetValue;
  if (storedLowThreshold >= 0 && storedLowThreshold <= 100) threshold_low = storedLowThreshold;
  if (storedHighThreshold >= 0 && storedHighThreshold <= 100) threshold_high = storedHighThreshold;
  if (storedPumpDuration > 0 && storedPumpDuration < 60000) pumpDuration = storedPumpDuration;
  if (storedWaitDuration > 0 && storedWaitDuration < 120000) waitDuration = storedWaitDuration;
}

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

  // Load saved settings
  loadFromEEPROM();

  // Initialize OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.clearDisplay();

  // Initialize pins
  pinMode(PUMP_PIN, OUTPUT);
  pinMode(MODE_BTN, INPUT_PULLUP);
  pinMode(SELECT_BTN, INPUT_PULLUP);
  pinMode(UP_BTN, INPUT_PULLUP);
  pinMode(DOWN_BTN, INPUT_PULLUP);

  digitalWrite(PUMP_PIN, LOW);
}

int readSoilMoisture() {
  int sum = 0;
  // Take 5 readings for smoothing
  for (int i = 0; i < 5; i++) {
    sum += analogRead(SOIL_SENSOR_PIN);
    delay(10);
  }
  int avgReading = sum / 5;

  // Convert to