The capacitive soil sensor is the one to buy for pots and garden beds: unlike the old two-prong resistive probe, nothing on it corrodes. It outputs a voltage that drops as the soil gets wetter.
The Nano reads it on A6 — one of its two analog-only pins, which is exactly what this sensor needs. The sketch averages 16 readings, converts them to a 0–100 % figure using your own dry and wet calibration, and suggests watering below 30 %.
Wiring
| Arduino Nano | Capacitive soil moisture sensor v1.2 | Wire | Notes |
|---|---|---|---|
| GND | GND | black | |
| 5V | VCC | red | |
| A6 | AOUT | yellow | A6 is analog-only — a good home for a sensor that only gives a voltage. |
3.3–5.5 V part, 5 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
- The output falls as the soil gets wetter. Every sensor is different, so calibrate: send
dwith the probe in air andwwith it in a glass of water. - On a 5 V Nano the output (about 1.2–3 V) goes straight to A6 — no divider.
- Some cheap v1.2 boards are mis-built (wrong regulator or a missing resistor), so the reading barely changes or is very slow. If dry and wet differ by less than ~150 counts, try another sensor.
- Push the probe in only up to the line printed on it, and seal the top edge and components with nail polish or hot glue — monsoon rain kills the exposed circuit, not the probe.
Code
// Capacitive soil moisture sensor v1.2 on an Arduino Nano, read on the analog-only pin A6.
// VCC → 5V, GND → GND, AOUT → A6. Calibrate DRY and WET with your own sensor, then it prints %.
const uint8_t SOIL_PIN = A6;
int DRY = 600; // reading in dry air (send 'd' with the probe in air to store)
int WET = 280; // reading in a glass of water (send 'w' with the probe in water)
int readAverage() {
long sum = 0;
for (uint8_t i = 0; i < 16; i++) {
sum += analogRead(SOIL_PIN);
delay(5);
}
return sum / 16;
}
void setup() {
Serial.begin(115200);
Serial.println(F("Soil sensor on A6 - send d (dry) or w (wet) to calibrate"));
}
void loop() {
int raw = readAverage();
if (Serial.available()) {
char c = Serial.read();
if (c == 'd') DRY = raw;
if (c == 'w') WET = raw;
if (c == 'd' || c == 'w') {
Serial.print(F("Calibrated: dry="));
Serial.print(DRY);
Serial.print(F(" wet="));
Serial.println(WET);
}
}
int pct = constrain(map(raw, DRY, WET, 0, 100), 0, 100);
Serial.print(F("Raw: "));
Serial.print(raw);
Serial.print(F(" Moisture: "));
Serial.print(pct);
Serial.println(pct < 30 ? F(" % -> water the plant") : F(" %"));
delay(1000);
}// Capacitive soil moisture sensor v1.2 on an Arduino Nano, read on the analog-only pin A6.
// VCC → 5V, GND → GND, AOUT → A6. Calibrate DRY and WET with your own sensor, then it prints %.
const uint8_t SOIL_PIN = A6;
int DRY = 600; // reading in dry air (send 'd' with the probe in air to store)
int WET = 280; // reading in a glass of water (send 'w' with the probe in water)
int readAverage() {
long sum = 0;
for (uint8_t i = 0; i < 16; i++) {
sum += analogRead(SOIL_PIN);
delay(5);
}
return sum / 16;
}
void setup() {
Serial.begin(115200);
Serial.println(F("Soil sensor on A6 - send d (dry) or w (wet) to calibrate"));
}
void loop() {
int raw = readAverage();
if (Serial.available()) {
char c = Serial.read();
if (c == 'd') DRY = raw;
if (c == 'w') WET = raw;
if (c == 'd' || c == 'w') {
Serial.print(F("Calibrated: dry="));
Serial.print(DRY);
Serial.print(F(" wet="));
Serial.println(WET);
}
}
int pct = constrain(map(raw, DRY, WET, 0, 100), 0, 100);
Serial.print(F("Raw: "));
Serial.print(raw);
Serial.print(F(" Moisture: "));
Serial.print(pct);
Serial.println(pct < 30 ? F(" % -> water the plant") : F(" %"));
delay(1000);
}Expected serial output
Soil sensor on A6 - send d (dry) or w (wet) to calibrate
Raw: 589 Moisture: 3 % -> water the plant
Raw: 402 Moisture: 61 %Soil sensor on A6 - send d (dry) or w (wet) to calibrate Raw: 589 Moisture: 3 % -> water the plant Raw: 402 Moisture: 61 %
Common errors
Moisture always 0 % or 100 %
DRY/WET not calibrated for your sensor — the defaults are only a guess. Use the d and w commands.
digitalRead on A6 always 0
Correct — A6/A7 have no digital input on the Nano. Use analogRead(), as the sketch does.