// Wokwi does not have native soil moisture sensors and water pumps
// we will use the DS18B20 temperature sensor as a proxi
// we will use the Servo Motor as a proxi
#include <Wire.h> // Required for I2C communication with the screen
#include <LiquidCrystal_I2C.h> // For I2C LCD
#include <OneWire.h> // Required for DS18B20 which is the sensor used to represent the soil moisture sensor
#include <DallasTemperature.h> // For DS18B20
#include <ESP32Servo.h> // For Servo Motor control
// ----- LCD Configuration -----
const int LCD_ADDR = 0x27; // or 0x3F
const int LCD_COLUMNS = 16;
const int LCD_ROWS = 2;
LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLUMNS, LCD_ROWS);
// ----- DS18B20 Temperature Sensor Configuration -----
const int ONE_WIRE_BUS = 4;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// ----- Servo Motor Configuration -----
const int SERVO_PIN = 14; // Connect servo signal to ESP32 GPIO13
Servo myServo; // Create a servo object
void setup() {
Serial.begin(115200);
Serial.println("ESP32 DS18B20 & I2C LCD & Servo Test");
// Initialize the LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.print("System Booting...");
lcd.setCursor(0, 1);
lcd.print("Please Wait...");
// Start the DS18B20 sensor library
sensors.begin();
if (sensors.getDeviceCount() == 0) {
lcd.clear();
lcd.print("No DS18B20 found!");
lcd.setCursor(0, 1);
lcd.print("Check wiring/resistor");
while (true); // Halt if no sensor found
}
sensors.setResolution(10);
// Allow allocation of all timers to Servo (up to 16 servos on ESP32)
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
myServo.setPeriodHertz(50); // Standard 50 Hz servo
myServo.attach(SERVO_PIN, 500, 2500); // Attach servo to pin, pulse width min/max for 0-180 deg
delay(2000);
lcd.clear();
}
void loop() {
sensors.requestTemperatures();
float soilMoisture = sensors.getTempCByIndex(0);
if (soilMoisture == DEVICE_DISCONNECTED_C) {
Serial.println("Error: Could not read Soil Moisture data");
lcd.setCursor(0, 0);
lcd.print("Error!");
lcd.setCursor(0, 1);
lcd.print(" ");
} else {
Serial.print("Soil Moisture: ");
Serial.print(soilMoisture);
Serial.println(" *C");
lcd.setCursor(0, 0);
lcd.print("Soil Moisture %: ");
lcd.print(soilMoisture, 1);
lcd.print((char)223);
lcd.print("C");
// ----- Servo Control Logic Based on Soil Moisture -----
// This is a simple example. Adjust thresholds and servo positions as needed.
if (soilMoisture > 50.0) { // If Soil Moisture is high
myServo.write(180); // Move servo to 180 degrees (e.g., open a vent)
lcd.setCursor(0, 1);
lcd.print("Status: Wet! ");
} else if (soilMoisture < 20.0) { // If Soil Moisture is low
myServo.write(0); // Move servo to 0 degrees (e.g., close a vent)
lcd.setCursor(0, 1);
lcd.print("Status: Critically Dry! ");
} else { // Moderate Soil Moisture
myServo.write(90); // Move servo to 90 degrees (e.g., partially open)
lcd.setCursor(0, 1);
lcd.print("Status: Dry! ");
}
}
delay(2000);
}LED IC2
Soil Moisture Sensor
ESP32 Micro-controller
(Brain)
Water Pump
--> SDA = 21
--> SCL = 23
Digital Pin (Binary) -->
--> Analog Pin
1. The digital pin sends binary, high and low level, signals to the MOSFET
(the gate) allowing/restricting the pump to be powered.
2. The analog pin receives varying (continuous) signals from the soil
moisture sensor.
3. SDA (data transfer) and SCL (synchronization) ports are used to
communicate with the LED screen.
4. The ESP32 Microcontroller has 5V (VCC) and 3V (3V3). Sensors and
screens are often connected to 3V for safety reasons. Pumps and other
devices are often connected to 5V.
6. The MOSFET acts as a gate that powers up the pump when
receives a high level signal from the ESP32. We use a NOT Logic
gate here as a proxy, even though it does not strictly function as
a MOSFET.
MOSFET (Proxy)