Capacitive Soil Moisture Sensor with ESP32, ESPHome and Home Assistant

Use a capacitive soil moisture sensor with ESP32, ESPHome and Home Assistant. Covers wiring, ADC setup, dry/wet calibration, filtering, power switching, corrosion, placement and smart irrigation automation.

A capacitive soil-moisture sensor is one of the easiest ways to make an ESP32 irrigation system smarter, but the raw analogue value is not a universal “soil moisture percentage”. These inexpensive probes measure changes in capacitance caused largely by the dielectric properties of the surrounding soil. The reading depends on the sensor design, supply voltage, soil type, salinity, mounting depth and even how tightly the soil is packed around the probe.

The right approach is therefore:

Read stable analogue voltage
→ calibrate in your own soil
→ filter noise
→ publish a relative 0–100% moisture value
→ use thresholds with hysteresis
→ let Home Assistant decide whether watering is needed

This guide uses a classic ESP32 with ESPHome, but the same method works with ESP32-C3, C6 and S3 boards as long as you choose a suitable ADC pin.

Capacitive vs Resistive Soil Sensors

FeatureResistive probeCapacitive probe
Measurement principleElectrical conductivity/resistance through soilCapacitance / dielectric change
Exposed metal electrodesUsually yesUsually no
Electrode corrosionCommonMuch lower
Influence of soil saltsHighStill present, but generally less direct
Long-term installationPoor unless carefully managedBetter
Typical outputAnalogue or comparatorAnalogue voltage

Seeed describes its capacitive sensor as corrosion-resistant because the metal electrodes do not need direct exposure to the soil. It also explicitly warns that the sensor is intended for qualitative moisture measurement rather than laboratory-grade quantitative volumetric water content.

For garden automation, that is normally fine. You rarely need to know that the soil contains exactly 23.7% volumetric water. You need to know whether a particular bed is dry enough to justify irrigation.

What the Sensor Actually Measures

Water has a much higher dielectric constant than dry soil and air. A capacitive probe detects how its electric field changes as the water content around the sensing section changes.

On many common analogue probes:

Dry soil  → higher output voltage
Wet soil  → lower output voltage

That direction is common but not universal, so test the actual sensor before writing automation logic.

Do not interpret its percentage as an absolute agronomic VWC measurement unless the sensor has been characterised for that purpose. Industrial soil probes use more controlled electronics, calibration and often temperature/electrical-conductivity compensation.

Typical Wiring to ESP32

For a 3.3 V-compatible analogue capacitive sensor:

SensorESP32
VCC3.3 V
GNDGND
AO / SIGADC1 pin such as GPIO34

On the classic ESP32, GPIO34 is a convenient ADC1 input and is input-only, so it cannot accidentally drive the sensor output.

If your module is specified for 5 V operation, do not assume its analogue output is automatically safe for a 3.3 V ESP32 ADC. Measure the maximum output voltage or use the manufacturer’s specification. A sensor powered at 5 V can potentially output more voltage than the ESP32 should receive.

Why ADC1 Is Usually the Better Choice

On the original ESP32, ADC1 pins are generally the least troublesome choice for analogue sensors. Older Arduino/ESP-IDF combinations historically had restrictions around ADC2 while Wi-Fi was active, and ADC behaviour differs across newer ESP32 variants.

The practical rule is simple: check the pinout for your exact ESP32 and choose an ADC pin that is not reserved for flash, PSRAM, USB or boot strapping.

For ESP32-C3 XIAO, for example, our XIAO ESP32-C3 pinout guide recommends the ADC1 pins over the board’s ADC2-labelled A3 input.

ESPHome ADC Configuration

sensor:
  - platform: adc
    pin: GPIO34
    id: soil_voltage
    name: "Soil Moisture Voltage"
    attenuation: auto
    update_interval: 5s
    entity_category: diagnostic

