Soil moisture sensor
This capacitive soil moisture sensor v1.2 costs $4 and reports how wet the soil is as an analog voltage: about 2.4–2.8 V in dry air, falling to 1.1–1.4 V in a glass of water. It has no exposed electrodes in the soil — the probe measures the dielectric constant of what surrounds it, so it corrodes far more slowly than the cheap resistive type. Like every analog sensor it needs an ADC on the Pi: a MCP3008 or ADS1115, or the soil + ADC board kit that combines both.
Pins
| Pin | What it is | Type |
|---|---|---|
| AOUT | Analog output | io |
| VCC | Supply 3.3–5.5 V | power |
| GND | Ground | ground |
In circuit.py:
SoilSensor()— Soil moisture sensor — $4- Pins: 3
Only three pins: power, ground and AOUT, the analog output. On a real board the pin is often marked AO or SIG; here it is AOUT.
Wiring it in circuit.py
from wiring import *
pi = Pi()
probe = SoilSensor()
adc = MCP3008()
pi.V3_3 >> probe.vcc
probe.gnd >> pi.GND
probe.aout >> adc.ch0 # 1.1–2.8 V, wet to dry
pi.V3_3 >> adc.vdd
adc.vdd >> adc.vref # reference = 3.3 V
adc.agnd >> pi.GND
adc.dgnd >> pi.GND
pi.SCLK >> adc.clk
pi.MISO >> adc.dout
pi.MOSI >> adc.din
pi.CE0 >> adc.csPower the probe from 3.3 V and its output stays inside the ADC's range; from 5 V the dry reading can reach 5 V and needs a divider before the ADC. The soil + ADC board is wired exactly as above — sensor on channel 0, SPI pins broken out.
Driving it in main.py
from gpiozero import MCP3008
from time import sleep
soil = MCP3008(channel=0)
while True:
# Calibrate: a glass of water reads ≈ 1.4 V, dry air ≈ 2.8 V.
moisture = (soil.value - 1.4) / (2.8 - 1.4)
print(f"moisture {max(0.0, min(1.0, moisture)) * 100:.0f} %")
sleep(1)soil.value is the probe voltage ÷ VREF, so the conversion above is just millivolts to percent using the datasheet's wet and dry bounds. Every probe is a little different — dip yours in water, note the reading, then do the same in dry air and use those two numbers. The soil + ADC board page covers the kit version.
Electrical notes
- Supply is 3.3–5.5 V; quiescent current is about 5 mA, safe on the 3V3 rail on its own.
- Output is 2.4–2.8 V dry and 1.1–1.4 V wet; higher voltage means drier soil. The output impedance is about 1 kΩ, which any MCP3008 or ADS1115 input handles easily.
- The response time is about 2 s, so it is a slow sensor: sample once a second at most.
- Only the lower part of the probe may enter the soil. The electronics at the top are not waterproof — push it in up to the line printed on the board.
- The output is ratiometric only loosely: changing the supply changes both the wet and dry levels a little, so calibrate at the voltage you will actually run.
Simulator vs real hardware
- Moisture comes from the soil feed of the probe's zone: it dries out with heat and rises when a pump waters the soil, so a closed-loop watering build behaves like the real thing. In the Lab you can set it by hand.
- Each probe draws its own calibration values (dry and wet voltages) inside the datasheet bands, so the "calibrate yours" advice is genuinely modelled rather than assumed.
- The behaviour refreshes every 200 ms and follows the supply: unpowered,
AOUTreads 0. - There is no corrosion, no electrolysis and no drift over time; a real capacitive probe's readings still shift with soil type and salinity, which the model does not reproduce.
Going deeper
- Primer: analog inputs and ADCs — the divider and sampling maths.
- The ADC side: MCP3008, ADS1115; the kit: soil + ADC board.
- Watering it: pump switched by a relay, or the relay + pump kit.
- The same ADC trick reads a potentiometer and an LDR.
Further reading
- DFRobot SEN0193 capacitive soil moisture sensor wiki — the sensor this page models, with its calibration notes.
- gpiozero: MCP3008 —
channelandvaluein Python. - SparkFun: Soil moisture sensor hookup guide — the resistive cousin, useful for the probe-in-soil practicalities.