How to Build a Smart Soil Moisture Monitor with ESPHome and ESP32

If you’ve ever forgotten to water a houseplant—or given it a bit too much love—this project is for you.

In this guide, you’ll learn how to build a simple soil moisture monitor using a capacitive sensor and an ESP32-C3 microcontroller. It runs ESPHome and integrates seamlessly with Home Assistant, allowing you to view live moisture levels from your phone, tablet, or smart home dashboard.

But it doesn’t stop there—once it’s connected, you can create automations too: send a notification when the soil gets too dry, or flash a smart bulb to remind you it’s watering time.

And if you’re not using Home Assistant? No problem. We’ll also include a simple ESPHome web interface, so you can access the sensor data directly through your browser on the local network.

Designed for indoor use, this setup is a budget-friendly, beginner-friendly way to bring a bit of smart tech into your home and keep your plants thriving.

Parts You’ll Need

Each setup requires just a few affordable components coming in at under £10 per sensor. Here’s what you’ll need:

ESP32-C3 Development Board

While this guide uses the ESP32-C3, other ESP32 development boards will also work, and even some ESP8266 boards can be used. Just make sure your board is compatible with ESPHome and includes at least one analog (ADC) pin for reading the moisture sensor.

Buy from Amazon
Capacitive Soil Moisture Sensor (V1.2)

More accurate and longer-lasting than resistive versions. Outputs an analogue voltage that reflects soil moisture levels.

Buy from Amazon
USB-C Cable

Used to power and flash the ESP32-C3. Any standard USB-C cable will work — you likely already have one.

Optional Extras

  • Small plant pot or test container for initial setup
  • Dupont jumper wires (for solder-free prototyping)
  • 3D-printed or waterproof enclosure (for a neater or more durable setup)

Wiring the Sensor to the ESP32-C3

Wiring the capacitive soil moisture sensor to your ESP32-C3 is quick and easy:

  • G → GND on the sensor
  • 3.3V → VCC on the sensor (Note: While the sensor claims to support 3.3V to 5V, I found that 5V caused inaccurate readings. 3.3V worked reliably.)
  • GPIO3 → AOUT on the sensor

Choose Your Setup

There are two ways to install and use your sensor:

  • Home Assistant User? Use the ESPHome Add-on and integrate directly into your smart home.
  • Standalone / No Home Assistant? Use the ESPHome web interface and built-in web server.

We’ll walk through both below — just follow the one that applies to you.

Home Assistant

Installing ESPHome and Flashing the ESP32-C3

To configure and flash your ESP32-C3, we’ll use ESPHome—a powerful tool that lets you build and deploy firmware using simple YAML. If you’re already using Home Assistant, this is by far the easiest and most seamless way to get started.

Here’s how to set everything up:

  1. Install the ESPHome Add-on
    • Go to Settings → Add-ons → Add-on Store
    • Search for ESPHome and click Install
    • After installing, click Start, and optionally enable Show in Sidebar
  2. Create a New Device
    • Open ESPHome from the sidebar
    • Click “+ New Device”, give it a name like soil-moisture-monitor
    • Select ESP32-C3 as the device type
    • Enter your Wi-Fi network name and password
  3. Plug in Your ESP32-C3 via USB
    • Connect the board to your computer via USB-C
    • Important: Hold down the BOOT button on the ESP32-C3 while plugging it in, and keep it held for a few seconds. This puts the board into flash mode.
  4. Install the Firmware
    • Click Install → Plug into this computer
    • Follow the instructions to flash the device
    • Once done, your ESP32-C3 will reboot, connect to Wi-Fi, and appear online in ESPHome

Writing our YAML Configuration

Here’s the actual YAML I used on my own sensor. It includes a raw voltage reading from the soil moisture sensor and converts it into a more useful percentage value using a template sensor:

esphome:
  name: indoor-rose-moisture-sensor
  friendly_name: Living Room Rose Moisture Sensor

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

logger:

web_server:
  port: 80

api:
  encryption:
    key: "REDACTED"

ota:
  - platform: esphome
    password: "REDACTED"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "Living-Room-Rose-Moisture-Sensor"
    password: "REDACTED"

captive_portal:

