Plant Moisture Monitor
A battery sensor that sits in a pot, checks soil moisture every hour and sends a reading over Wi-Fi. Runs for months on one charge.
“Make a sensor that sits in a plant pot and tells me when the soil is dry.”
Spec
Plant Moisture Monitor
A battery-powered soil sensor that reports moisture, temperature and humidity over Wi-Fi every hour.
- Power
- 1000 mAh LiPo, USB-C charging, about 6 months per charge
- Size
- 58 × 38 × 22 mm head with a 10 cm probe
- Inputs
- Capacitive soil probe, Temperature and humidity sensor, Pair button
- Outputs
- Status LED, Wi-Fi readings
- Connectivity
- Wi-Fi 2.4 GHz, USB-C
- Budget
- Under $20 in parts
Constraints
- Splash resistant
- No exposed metal in the soil
Why
Capacitive, not resistive
Resistive probes corrode in wet soil within weeks. A capacitive probe has no exposed metal and lasts for years.
Why
Hourly readings
Soil dries over days, so one reading an hour is plenty and keeps the battery going for months.
Circuit board
Why
Probe power is switched
The probe only gets power for 50 ms per reading through GPIO1, which saves about 5 mA the rest of the time.
Why
SHT40 for air readings
It's tiny, accurate to 0.2 °C and draws almost nothing between readings.
Firmware
// Plant Moisture Monitor — wakes every hour, measures soil moisture,
// temperature and humidity, posts them over Wi-Fi, then sleeps again.
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_SHT4x.h>
#include "pins.h"
#include "secrets.h" // WIFI_SSID, WIFI_PASS, WEBHOOK_URL
constexpr uint64_t SLEEP_US = 60ULL * 60ULL * 1000000ULL; // 1 hour
constexpr uint16_t SOIL_DRY = 2900; // Raw ADC in dry air (calibrate!)
constexpr uint16_t SOIL_WET = 1250; // Raw ADC in a glass of water
Adafruit_SHT4x sht;
uint8_t readSoilPercent() {
digitalWrite(PIN_SOIL_PWR, HIGH); // Power the probe only while reading
delay(50);
uint32_t sum = 0;
for (int i = 0; i < 16; i++) sum += analogRead(PIN_SOIL_ADC);
digitalWrite(PIN_SOIL_PWR, LOW);
const int raw = sum / 16;
return constrain(map(raw, SOIL_DRY, SOIL_WET, 0, 100), 0, 100);
}
bool connectWifi(uint32_t timeoutMs = 8000) {3 files: src/main.cpp, include/pins.h, platformio.ini
Why
Deep sleep between readings
The chip is fully asleep for 59 minutes and 58 seconds of every hour, drawing a few microamps.
Why
Calibrate once
SOIL_DRY and SOIL_WET are set by holding the probe in air and in water. The app will walk you through it.
Enclosure
- Outer size
- 58 × 38 × 22 mm
- Material
- PETG, 0.2 mm layers
- Print time
- 1 h 40 min, no supports
Why
Drip edge on the lid
The lid overlaps the base by 2 mm so water from watering runs off instead of in.
Assembly
- 1Plug in the battery and probe.
- 2Screw the board to the base.
- 3Snap on the lid and push the probe into the soil.
Why
Fit check passed
1.5 mm clearance above the tallest part.
See every stage run, step by step
The workspace shows each engine working, with approval checkpoints in between.