Skip to main content

Build. Learn.
Innovate.

Soil Moisture Monitoring

Written By:

Published on:

Project Overview

This project introduces students to the basics of soil moisture detection using an analog sensor with an ESP32. The data is read, interpreted as moisture percentage, and can be displayed on an OLED or web dashboard. Students can enhance the system to trigger watering when the soil gets too dry.

Educational Goals

  • Understand how soil moisture sensors work and interpret analog values
  • Interface an analog sensor with an ESP32
  • Convert raw analog readings into human-readable percentages
  • Visualize and monitor moisture levels in real time
  • Explore automation based on sensor thresholds

Detailed Parts List

  • 1x ESP32 Dev Board (36-pin)
  • 1x Soil Moisture Sensor (analog output)
  • 1x 10kΩ resistor (if building voltage divider manually)
  • 1x OLED Display (SSD1306 I2C) (optional)
  • Jumper wires
  • Breadboard

Circuit Diagram Description

  • Soil sensor AO (analog out) → ESP32 GPIO34
  • VCC → ESP32 3.3V
  • GND → ESP32 GND
  • (Optional) OLED I2C:
    • SDA → GPIO21
    • SCL → GPIO22

Soil Sensor AO —> GPIO34 (ADC input)
Soil Sensor VCC —> 3.3V
Soil Sensor GND —> GND

Software Functionality

  • Read analog values from sensor using ADC
  • Convert raw ADC value (0–4095) into a percentage (dry to wet)
  • Display moisture level on serial monitor or OLED
  • (Optional) Trigger LED/buzzer or motor for watering
  • Serve an HTML dashboard displaying real-time moisture updates via Chart.js

Web Interface Features (Integrated)

  • Real-time graph of moisture percentage using Chart.js
  • JavaScript-based polling for live data
  • Responsive and visually clear layout

Implementation Steps

  1. Wire the soil moisture sensor to the ESP32
  2. Flash MicroPython firmware to ESP32
  3. Upload “** with web dashboard**
  4. Test soil in wet and dry conditions
  5. Access the web dashboard via local IP address

Extensions and Challenges

  • Add water pump relay for automatic watering
  • Monitor and log daily moisture levels
  • Use web dashboard for remote monitoring
  • Alert via buzzer or light when soil is too dry

Troubleshooting Guide

  • Values always high/low: Ensure correct sensor wiring and clean probes
  • ADC always returns 0: Verify correct ADC-capable GPIO (e.g. GPIO34)
  • OLED not displaying: Check I2C wiring and address
  • ESP32 crashing: Ensure proper power and grounding

Project Code


from machine import ADC, Pin
from time import sleep, ticks_ms, ticks_diff
import network, socket

# Setup Wi-Fi
ssid = 'YOUR_WIFI_SSID'
password = 'YOUR_WIFI_PASSWORD'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while not wlan.isconnected():
pass
ip = wlan.ifconfig()[0]
print("Web interface at:", ip)

# Initialize soil sensor
soil = ADC(Pin(34))
soil.atten(ADC.ATTN_11DB)
soil.width(ADC.WIDTH_12BIT)
moisture_percent = 0

# HTML with Chart.js
html = """<!DOCTYPE html>
<html>
<head>
<title>Soil Moisture Dashboard</title>
<script src='https://cdn.jsdelivr.net/npm/chart.js'></script>
<style>
body { font-family: Arial; background: #111; color: white; text-align: center; }
canvas { background: #222; border-radius: 10px; margin-top: 30px; }
</style>
</head>
<body>
<h1>Real-Time Soil Moisture</h1>
<canvas id='moistureChart' width='400' height='200'></canvas>
<script>
const ctx = document.getElementById('moistureChart').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{ label: 'Moisture %', data: [], borderColor: 'deepskyblue', fill: false }]
},
options: {
animation: false,
responsive: true,
scales: { y: { min: 0, max: 100, title: { display: true, text: 'Moisture (%)' } }, x: { title: { display: true, text: 'Time' } } }
}
});
async function updateChart() {
const res = await fetch('/moisture');
const data = await res.json();
const t = new Date().toLocaleTimeString();
if(chart.data.labels.length > 20) { chart.data.labels.shift(); chart.data.datasets[0].data.shift(); }
chart.data.labels.push(t);
chart.data.datasets[0].data.push(data.moisture);
chart.update();
}
setInterval(updateChart, 2000);
</script>
</body>
</html>"""

# Web server
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)

while True:
moisture_raw = soil.read()
moisture_percent = int((1 - (moisture_raw / 4095)) * 100)
cl, addr = s.accept()
request = cl.recv(1024).decode()
if 'GET /moisture' in request:
cl.send('HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n')
cl.send('{{"moisture": {}}}'.format(moisture_percent))
else:
cl.send('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n')
cl.send(html)
cl.close()

STEM Benefits

  • Science: Explore water retention and soil health in agricultural systems.
  • Technology: Learn how sensors measure environmental data and trigger automated responses.
  • Engineering: Design a self-regulating watering system using sensors and microcontrollers.
  • Math: Convert analog sensor readings to percentages and monitor trends over time.

Project Code

Projects
ShowCase

Real-World Projects
with Code & Hardware

Insights, Ideas
& How-Tos

Help, Support, and
Common Questions

What types of projects can I find on your website?

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.

You can explore a wide range of microcontroller and electronics projects, including Arduino, ESP32, IoT, and more. Each project comes with downloadable code, detailed guides, and the necessary hardware list.