sensor:
  - platform: adc
    pin: 3
    name: "Soil Moisture Voltage"
    id: SMV
    update_interval: 1s
    attenuation: 11db

  - platform: template
    name: "Soil Moisture %"
    unit_of_measurement: "%"
    update_interval: 60s
    lambda: |-
      const float DRY_VOLTAGE = 2.2;
      const float WET_VOLTAGE = 1.8;

      float percent = ((DRY_VOLTAGE - id(SMV).state) / (DRY_VOLTAGE - WET_VOLTAGE)) * 100.0;

      if (percent < 0.0) percent = 0.0;

      return percent;
YAML

What You’ll Need to Update:

Before flashing, make sure to update the following lines:

2 – This will be the name of your device (keep it under 32 characters)
3 – This is the friendly name of your device
24 – If you are not using HA (Home Assistant) then replace !secret wifi_ssid with your ssid. If you are using HA make sure you have this secret set.
25 – Just as with line 24 but this time enter your WiFi password.
28 – Should the device disconnect from the WiFi it will emit it’s own SSID allowing you to reconnect. Set this as you wish.
29 – Same as above but for the password.

Standalone

Installing ESPHome and Flashing the ESP32-C3

Not using Home Assistant? No problem. You can still set up your ESP32-C3 by compiling the firmware locally using the ESPHome CLI.

Here’s how to do it from scratch:

  1. Install ESPHome on Your Computer
    You’ll need Python installed. If you don’t have it already, grab it from:
    https://www.python.org

    Then open a terminal or command prompt and run:
    pip install esphome
    This installs the ESPHome CLI tool.
  2. Save Your YAML Configuration
    Create a new folder on your computer and save your YAML file there, e.g.:
    indoor-moisture-sensor.yaml
    You can copy the full YAML example provided in the next section and tweak it as needed.
  3. Compile the Firmware
    In the same folder as your YAML file, run:
    esphome compile indoor-moisture-sensor.yaml
    If everything works, a .bin firmware file will be created at:
    ./.esphome/build/indoor-moisture-sensor/.pioenvs/indoor-moisture-sensor/firmware.bin
  4. Flash the Firmware via Web Browser
    Now that you have the .bin file, use the official ESPHome web tool to flash it:
    • Open https://web.esphome.io in Google Chrome or Microsoft Edge
    • Click Connect and choose your ESP32-C3 from the list
    • Select Install → Manual .bin file
    • Upload the .bin file you compiled in the previous step
    • Wait for the flash to complete
Warning: Before connecting your ESP32-C3 via USB, hold down the BOOT button. Keep it held while plugging in the USB cable. This puts the board into flashing mode.

Once flashed, your device will boot, connect to Wi-Fi, and serve the local web interface at its IP address. You can also make future updates wirelessly via OTA.


Writing our YAML Configuration

Here’s the YAML configuration tailored for standalone use without Home Assistant. It reads the raw voltage from the soil moisture sensor and converts it into a more useful percentage value using a template sensor. We’ve also removed any Home Assistant-specific features like the API encryption and OTA password to keep things simple.

esphome:
  name: indoor-rose-moisture-sensor
  friendly_name: Living Room Rose Moisture Sensor

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

logger:

web_server:
  port: 80

wifi:
  ssid: "YourNetworkName"
  password: "YourNetworkPassword"

  # Optional fallback access point
  ap:
    ssid: "Living-Room-Rose-Moisture-Sensor"
    password: "SomePassword"

captive_portal:

sensor:
  - platform: adc
    pin: 3
    name: "Soil Moisture Voltage"
    id: SMV
    update_interval: 1s
    attenuation: 11db

  - platform: template
    name: "Soil Moisture %"
    unit_of_measurement: "%"
    update_interval: 60s
    lambda: |-
      const float DRY_VOLTAGE = 2.2;
      const float WET_VOLTAGE = 1.8;

      float percent = ((DRY_VOLTAGE - id(SMV).state) / (DRY_VOLTAGE - WET_VOLTAGE)) * 100.0;

      if (percent < 0.0) percent = 0.0;

      return percent;

YAML

What You’ll Need to Update:

Before flashing, make sure to update the following lines:

2 – This will be the name of your device (keep it under 32 characters)
3 – This is the friendly name of your device
16 – Your SSID
17 – Your WiFi password
28 – Should the device disconnect from the WiFi it will emit it’s own SSID allowing you to reconnect. Set this as you wish.
29 – Same as above but for the password.

Show CommentsClose Comments

Leave a comment