
What you'll build
This guide shows you how to build a Plant Disco Guardian -- an ESP32-based soil moisture monitor that not only tells you when your plant is thirsty but throws a full disco celebration when you water it. A capacitive soil moisture sensor continuously reads the hydration level, and when it drops below a configurable threshold, a WS2812B LED ring glows a warning red and the buzzer emits a gentle periodic chirp. The moment you water the plant and the sensor detects rising moisture, the guardian erupts into a disco light show with rainbow chasing patterns, strobing colors, and a triumphant victory melody. It is absurd, it is delightful, and it actually makes you better at remembering to water your plants.
Under the hood you will learn how capacitive soil moisture sensors work and why they are preferred over resistive probes for long-term use, how to read analog values from the ESP32's ADC and smooth them with a running average to avoid false triggers from sensor noise, and how to drive WS2812B LEDs through the FastLED library with buttery-smooth animations. The disco celebration routine teaches you how to chain multiple animation patterns into a sequenced light show using non-blocking timers, while the alert system demonstrates hysteresis-based threshold logic that prevents the guardian from flickering between alert and celebration states when moisture sits near the boundary.
The completed guardian is a conversation starter that sits in any pot and runs for weeks on a USB power supply. The code is structured so you can adjust moisture thresholds for different soil types, customize the disco playlist with your own LED patterns and melodies, or add Wi-Fi to push moisture data to a dashboard or send phone notifications. Pair it with multiple sensors to monitor an entire windowsill garden from a single ESP32. It is the most fun you will ever have learning about analog-to-digital conversion and threshold-based alerting. If you want to explore more WS2812B animation techniques, the gesture-controlled mood lamp builds on the same FastLED skills with hand-wave interaction.
Wiring diagram
Wiring diagram
Components needed
Assembly
Connect the soil moisture sensor
Wire capacitive soil moisture sensor VCC to 3.3V, GND to ground, and analog output to GPIO34.
- Use a capacitive sensor (not resistive) for longer life in wet soil.
- GPIO34 is input-only — this is fine for analog reads.
Wire the LED ring
Connect WS2812B 5V to USB 5V, GND to ESP32 GND, and DIN to GPIO4. Add a 330 Ω resistor on the DIN line.
- A diffuser (frosted cup or paper) around the ring makes the glow more even.
Add the buzzer
Wire piezo buzzer signal to GPIO26 with the other lead to GND.
- A passive buzzer lets you control pitch; an active buzzer only beeps at one frequency.
Calibrate and deploy
Flash the sketch and open Serial Monitor at 115200 baud. Read the moisture values when the soil is dry and wet, then adjust DRY_THRESHOLD and WET_THRESHOLD in the code. Stick the sensor in your plant pot and enjoy the disco.
- Different soil types and sensors produce different ranges — always calibrate.
Pin assignments
| Pin | Connection | Type |
|---|---|---|
| 3V3 | soil-sensor-1 VCC | POWER |
| GND | soil-sensor-1 GND | GROUND |
| GPIO 34 | soil-sensor-1 SIG | ANALOG |
| 5V | plant-led-ring-1 5V | POWER |
| GND | plant-led-ring-1 GND | GROUND |
| GPIO 4 | plant-led-ring-1 DIN | DATA |
| GND | plant-buzzer-1 GND | GROUND |
| GPIO 26 | plant-buzzer-1 SIG | PWM |
Code
#include <FastLED.h>
#define SOIL_PIN 34
#define LED_PIN 4
#define NUM_LEDS 12
#define BUZZER_PIN 26
CRGB leds[NUM_LEDS];
const int DRY_THRESHOLD = 1700;
const int WET_THRESHOLD = 2200;
bool wasDry = false;
unsigned long discoEndMs = 0;
const unsigned long DISCO_DURATION = 5000;
int smoothRead(int pin, int samples = 8) {
long sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delay(2);
}
return sum / samples;
}
void discoPattern() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV((millis() / 6 + i * 21) % 255, 255, 200);
}
}
void warningPattern() {
uint8_t pulse = beatsin8(30, 60, 200);
fill_solid(leds, NUM_LEDS, CRGB(pulse, 0, 0));
}
void idlePattern() {
uint8_t glow = beatsin8(15, 40, 120);
fill_solid(leds, NUM_LEDS, CRGB(0, glow, glow / 3));
}
void setup() {
Serial.begin(115200);
delay(100);
FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(140);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println("Plant Disco Guardian ready");
}
void loop() {
int moisture = smoothRead(SOIL_PIN);
bool isDry = moisture < DRY_THRESHOLD;
bool isWet = moisture > WET_THRESHOLD;
if (wasDry && isWet) {
discoEndMs = millis() + DISCO_DURATION;
tone(BUZZER_PIN, 1800, 100);
delay(110);
tone(BUZZER_PIN, 2200, 100);
delay(110);
tone(BUZZER_PIN, 2600, 150);
Serial.println("DISCO TIME!");
}
bool discoMode = millis() < discoEndMs;
if (discoMode) {
discoPattern();
} else if (isDry) {
warningPattern();
if ((millis() / 3000) % 2 == 0) {
tone(BUZZER_PIN, 900, 80);
}
} else {
idlePattern();
}
FastLED.show();
wasDry = isDry;
Serial.printf("Moisture: %d | %s\n", moisture,
discoMode ? "DISCO" : isDry ? "DRY" : "OK");
delay(discoMode ? 30 : 200);
}
// Run this and build other cool things at schematik.ioReady to build this?
Open this project in Schematik to get the full wiring diagram, pin assignments, and deployable code for the Plant Disco Guardian.
Open in Schematik →Related guides
How to Build a Gesture-Controlled Mood Lamp with ESP32
ESP32 · Beginner
How to Build a Cosmic Critter Pet with Raspberry Pi Pico
Raspberry Pi Pico · Beginner
How to Build a Rocket Launch Alarm Clock with ESP32
ESP32 · Beginner
How to Build a Laser Harp Synth with ESP32
ESP32 · Beginner