Current ESPHome supports attenuation: auto, which combines the available ESP32 attenuation ranges automatically. ESPHome notes that its usable measured range is approximately 0.075 V to 3.12 V in its tests, with exact limits varying between chips.

This is another reason to run the sensor from 3.3 V where possible and confirm the actual output range before connecting it permanently.

Do Not Start by Mapping Air and Water to 0% and 100%

A lot of tutorials calibrate a probe like this:

sensor in air  = 0%
sensor in water = 100%

That is useful as a quick functional test, but it is not the best irrigation calibration. Your plant does not live in air or a glass of water.

A better two-point calibration is:

  1. Install the sensor at its real depth and orientation.
  2. Let the soil dry to the point where you genuinely want irrigation to start.
  3. Record the stable sensor voltage. Call that your practical 0% or dry threshold.
  4. Water the soil thoroughly and allow excess water to drain.
  5. Wait until the root zone reaches a stable wet condition rather than measuring during a puddle.
  6. Record that voltage as your practical 100% reference.

This produces a percentage that actually means something for your garden.

Example Calibration

Suppose your installed probe measures:

Dry irrigation threshold: 2.62 V
Wet drained soil:          1.38 V

Because the voltage decreases as moisture increases, map the values in reverse:

filters:
  - calibrate_linear:
      - 2.62 -> 0
      - 1.38 -> 100
  - clamp:
      min_value: 0
      max_value: 100

ESPHome’s calibrate_linear filter is designed specifically to convert known measured sensor values into useful engineering values.

Full Calibrated ESPHome Sensor

sensor:
  - platform: adc
    pin: GPIO34
    name: "Garden Soil Moisture"
    id: garden_soil_moisture

    attenuation: auto
    update_interval: 5s

    filters:
      - median:
          window_size: 7
          send_every: 3
          send_first_at: 3

      - calibrate_linear:
          - 2.62 -> 0
          - 1.38 -> 100

      - clamp:
          min_value: 0
          max_value: 100

      - round: 1

    unit_of_measurement: "%"
    device_class: moisture
    state_class: measurement
    accuracy_decimals: 1

The calibration values above are examples only. Replace them with your own dry and wet readings.

Why Use a Median Filter?

Analogue soil sensors can produce occasional spikes from Wi-Fi activity, supply noise, long cables or ADC variation.

A median filter is useful because it rejects isolated outliers without averaging one huge bad reading into the result. ESPHome’s current median filter keeps a rolling window and publishes the median at the selected interval.

For a slowly changing quantity such as soil moisture, there is little reason to publish every noisy five-second ADC sample directly to Home Assistant.

Moving Average Is Another Good Option

If the sensor is noisy but does not produce sharp isolated spikes, use:

- sliding_window_moving_average:
    window_size: 12
    send_every: 12

With a five-second update interval, that publishes one one-minute average.

Do not over-filter. A one-hour moving average will make the graph pretty but can hide the important transition immediately after irrigation.

Power the Sensor Only When Measuring

A capacitive sensor does not suffer exposed-electrode electrolysis in the same way as a cheap resistive fork, but permanent outdoor power is still not always ideal. Low-cost boards can absorb moisture around PCB edges and components, drift with temperature, or corrode around unprotected circuitry.

Duty-cycling the sensor also saves power on a battery node.

For a robust design, switch the sensor supply using a small MOSFET/load switch rather than assuming every sensor can be powered directly from an ESP32 GPIO.

ESP32 GPIO
    |
 MOSFET / load switch
    |
3.3 V → soil sensor

sensor output → ESP32 ADC

Then the sequence is:

sensor power ON
wait for circuit to settle
take several ADC readings
publish filtered value
sensor power OFF

Simple ESPHome Power-Switch Concept

If your hardware includes a MOSFET/load switch controlled by GPIO25:

switch:
  - platform: gpio
    pin: GPIO25
    id: soil_sensor_power
    internal: true
    restore_mode: ALWAYS_OFF

