Plant monitor on an Arduino Uno
A soil moisture sensor, a rain sensor and a water level sensor on three analog pins. Two read lower when wetter and one reads higher. The whole build, an Arduino Uno and 5 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 20 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $33. On Mokxi they're free.
Step by step, with the wiring and the common mistakes: Arduino Soil Moisture Sensor: Code and Wiring
What you'll learn
- Reading several analog sensors
- Sensors that read lower when wetter
- Calibrating with two end points and
map - A comparator output on a digital pin
- Combining conditions to drive a lamp
- Difficulty: Intermediate
- Time: About 20 minutes
- Board: Arduino Uno R3
- Parts: 7
How it works
Three sensors measure water, and they do not agree which way is up. Once a second the sketch reads the soil sensor on A0, the rain sensor on A1 and the water level sensor on A2, plus the rain sensor's digital output on pin 7, and prints them.
The capacitive soil sensor reads lower when wetter, about 520 in air and 260 in water, so map is given the two ends swapped to make a percent. The rain plate reads 1023 when dry and falls when wet. Its board pulls DO low when it is wet enough. The water level reading goes higher as water rises.
The green lamp on pin 8 lights when the soil is under 30 percent and it is not raining.
Parts list
7 parts, plus the jumper wires. They retail for about $33; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Half breadboard
- 1 × Soil moisture sensor, capacitive
- 1 × Rain sensor
- 1 × Water level sensor
- 1 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × LED, greenIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Resistor, 220 Ω pin 1 | Arduino Uno R3 pin 8 |
| Rain sensor pin DO | Arduino Uno R3 pin 7 |
| Soil moisture sensor, capacitive pin VCC | Arduino Uno R3 pin 5V |
| Rain sensor pin VCC | Arduino Uno R3 pin 5V |
| Water level sensor pin VCC | Arduino Uno R3 pin 5V |
| Soil moisture sensor, capacitive pin GND | Arduino Uno R3 pin GND |
| Rain sensor pin GND | Arduino Uno R3 pin GND |
| Water level sensor pin GND | Arduino Uno R3 pin GND |
| LED, green pin C | Arduino Uno R3 pin GND |
| Soil moisture sensor, capacitive pin AOUT | Arduino Uno R3 pin A0 |
| Rain sensor pin AO | Arduino Uno R3 pin A1 |
| Water level sensor pin S | Arduino Uno R3 pin A2 |
| LED, green pin A | Resistor, 220 Ω pin 2 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Plant monitor: the soil, the rain and the water butt, once a second.
//
// A0 the soil sensor's AOUT A1 the rain sensor's AO
// A2 the water level's S pin 7 the rain sensor's DO
// pin 8 the "water me" lamp, through 220 ohm to GND
// every sensor's VCC -> 5 V and GND -> GND
//
// Three sensors that all look like "an analog pin that means water", and they
// disagree about which way is up. That is the thing to take away.
//
// # The soil sensor reads lower when it is wetter
//
// The capacitive stake gives about 520 counts held in the air and about 260
// with its tip in water, and the soil is somewhere between. So the percentage
// is map(reading, 520, 260, 0, 100): the two ends swapped. Those two numbers
// are this sensor's; a real one is calibrated in dry and soaked soil first.
//
// # The rain sensor reads lower too, and has a comparator
//
// Dry, the plate is open and A1 reads the full 1023. Wet, it falls. Its board
// also compares that with its trimmer and pulls DO low when it is wet enough,
// so pin 7 is a plain "is it raining" without any arithmetic.
//
// # The water level reads higher, and not in millimetres
//
// Its transistor turns on as soon as the tip is wet and then creeps up as the
// water rises: most of the reading is in the first few millimetres. It is a
// level indicator, not a gauge.
//
// # The lamp
//
// Pin 8 lights when the soil is under 30% and it is not raining: the plant
// wants water and the sky is not going to give it any.
const int SOIL = A0;
const int RAIN_AO = A1;
const int WATER = A2;
const int RAIN_DO = 7;
const int LAMP = 8;
// This sensor's two ends, in counts on a 5 V board.
const int SOIL_AIR = 520;
const int SOIL_WATER = 260;
void setup() {
pinMode(RAIN_DO, INPUT);
pinMode(LAMP, OUTPUT);
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: plant monitor");
}
void loop() {
int soil = analogRead(SOIL);
int percent = constrain(map(soil, SOIL_AIR, SOIL_WATER, 0, 100), 0, 100);
int rain = analogRead(RAIN_AO);
bool raining = digitalRead(RAIN_DO) == LOW;
int water = analogRead(WATER);
Serial.print("soil ");
Serial.print(percent);
Serial.print("% (");
Serial.print(soil);
Serial.print(") rain ");
Serial.print(rain);
Serial.print(raining ? " raining" : " dry");
Serial.print(" water ");
Serial.println(water);
digitalWrite(LAMP, percent < 30 && !raining ? HIGH : LOW);
delay(1000);
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
setup makes the rain sensor's DO pin an input, the lamp pin an output, and starts serial at 115200 with a title line.
void setup() {
pinMode(RAIN_DO, INPUT);
pinMode(LAMP, OUTPUT);
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: plant monitor");
}loop sketch.ino
loop reads all three sensors. It turns the soil count into a percent, with map and constrain keeping it between 0 and 100. It decides it is raining when DO is LOW, prints one line of readings, and switches the lamp. Then it waits a second.
void loop() {
int soil = analogRead(SOIL);
int percent = constrain(map(soil, SOIL_AIR, SOIL_WATER, 0, 100), 0, 100);
int rain = analogRead(RAIN_AO);
bool raining = digitalRead(RAIN_DO) == LOW;
int water = analogRead(WATER);
Serial.print("soil ");
Serial.print(percent);
Serial.print("% (");
Serial.print(soil);
Serial.print(") rain ");
Serial.print(rain);
Serial.print(raining ? " raining" : " dry");
Serial.print(" water ");
Serial.println(water);
digitalWrite(LAMP, percent < 30 && !raining ? HIGH : LOW);
delay(1000);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The soil percent seems backwards. This project
That is expected to need swapped ends. The sensor reads lower when wet, soSOIL_AIRis the big number andSOIL_WATERthe small one. - The lamp stays off though the soil is dry. This project
The lamp stays off when the rain sensor says it is raining, which is DO reading LOW. - Your sensor gives different numbers. This project
EditSOIL_AIRandSOIL_WATERto the counts from your own sensor in air and in water. - The reading seems backward: wet soil gives a lower number. Soil moisture sensor
A capacitive sensor reads lower when wetter. Measure it in dry air and in a glass of water, then map those two values to 0 and 100 percent. - The reading is unstable or the sensor corrodes. Soil moisture sensor
Keep the electronics above the soil line and do not submerge past the marked line. Power it from 3.3 V or 5 V as the board allows, and average several readings. - The sensor reads wet or dry all the time. Rain sensor
Turn the trimmer to set the DO threshold, and test with a drop of water. AO falls when the plate is wetter. Power it with 3.3 V to 5 V and share ground. - The plate corrodes and stops working after a while. Rain sensor
The traces carry current through water, which wears them away. Power the sensor only when you read it, using a digital pin for VCC, and rinse and dry the plate. - The reading keeps changing and the probe traces corrode. Water level sensor
Do not leave power on all the time. Power the sensor only when you read it, since DC current across wet traces causes corrosion.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.