For several years my wife would take a weekend trip for this or for that and it was my job to maintain the house. It would always happen when my wife would call to say that she was on her way home that I would remember the hanging baskets on the front porch. They were always fried and looking pathetic. It finally occured to me that I would never remember this chore except for when things were tragically bad and beyond repair. I had already used arduinos to automate other chores around the house that had bad results when I would forget like forgetting to close the chicken coop. After doing research online I found several examples where people ust the arduino to measure voltage from a voltage divider using the dirt as one of the resistors to calculate the moisture level in the soil and then have the arduino open a solenoid valve to water the plants. While these were a great jumping off point I ran into issues with these, namely the condition of electricity lowing through the probes in the wet dirty enviroment ate the silver off the probes rendering them worthless in less than a month. Another Issue was the water not soaking around the planter quickly enough after the water shut off so the arduino would run a second or even a third time oversaturating the plants causing root rot and making a mess. So I came up with some solutions to remedy these problems which I am bringing to you today.
First off I built cheeper more durable probes using 2 stainless machine screws and a lego peice which is much more durable as oposed to the comercial probes. next instead of constantly running current through the probe I have the arduino turn the power on and then wait half a second to take the measurement. Finally I set up a 5 hour count down after the water is run figuring that it will never need to be run twice closer than that.
2 8mm Machine Screws
2 Brass lug terminals that fit over the screws
1 Lego peice with 3 holes in it
Wire
Arduino UNO
LCD screen
1K Ohm resistor
Solenoid Valve
Hose
Spray nozzles
I used (2) #10 stainless machine screws, 4 Nuts, and (2 Crimped terminals that fit the screws.
First I put the screws into the terminals
Then 1 Nut onto each screw
Need any peice of nonconductive plastic to hold the probes rigid. I have sourced a spare lego block
Put the Probes through the form and then tighten the last nuts onto each probe.
You want the probes to be parallel and you can play with the spacing but I like about a fingerswidth apart.
The basic principle of the system is simply the concept that after each load in a circuit the voltage will drop. The total of the voltage after each load will add up to the total voltage supplied. This circuit is using resistance as the two loads. The one resistor is a known resistor (I used a 1K but really any resistor would work. I would just avouid using one that is too low. The best option would probably be to measure the resistance of the dirt with an ohm meter and use a similar sized resistor.) while the other resistance is measured from the dirt. As the dirt dries the resistance goes up and as it is watered the resistance is deminished. We can then have the arduino monitor the resistance and turn the water on at the appropriate dryness.
In the Arduino IDE we will start out by defining the variables that we will need:
const int probePin = A0;//This variable is to tell the arduino which pin to read,
//you can skip this and type A0 each time you read the pin
int probeValue = 0;//This Variable is where you will store readings
float Vs = 5;//This variable is the supply voltage and is used to calculate the
//measured resistance
float Vm = 0;//This Variable is to store values in calculating resistance
float Res = 0;//This Variable is where we store calculated Resistance
float Ref = 1000;//This is the value of the resistor we use in the divider
Everything after the "//" is ignored by the arduino and a place to make notes about the code.
After we establish the variables we need to take care of the system Setup:
void setup() {
pinMode(8,OUTPUT);//This is to establish Pin 8 as an output pin so we do
//not have to run voltage through the probe constantly
Serial.begin(9600);//This sets the baud rate so we can read outputs from the
//Arduino in the serial monitor
}
Finally we are ready for our loop which is the part of the program that runs constantly and does the actual work:
void loop() {
digitalWrite (8,HIGH);//Turns pin 8 on so 5 volts are supplied to probe
delay (1000);//waits half a second so that system has a chance to energize
probeValue = analogRead(probePin);//Reads voltage at pin A0, Substitute "A0" for
//"probePin" if you did not set up variable
Vm = (Vs*probeValue/1023);//Not sure on this step but everyone online uses it to
//balance readings to the arduino
Res = Ref*(1/((Vs/Vm)-1));//Using Ohm's law to calculate the resistance
Serial.println(Res);//Prints calculated resistance to the serial monitor
delay (1000);
}
This program as is is set up to test the probe we built so we can monitor it and see the resistance calculated. We can put this code on the arduino and then use serial monitor and know what resistance readings we will see when it is time to turn the water on. We can also see the ideal resistance after we water which will be useful later for how long to run the water for.
Here is the complete code so you can copy and paste it into your arduino IDE:
const int probePin = A0;//This variable is to tell the arduino which pin to read,
//you can skip this and type A0 each time you read the pin
int probeValue = 0;//This Variable is where you will store readings
float Vs = 5;//This variable is the supply voltage and is used to calculate the
//measured resistance
float Vm = 0;//This Variable is to store values in calculating resistance
float Res = 0;//This Variable is where we store calculated Resistance
float Ref = 1000;//This is the value of the resistor we use in the divider
void setup() {
pinMode(8,OUTPUT);//This is to establish Pin 8 as an output pin so we do
//not have to run voltage through the probe constantly
Serial.begin(9600);//This sets the baud rate so we can read outputs from the
//Arduino in the serial monitor
}
void loop() {
digitalWrite (8,HIGH);//Turns pin 8 on so 5 volts are supplied to probe
delay (1000);//waits half a second so that system has a chance to energize
probeValue = analogRead(probePin);//Reads voltage at pin A0, Substitute "A0" for
//"probePin" if you did not set up variable
Vm = (Vs*probeValue/1023);//Not sure on this step but everyone online uses it to
//balance readings to the arduino
Res = Ref*(1/((Vs/Vm)-1));//Using Ohm's law to calculate the resistance
Serial.println(Res);//Prints calculated resistance to the serial monitor
delay (1000);
}
After writing and testing this past section of code it occurs to me that I can greatly simplify this code because I do not truely need to calculate the resistance of the dirt. Since the Arduino is reading an actual voltage and then working backwards to find the resistance I can skip this step and then just figure out at which measured voltage the water should turn on. So this will elliminate the need for the variables "Vs, Vm, Res, and Ref." It will also eliminate almost all of the code inside the loop. The new code will now look like
const int probePin = A0;//This variable is to tell the arduino which pin to read,
//you can skip this and type A0 each time you read the pin
int probeValue = 0;//This Variable is where you will store readings
void setup() {
pinMode(8,OUTPUT);//This is to establish Pin 8 as an output pin so we do
//not have to run voltage through the probe constantly
Serial.begin(9600);//This sets the baud rate so we can read outputs from the
//Arduino in the serial monitor
}
void loop() {
digitalWrite (8,HIGH);//Turns pin 8 on so 5 volts are supplied to probe
delay (1000);//waits half a second so that system has a chance to energize
probeValue = analogRead(probePin);//Reads voltage at pin A0, Substitute "A0" for
//"probePin" if you did not set up variable
Serial.println(probeValue);//Prints measured voltage to the serial monitor
delay (1000);
}
Now we will need to load the program onto our board and watch the serial monitor. We will need to get our probe inserted into the dirt around the plants we want to water and wait for the dirt to be the most dry we would want to tolerate. Read the voltage printed to the serial monitor and make a note of the value. Now water your plants appropriately and see what the voltage value does and make a note of this value. Did the voltage change with watering? Did the readings make sense? If they did we are ready to setup our code using the numbers we recorded and adding a relay to do the work for us.
For my testing I used one of our lemon bushes that was ready to be watered.
As you can see I am getting reading from the probe of 20. I am suprised that this reading is not less than 5 but that must be where that number people use in the calculations comes from. I want to figure that part out but for now it is not important, the only thing that matters is that we can change that number when we add water.
As you can see as I water the plant with the water right on the probe the reading goes as high as 479. So what is going on? Since the water which is highly conductive when it has minerals disolved into it is directly on the probe the resistance goes way down and the voltage allowed through now goes up inversly. Now we let the water soak in and see what happens to our readings.
So now we can see that once the water has soaked in and the system balances out we are getting reading of 192. So this is the information for the code moving forward; the first number we will have the Arduino look for to turn the water on, and then we will watch how long we need to run the water to achieve the second number.
We are now ready to use these readings to set our arduino up to turn the water on and off. Since I am pushing for watering multiple zones in the polyhouse I am going to use variables for all of the pins and readings so that I can just copy and paste for each region and then adjust the numbers at the top of the code.
Here is the code with coments on each line
const int probePin = A0; //pin where we will read voltage
const int probepower = 8; //pin that will output voltage to the probe
int probeValue = 0; //establishes a variable to store measured voltage
const int relayPin = 2; //pin that will turn relay on and off
const int toodry = 20; //variable to set when to turn water on,
//came from calibration in last step
const int saturated = 250; //variable for when plants are over saturated
const int runtime = 6000; //variable for how long to run water,
//if we notice over saturation we can adjust down
//if it runs very often we may need to adjust up
void setup() {
pinMode(probepower,OUTPUT); //Sets our pins to output 5 volts when turned
pinMode(relayPin,OUTPUT); //on or off
Serial.begin(9600); //sets our serial monitor baud rate
}
void loop() {
digitalWrite (relayPin, LOW); //makes sure our water is off in the beginning
digitalWrite (probepower, HIGH); //applies power to the probe
delay (1000); //gives system a half second to balance out
probeValue = analogRead(probePin); //reads and assigns value to variable
delay (1000); //balances system
digitalWrite (probepower, LOW); //turns power to probe off so we do not damage probe
Serial.println (probeValue); //writes the readingto the serial monitor
if (probeValue < toodry) //sets condition to turn water on based on reading
{
digitalWrite (relayPin, HIGH); //turns water on
delay (runtime); //keeps water running for length of time we decide
digitalWrite (relayPin, LOW); //turns water off
}
delay (1000); //balances system
if (probeValue > saturated) //sets condition to print if system is over watering so
//we know to adjust
{
Serial.println ("saturated");
}
delay (1000); //balances system
if (probeValue < saturated) //sets condition for not oversaturated
{
if (probeValue > toodry) //sets condition for not over dry
{
Serial.println ("Normal range"); //prints that things are good
}
}
delay (600000); //puts system on hold for 5 minutes since system will not dry out that fast
//makes probe last longer
}