sensor:
  - platform: adc
    pin: GPIO34
    id: soil_adc
    attenuation: auto
    update_interval: never

You can then use an ESPHome interval/script to enable power, allow a short settling period, trigger the ADC update and switch the probe off again. The exact settling time depends on the sensor electronics, so measure it rather than assuming every capacitive board stabilises in the same 50 ms.

Cheap “Capacitive v1.2” Sensors Are Not Waterproof

The sensing blade may be coated, but the electronics at the top of many inexpensive PCB probes are exposed.

Do not bury the entire board. Insert only the intended sensing area and keep:

  • Components above the soil line.
  • Cable solder joints dry.
  • Connector away from irrigation spray.
  • PCB edges protected where practical.

Seeed gives the same warning for its Grove capacitive probe: do not insert the sensor beyond the marked maximum soil line.

Conformal Coating and Epoxy

For a permanent DIY installation, you can protect the exposed component area and PCB edges with suitable conformal coating or potting material, while keeping connectors and intentionally exposed sensing surfaces appropriate to the sensor design.

Any coating near the capacitive sensing region changes the dielectric environment slightly, so calibrate after the final waterproofing treatment, not before.

If you need a sensor that can genuinely remain buried outdoors for years, use a purpose-built waterproof or industrial probe rather than expecting a £2 exposed PCB to behave like an IP68 agricultural sensor.

Sensor Placement Matters More Than People Expect

A perfectly calibrated sensor in the wrong place produces useless irrigation decisions.

Place the probe:

  • Inside the active root zone.
  • At a representative depth.
  • Away from a dripper’s immediate wet spot.
  • Away from roof runoff.
  • Not directly beside a retaining wall or concrete edge that dries differently.
  • In soil representative of the irrigation zone.

For lawn, the useful root-zone depth may be very different from a deep shrub or tree bed. One sensor cannot automatically represent every plant in the garden.

Use More Than One Sensor for Large Zones

If one irrigation zone contains different soil or exposure conditions, consider two or three sensors and make the watering decision from a robust aggregate.

For example, use the median of three bed sensors rather than allowing one unusually wet probe beside a dripper to suppress irrigation for the entire zone.

Home Assistant is a good place to create this aggregate because it already receives all the sensor entities.

Do Not Use One Exact Threshold

A rule like:

if moisture < 35:
    water
else:
    stop

can chatter if the reading sits around 35%.

Use hysteresis instead:

Below 30% → soil considered dry
Above 45% → soil considered wet

30–45% → keep previous state / no new decision

Even better, use moisture to decide whether a scheduled irrigation cycle is allowed to start rather than switching water on and off every time the ADC moves by one percent.

Home Assistant Irrigation Condition

With the ESP32 Smart Irrigation Controller from the previous guide, Home Assistant can start the irrigation cycle only when the soil is dry:

alias: Garden Irrigation - Moisture Controlled
triggers:
  - trigger: time
    at: "05:30:00"

conditions:
  - condition: numeric_state
    entity_id: sensor.garden_soil_moisture
    below: 30

  - condition: state
    entity_id: binary_sensor.irrigation_rain_sensor
    state: "off"

actions:
  - action: switch.turn_on
    target:
      entity_id: switch.irrigation_cycle

mode: single

This is much safer than allowing an analogue sensor to control a valve continuously. If the sensor fails, the worst case is usually a skipped scheduled cycle rather than an uncontrolled open valve.

Add a Sensor-Failure Check

A disconnected analogue sensor may produce a value that looks extremely dry or extremely wet depending on the ADC input and board.

Before relying on it for irrigation, establish the normal electrical range. For example, if the calibrated sensor should always operate between 1.2 and 2.8 V, values outside that range can indicate a wiring fault.

ESPHome can expose the raw voltage as a diagnostic entity while publishing the calibrated percentage separately. That makes debugging much easier.

