ESP32 UNO - Soil Moisture Sensor
Does your plant need water? Connect a soil moisture sensor to the ESP32 Uno form board and let the Arduino code tell you. The ESP32 Uno reads the sensor as a number from 0 to 4095, and you can use that number to decide if the soil is wet or dry.
By the end, you can:
- Choose between a resistive and a capacitive moisture sensor
- Wire a capacitive soil moisture sensor to the ESP32 Uno
- Read the moisture level with analogRead() in Arduino IDE
- Calibrate the sensor for your own soil
- Print "wet" or "dry" from a threshold value

Components You Need
| 1 | × | ESP32 Uno-form Board | |
| 1 | × | USB Cable Type-A to Type-C (for USB-A PC) | |
| 1 | × | USB Cable Type-C to Type-C (for USB-C PC) | |
| 1 | × | Capacitive Soil Moisture Sensor | |
| 1 | × | Jumper Wires |
Or you can buy the following kits:
| 1 | × | DIYables Sensor Kit (18 sensors/displays) |
Additionally, some of these links are for products from our own brand, DIYables .
Buy Note: Many soil moisture sensors available in the market are unreliable, regardless of their version. We strongly recommend buying the sensor with TLC555I Chip from the DIYables brand using the link provided above. We tested it, and it worked reliably.
Two Kinds of Soil Moisture Sensor
By the end of this part, you know which sensor type to buy and why.

| Feature | Resistive Sensor | Capacitive Sensor |
|---|---|---|
| How it measures | Current flows between two bare probes | Probe measures a change in capacitance |
| Probe surface | Bare metal | Covered with a coating |
| Wear | Corrodes after some time in wet soil | Does not corrode |
| Our advice | Avoid | Use this one |
The resistive probes send a small current through the soil. That current causes electrochemical corrosion, so the metal wears away and the readings drift. The photo below shows a probe that corroded this way.

The rest of this page uses the capacitive sensor.
Capacitive Soil Moisture Sensor Pinout
The sensor has three pins.
| Pin | Role |
|---|---|
| GND | Ground (0V) |
| VCC | Power, 3.3V to 5V. Use 3.3V with the ESP32 Uno |
| AOUT | Analog signal that changes with the water in the soil |

Good to know: the AOUT voltage goes DOWN when the soil gets wetter. So a small number from the ESP32 Uno means wet soil, and a big number means dry soil.
How the Reading Changes
More water around the probe gives a lower voltage on AOUT. The ESP32 Uno ADC turns that voltage into a number from 0 to 4095 (12-bit).
ESP32 Uno Pinout
Every Uno header pin on the ESP32 Uno form board has its own GPIO number, and the code uses that number. Look at the diagram to find A0 and its GPIO before you wire the sensor.

How to Connect the Sensor
By the end of this part, the sensor is powered and its signal goes to the ESP32 Uno.

