Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

Capacitive soil moisture sensor with Raspberry Pi Pico W — MicroPython

Read a capacitive soil moisture sensor v1.2 on Pico W ADC0 (GP26) in MicroPython, calibrate dry and wet values, and turn them into a percentage.

MicroPythonVerified — micropython (mpy-cross v1.29.0), 3 Nov 2026Compile-only

Community draft — report a mistake

A capacitive probe has no exposed metal, so it doesn’t corrode like the cheap two-prong sensors. It outputs an analog voltage — higher when dry, lower when wet — which the Pico W reads on GP26 (ADC0).

Power it from 3V3, run the script, and note the raw number in air and in water. Those two values turn the reading into a useful 0–100 % moisture figure.

Wiring

Raspberry Pi Pico WOnly the pins used are shown · 3.3 V logicCapacitive soil moisture sensor v1.2GND3V3GP26GNDVCCAOUT
Every connection
Raspberry Pi Pico WCapacitive soil moisture sensor v1.2WireNotes
GNDGNDblack
3V3VCCred3V3 is pin 36. At 3.3 V the output stays well under the ADC’s 3.3 V limit.
GP26AOUTyellowGP26 = ADC0, physical pin 31.

3.3–5.5 V part, 3.3 V board. The output is an analog voltage that stays below the supply. Power it from 3.3 V on ESP32 and Pico so AOUT can never exceed the ADC input range; on an Uno 5 V is fine.

Board quirks

  • Every probe reads differently. Note the raw value in dry air and in a glass of water and put them in DRY and WET.
  • Some v1.2 boards ship with an NE555 instead of a TLC555 timer, or without the regulator, and barely respond at 3.3 V — if raw hardly changes between air and water, that is why.
  • Seal the top edge and the electronics with hot glue or nail polish: monsoon humidity creeps into the exposed board and the reading drifts.
  • The on-board LED lights below 30 %. For phone alerts over Wi-Fi, see the soil-moisture project on this site.

Code

main.pyMicroPython
# Capacitive soil moisture sensor v1.2 on a Raspberry Pi Pico W (MicroPython).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, AOUT -> GP26 / ADC0 (pin 31).
# Calibrate: note the raw value with the probe in dry air (DRY) and in a glass of water (WET).
from machine import ADC, Pin
import time

DRY = 52000   # raw reading in dry air   <- replace with yours
WET = 21000   # raw reading in water     <- replace with yours

sensor = ADC(26)
led = Pin("LED", Pin.OUT)


def moisture():
    raw = sum(sensor.read_u16() for _ in range(16)) // 16
    pct = (DRY - raw) * 100 // (DRY - WET)
    return max(0, min(100, pct)), raw


print("Soil moisture on GP26 - put the probe in dry air, then water, to calibrate")
while True:
    pct, raw = moisture()
    led.value(pct < 30)  # LED on = needs water
    print("Moisture {:3d} %  (raw {})".format(pct, raw))
    time.sleep(2)

Expected serial output

REPL / Thonny shellOutput
Soil moisture on GP26 - put the probe in dry air, then water, to calibrate
Moisture   0 %  (raw 52310)
Moisture  64 %  (raw 32150)
Moisture  98 %  (raw 21540)

Common errors

Always 0 % or always 100 %

DRY and WET are still the example values. Replace them with your own readings.

Raw value barely changes between air and water

Probably a faulty batch (wrong timer chip or missing regulator). Try the probe at 5 V on another board to confirm, then buy from a different seller.

↑↓ to move · Enter to open