Raw Voltage + Calibrated Percentage

sensor:
  - platform: adc
    pin: GPIO34
    id: soil_raw
    name: "Soil Sensor Voltage"
    attenuation: auto
    update_interval: 10s
    entity_category: diagnostic

    filters:
      - median:
          window_size: 5
          send_every: 1

  - platform: copy
    source_id: soil_raw
    name: "Soil Moisture"
    filters:
      - calibrate_linear:
          - 2.62 -> 0
          - 1.38 -> 100
      - clamp:
          min_value: 0
          max_value: 100
      - round: 1
    unit_of_measurement: "%"
    device_class: moisture
    state_class: measurement

This gives you both the engineering diagnostic and the friendly Home Assistant percentage.

Long Sensor Cables

An analogue signal running several metres through a garden is much more vulnerable to noise and voltage drop than a short cable inside a plant pot.

For longer runs:

  • Use a shared solid ground.
  • Keep the analogue wire away from pumps, solenoid-valve cables and mains wiring.
  • Use twisted/shielded cable where appropriate.
  • Filter readings.
  • Consider putting the ESP32/ADC closer to the probes.
  • For genuinely long agricultural runs, use a digital/RS-485 industrial probe instead.

When an ADS1115 Helps

The built-in ESP32 ADC is good enough for ordinary irrigation thresholds, but an external ADS1115 can help when you want:

  • Several analogue probes.
  • Better repeatability/resolution.
  • A cleaner analogue front end.
  • Differential measurements for other sensors.

See our ADS1115 with ESPHome: Gain, Differential Inputs and Calibration guide.

Remember that an ADS1115 does not magically fix a poor sensor or bad placement. It only measures the electrical output more precisely.

Battery-Powered Soil Sensor Node

A garden probe is well suited to deep-sleep operation because soil moisture changes slowly.

A battery node can:

wake every 15 minutes
→ power sensor
→ wait for stabilisation
→ take several readings
→ connect to Wi-Fi
→ publish moisture
→ sleep

There is usually no benefit in sampling soil moisture every second for Home Assistant. A 10–30 minute interval is enough for most gardens and saves enormous battery power.

The XIAO ESP32-C6 and XIAO ESP32-S3 are attractive battery platforms because their boards include lithium charging; see our XIAO ESP32-C6 and XIAO ESP32-S3 guides.

Common Problems

SymptomLikely cause / first check
Percentage is backwardsReverse dry/wet calibration points
Always reads 100%ADC input saturated or wet calibration incorrect
Always reads 0%Disconnected signal, dry calibration or wrong ADC pin
Reading jumps when Wi-Fi transmitsSupply/ADC noise; add median/average filtering
Different soil gives different percentageNormal for cheap relative capacitive probes; recalibrate
Sensor works for months then driftsMoisture ingress, PCB edge corrosion or soil/placement change
Works indoors but fails outdoorsElectronics not waterproof
One sensor says wet while plants are dryProbe placed too close to dripper or wrong depth
ADC voltage above expected rangeCheck sensor supply/output before reconnecting ESP32
Irrigation toggles repeatedly near thresholdAdd hysteresis and schedule-based logic

Recommended Setup for Home Assistant Irrigation

For a practical garden, I would use:

  • A capacitive probe installed permanently at representative root depth.
  • 3.3 V supply if the module supports it.
  • ESP32 ADC1 input.
  • Median filtering.
  • Calibration in the actual soil after installation.
  • Raw-voltage diagnostic entity.
  • Calibrated relative percentage for dashboards.
  • Moisture used as a condition to permit/skip scheduled irrigation.
  • Physical rain sensor as a separate lockout.
  • ESPHome sprinkler controller handling actual valve timing locally.

That gives you a useful smart-irrigation signal without pretending a low-cost analogue PCB is a laboratory soil-water instrument.

Related Smart Garden Guides

Official and Reference Resources

Share your love