This image is created using Fritzing. Click to enlarge image
| Sensor Pin | ESP32 Uno Pin |
|---|---|
| VCC | 3.3V |
| GND | GND |
| AOUT | A0 (GPIO2) |
WARNING
A0 (GPIO2) is a boot strapping pin. If the sensor holds this pin at a strong level while the board starts or while you upload code, the upload can fail. Unplug the AOUT wire during upload if this happens. Power the sensor from 3.3V so the AOUT signal never goes above what the ESP32 Uno pin can take.
Good to know: ESP32 Uno pins are not 5V tolerant. A0 (GPIO2) is an ADC2 pin, which is fine here because this sketch does not use WiFi.
ESP32 Uno Code - Read the Moisture Value
The sketch reads A0 (GPIO2) twice a second and prints the raw value.
| Code Part | What It Does |
|---|---|
| AOUT_PIN 2 | Selects GPIO2, which is the A0 hole on the Uno header |
| analogSetAttenuation(ADC_11db) | Widens the ADC input range to about 0-3.3V |
| analogRead(AOUT_PIN) | Returns the moisture level as 0 to 4095 |
| Serial.println(value) | Sends the number to the Serial Monitor |
| delay(500) | Gives two readings per second |
Good to know: the 11 dB setting lets the analog pin read the full range, from 0V up to about 3.3V. Without it, the readings reach 4095 too early and the moisture values look wrong.
Detailed Instructions
- First time with this board? Set it up with ESP32 Uno - Getting Started before you continue.
- Build the circuit by following the wiring table above.
- Plug in the USB Type-C cable between the ESP32 Uno and your computer.
- Select the board in Arduino IDE: pick ESP32 Dev Module and the COM port of the board (CH340).
- Copy the code above into a new sketch.
- Click Upload and wait for the "Done uploading" message.
- Open the Serial Monitor at 9600 baud.
- Test it: push the sensor into dry soil, then slowly pour water next to it. You can also dip the sensor in a cup of salt water.
- Watch the values drop as the soil gets wet. Output looks like this:
- Pro tip: let the reading settle for about 10 seconds after you move the sensor. Water needs time to spread through the soil.
※ NOTE THAT:
- Do not use pure water for the test. Pure water conducts almost no electricity, so it hardly changes the reading.
- The value does not fall to zero. It stays in a band that depends on the soil, the depth of the probe and the supply voltage.
- Keep the electronics at the top of the sensor dry. Push only the marked probe part into the soil.
Video Tutorial
See the ESP32 Uno build in action in the video below.
Calibrate the Sensor
By the end of this part, you have your own wet/dry threshold.
The reading depends on the soil type and its water content, so no fixed number works for everyone. Do this once:
Step 1 - Start the sketch
Run the code above and open the Serial Monitor.
Step 2 - Insert and water
Push the sensor into the soil, then add water a little at a time.
Step 3 - Note the switch point
Write down the value at the moment you think the soil goes from dry to wet. This number is your THRESHOLD.
Tell Wet Soil from Dry Soil
By the end of this part, the ESP32 Uno prints if the soil is wet or dry.
Put your THRESHOLD into the sketch below. The value 2000 is only an example, so replace it with the number you noted.
| Code Part | What It Does |
|---|---|
| THRESHOLD 2000 | The border between dry and wet, set by you |
| value > THRESHOLD | True when the soil holds little water |
| Serial.print(value) | Shows the number next to the text |
The Serial Monitor shows the result:
ESP32 Uno vs UNO R4 for This Project
By the end of this part, you know what to change when you move this project from the UNO R4 to the ESP32 Uno.
| Item | Arduino UNO R4 | ESP32 Uno |
|---|---|---|
| Logic voltage | 5V | 3.3V |
| Sensor pin | A0 | A0 (GPIO2), written as 2 in code |
| ADC range | 0-1023 | 0-4095 |
| Typical wet/dry threshold | about 530 | about 2000, calibrate it yourself |
| Extra code line | none | analogSetAttenuation(ADC_11db) |
| Sensor power | 5V | 3.3V |
| Arduino IDE board | Arduino UNO R4 WiFi | ESP32 Dev Module |
The wiring stays the same on the Uno header, but power the sensor from 3.3V. Your old threshold must be calibrated again because the ADC range is four times bigger.
Go Wireless: Check Your Plant from the Couch
By the end of this part, you know how to read soil moisture on your phone.
The ESP32 Uno has WiFi and Bluetooth built in. Send the moisture value to a web page or to a phone app, and you see the soil state without walking to the pot. Note that the ESP32 Uno cannot read A0 (GPIO2) with analogRead() while WiFi is on, so for WiFi projects move the AOUT wire to A2 (GPIO35) and change AOUT_PIN in the code.
Function References
Troubleshooting
| Problem | Possible Cause | Solution |
|---|---|---|
| No COM port in Arduino IDE | CH340 driver missing or charge-only USB cable | Install the CH340 driver and use a USB cable that carries data |
| Upload fails with "Failed to connect" | Board is not in download mode | Hold the BOOT button when the upload starts |
| Upload fails only with the sensor wired | A0 (GPIO2) is a boot strapping pin and the sensor pulls it | Unplug the AOUT wire during upload, then plug it back |
| Reading is always 0 | VCC or GND not connected | Check the wires and power the sensor from 3.3V |
| Reading is always 4095 | AOUT floating or wrong pin | Connect AOUT to A0 (GPIO2) and check the pin number in code |
| Values hit 4095 too early | Attenuation line missing | Keep analogSetAttenuation(ADC_11db) in setup() |
| Values jump around | Loose jumper wire or electrical noise | Re-seat the wires and average a few samples |
| Wet soil gives a high number | Reading is reversed in your mind | On this sensor a lower number means wetter soil |
| Sensor stops working after some weeks | Water got into the electronics | Keep the top of the sensor dry and seal the edge |
FAQ
How does a capacitive soil moisture sensor work?
It measures how the water in the soil changes the capacitance around its probe. The sensor turns this change into a voltage on the AOUT pin. More water gives a lower voltage.
Should I power the sensor with 3.3V or 5V on the ESP32 Uno?
Use 3.3V. The ESP32 Uno pins are not 5V tolerant, and a 5V supply can push the AOUT signal above what the analog pin can take.
Why do I get numbers up to 4095 and not 1023?
The ESP32 Uno has a 12-bit ADC, so analogRead() returns 0 to 4095. A UNO R4 sketch with a threshold of 530 needs a new threshold here.
Why does the code call analogSetAttenuation(ADC_11db)?
It sets the ESP32 Uno ADC input range to about 0-3.3V, so the full sensor signal maps to 0-4095. With a smaller range, readings saturate early. The UNO R4 does not need this line, because it is an ESP32-only call. Keep the sensor output at 3.3V or less.
Can I connect the sensor to a different pin?
Yes. Use A2 to A5 (GPIO35, 34, 36, 39) for input-only analog reads, which are safe for a sensor. Change AOUT_PIN to the new GPIO number.
Why should I avoid A0 (GPIO2) for permanent builds?
GPIO2 is a boot strapping pin, and it is an ADC2 pin. ADC2 stops working for analogRead() when WiFi is on. A2 (GPIO35) is a better choice for a WiFi project.
How do I find the right THRESHOLD value?
Read the raw value in dry soil and again in wet soil. Pick a number between the two, then test it with your plant and adjust it.
Can I use two soil moisture sensors?
Yes. Put the second AOUT on another analog pin such as A2 (GPIO35), add a second #define and call analogRead() for each pin.
Can I see the soil moisture on my phone?
Yes. The ESP32 Uno has WiFi and Bluetooth. The Go Wireless section above lists tutorials that show a value on a web page or in a phone app.
What if my project needs more pins than the Uno headers give?
The ESP32 Uno has a few extra holes near the power header: GPIO32 and GPIO33 (I/O, PWM, analog on ADC1, so they also work while WiFi is on) and GPIO15 (I/O, PWM, analog on ADC2). Solder pin headers to use them and write the GPIO number in code. For a second soil sensor in a WiFi project, GPIO32 or GPIO33 fit best. Two warnings: (1) GPIO15 and GPIO0 (the IO0 pin at the unused Uno NC position) are boot strapping pins, so a wrong connection can stop the board from booting or uploading code. Use GPIO32 and GPIO33 first. (2) Never use the six holes under the digital header (SD0-SD3, CMD, CLK = GPIO6-GPIO11). They are wired to the flash chip and using them crashes the board.