Self-watering planter that texts you when the tank runs dry
- Build Logs
- 29 Jul, 2026
Automatic watering is a project everybody attempts and most people abandon, because version one either kills the plant or empties itself onto the floor. The difference between a toy and something you can leave running for a month is entirely in the failure handling — and that is what this build is really about.
What you will need
| Part | Qty | Approx. |
|---|---|---|
| NodeMCU ESP8266 (CP2102) | 1 | ₹300 |
| Capacitive Soil Moisture Sensor V2.0 | 1 | ₹67 |
| Water Level Detection Sensor | 1 | ₹22 |
| Submersible Water Pump | 1 | ₹44 |
| 1 Channel 5V Relay Module with Optocoupler | 1 | ₹126 |
Roughly ₹559, plus silicone tubing and a 5V supply for the pump.
Buy the capacitive probe, not the cheap one
There are two kinds of soil moisture sensor and they look almost identical.
The resistive type — two bare metal prongs — measures conductivity between them. To do that it passes current through wet soil, which electrolyses the electrodes. They visibly corrode within weeks, the readings drift the whole time, and eventually the prongs simply dissolve. They are ₹20 and they are a false economy for anything permanent.
The capacitive type has no exposed metal — the sensing element is sealed under solder mask, and it measures the dielectric constant of the surrounding soil instead. Nothing corrodes because no current flows into the soil. It costs three times as much and lasts indefinitely.
Note that it reads backwards from what you expect: a higher number means drier. Air gives roughly 600–700 on the ESP8266's ADC, a glass of water roughly 300. Calibrate against your own soil, because the absolute numbers vary with soil type and how deep you push it in.
The ESP8266 has exactly one analogue pin
And this build has two analogue sensors. The NodeMCU's A0 is the only ADC, and it reads 0–3.3V (the board has a divider so it tolerates 3.3V; the bare chip is 1.0V).
Two options. The clean one is to power each sensor from a GPIO and read them alternately — which also extends probe life by leaving them unpowered most of the time. That is what the sketch below does.
| From | To | Note |
|---|---|---|
| Soil sensor VCC | NodeMCU D5 | powered on demand |
| Water level VCC | NodeMCU D6 | powered on demand |
| Both sensors AOUT | NodeMCU A0 | only one powered at a time |
| Both sensors GND | NodeMCU GND | |
| Relay IN | NodeMCU D1 | |
| Relay VCC / GND | NodeMCU VIN (5V) / GND | |
| Relay COM / NO | 5V supply + / pump + | |
| Pump − | 5V supply − | flyback diode across pump |
A pump is a motor, so the same rule as the solenoid lock applies: fit a 1N4007 across its terminals, band to positive, or the switch-off spike will find its way back into your board.
The three failures that matter
Plenty of tutorials stop at "if dry, run pump". Here is what that misses.
Dry running. A submersible pump is cooled and lubricated by the water it moves. Run it in an empty tank and it overheats and seizes, sometimes in under a minute. This is why the water level sensor is arguably more important than the moisture sensor — it is protecting your hardware, not your plant.
Watering faster than the soil absorbs. Soil takes minutes to wick moisture to the probe. Run the pump until the sensor reads wet and you will have pumped the entire tank into the pot long before the reading moves. The fix is to water in a short pulse, then wait before measuring again.
A stuck-wet or stuck-dry sensor. If the probe falls out of the soil it reads permanently dry and the system waters forever. A daily cap on watering cycles turns a flood into a mild disappointment.
#include <ESP8266WiFi.h>
#define SOIL_PWR D5
#define LEVEL_PWR D6
#define RELAY D1
#define RELAY_ON LOW // active-low module
#define RELAY_OFF HIGH
const int DRY_THRESHOLD = 550; // higher = drier; calibrate!
const int TANK_EMPTY = 100; // below this = no water
const unsigned long PULSE_MS = 4000; // water for 4s
const unsigned long SOAK_MS = 30UL * 60 * 1000; // then wait 30 min
const byte MAX_PULSES_PER_DAY = 8;
unsigned long lastWater = 0;
unsigned long dayStart = 0;
byte pulsesToday = 0;
int readSensor(uint8_t powerPin) {
digitalWrite(powerPin, HIGH);
delay(500); // let it settle before reading
int v = analogRead(A0);
digitalWrite(powerPin, LOW); // power down = no corrosion, no drift
return v;
}
void setup() {
Serial.begin(115200);
digitalWrite(RELAY, RELAY_OFF); // before pinMode, so no boot pulse
pinMode(RELAY, OUTPUT);
pinMode(SOIL_PWR, OUTPUT);
pinMode(LEVEL_PWR, OUTPUT);
digitalWrite(SOIL_PWR, LOW);
digitalWrite(LEVEL_PWR, LOW);
dayStart = millis();
}
void loop() {
// Reset the daily budget.
if (millis() - dayStart > 24UL * 60 * 60 * 1000) {
dayStart = millis();
pulsesToday = 0;
}
if (millis() - lastWater < SOAK_MS) { delay(1000); return; }
int soil = readSensor(SOIL_PWR);
int level = readSensor(LEVEL_PWR);
Serial.printf("soil=%d level=%d pulses=%d\n", soil, level, pulsesToday);
if (level < TANK_EMPTY) {
Serial.println("TANK EMPTY - refusing to run the pump");
notify("Planter tank is empty");
delay(60000);
return;
}
if (pulsesToday >= MAX_PULSES_PER_DAY) {
Serial.println("Daily limit reached - check the probe");
notify("Planter hit its daily watering limit - probe may be loose");
delay(60000);
return;
}
if (soil > DRY_THRESHOLD) {
digitalWrite(RELAY, RELAY_ON);
delay(PULSE_MS);
digitalWrite(RELAY, RELAY_OFF);
lastWater = millis();
pulsesToday++;
}
delay(1000);
}
The SOAK_MS wait is the single most important line. It is what turns "pump until wet" — which floods — into "add a little, wait, reassess", which is how watering actually works.
Calibrating the threshold
Do not guess. Push the probe into the pot when the plant is genuinely thirsty and note the reading; water it thoroughly, wait an hour, and note it again. Set DRY_THRESHOLD between the two, nearer the dry number. Most houseplants prefer to dry out somewhat between waterings, so erring dry is safer than erring wet — root rot kills far more houseplants than drought.
Things that go wrong
Pump runs constantly. Relay is active-high, not active-low, so your "off" is actually on. Swap RELAY_ON and RELAY_OFF.
Pump clicks on at power-up before the sketch runs. The pin was made an output before its state was set. Ordering matters, which is why digitalWrite comes first above.
Readings jump around wildly. Both sensors powered at once, both driving A0. Only one at a time.
Sensor reads dry even in water. On a capacitive probe, check you have not submerged it past the marked line — the electronics at the top are not waterproof, and once water gets in, it is finished.
Pump is noisy but moves nothing. Air lock. Submerge it fully and squeeze the tubing to purge it; these small pumps cannot self-prime.
Plant is soaked but the sensor still reads dry. The probe is in a dry pocket, or too near the pot edge. Push it in mid-way between the stem and the rim, at root depth.
Where to take it next
Add the local web dashboard from our room monitor build and you can check moisture history from your phone, which is genuinely useful for working out how often a given plant actually needs water. Multiple plants means multiple pumps — at which point a 2-channel relay and one tank per zone is the sensible layout.
Ask us if you want help sizing tubing or picking a pump for a bigger planter.