Arduino Soil Moisture Alarm

So decided to take a break from the esp8266  frenzy I’ve been on.  (Why shouldn’t the coffee machine be hooked up to the internet?)  I had one of those cheap soil moisture sensors come in the mail yesterday from Aliexpress and decided to try it out.  Turns out they are pretty much just a cheap PCB probe with a small circuit for an adjustable digital comparator and resistor for analog input.  (D0 and A0 pins respectively.)

soil moisture
Hygrometer with comparator.

Spent the afternoon putting some code together to output the approximate soil moisture level on some bargraph LEDs.  As the soil dries out, the resistance across the probes increases until all of the LEDs are extinguished.  If the soil completely dries out (an effective open circuit), all the leftmost red LED will light and a buzzer will sound until the plant has been watered again.  The 10K resistor that is on the supplied circuit forms a voltage divider with the probe that is read by the analog in of the Arduino. (As I’m not using the digital comparator on it I could omit the whole thing and just use a 10K resistor)  To help prevent against electrolysis, the probe is only powered on by a NPN transistor when a reading is recorded, once an hour. This reading is scaled down to the range of the LEDs and the corresponding lights are activated.

soil_moisture (6)

This was an fun afternoon project to put together, and can easily be scaled up to different use cases.  Instead of activating the buzzer, a small water pump could easily be activated to self water.  This project would also work out great ported to an esp8266 to graph moisture levels over time or provide remote watering.   Be nice to set it up with multiple probes for other plants as well.

I’m worried about the probes corroding over time and the measurement range getting out of wack, but as a proof of concept this works fine for now.  Will probably just make my own probes (galvanoized nails in plaster?) or switch to capacitive probes after this,  the digital comparator on the PCB is useless for me and the analog section is just a simple voltage divider.  Can update in a month or so and see how it held up.

 

 /*
Name: Soil_Monitor_Arduino.ino
Created: 3/24/2017 9:08:29 PM
Author: Diego
Notes:
*/

// ___DECLARE VARIABLES___
int analogSoilPin = A0; //analog Pin for soil sensor
int digitalPower = 8; //pin to turn sensor on and off
int buzzer = 7; // buzzer pin

int ledPins[] = { 9, 10, 11, 12, 13 }; //array holding pin numbers

unsigned long currentTime = 0; //hold current time value
unsigned long lastTime = 0; //hold prevous time value

long interval = 3600000; //intervel time for readings in mS '1hour is 3600000'

int anaSoil = 0; //variable analog soil value
int digSoil = 0; //variable analog soil value

int minLvl = 500; //minimum soil resistance
int maxLvl = 950; //maximum soil resistance

int ledLevel = 0; //translated ledLevel (0-4)

// ___SETUP___
void setup() {
Serial.begin(9600); //start serial
pinMode(analogSoilPin, INPUT); //set analog pin

for (int thisPin = 0; thisPin <= 4; thisPin++) { //set LED pins to OUTPUTs
pinMode(ledPins[thisPin], OUTPUT);
}

pinMode(buzzer, OUTPUT); //buzzer pin
pinMode(digitalPower, OUTPUT); //set digital pin
readSensor(); //Initital sensor read
clearLeds(); //make sure leds off
updateLeds();

digitalWrite(digitalPower, 0); //turn off sensor pin
}

// ___MAIN LOOP___
void loop() {

unsigned long currentTime = millis(); //set current time

if (currentTime - lastTime > interval) { //is current time - last time we entered loop greater than interval?
lastTime = currentTime; //it is so update time

readSensor(); //Read the sensor
clearLeds(); //clear leds
updateLeds();
}
}


// ___FUNCTIONS___
// --Update Leds--
void updateLeds() {
int ledLevel = map(anaSoil, minLvl, maxLvl, 0, 4); //map anaSoil to ledLevel

switch (ledLevel) {

case 0:
digitalWrite(ledPins[0], 1);
digitalWrite(ledPins[1], 1);
digitalWrite(ledPins[2], 1);
digitalWrite(ledPins[3], 1);
digitalWrite(ledPins[4], 1);
break;
case 1:
digitalWrite(ledPins[0], 1);
digitalWrite(ledPins[1], 1);
digitalWrite(ledPins[2], 1);
digitalWrite(ledPins[3], 1);
break;

case 2:
digitalWrite(ledPins[0], 1);
digitalWrite(ledPins[1], 1);
digitalWrite(ledPins[2], 1);
break;

case 3:
digitalWrite(ledPins[0], 1);
digitalWrite(ledPins[1], 1);
break;

case 4:
digitalWrite(ledPins[0], 1);
alarm(); //call buzzer function, its too dry
break;
}

}
// --CLEAR lEDS--
void clearLeds() {
for (int thisLed = 0; thisLed <= 4; thisLed++) { //starting at 0, increment leds and turn off
digitalWrite(ledPins[thisLed], 0);
}
}

// --READ SENSOR--
void readSensor() {
digitalWrite(digitalPower, 1); //turn on sensor pin
delay(100); //let voltage stabalize?

anaSoil = analogRead(analogSoilPin); //analog read of soil sensor
Serial.print("The analog soil value is = ");
Serial.print(anaSoil);
Serial.println();

digitalWrite(digitalPower, 0); //turn off sensor pin
return;
}

// --BUZZER FUNCTION--
void alarm() {

if (anaSoil < maxLvl) { //is sensor wet? return if so
return;
}

else { //still dry, sound the alarmn
for (int i = 0; i < 10; i++) {

tone(buzzer, 4000, 50); //strobe tone out... (pin, khz, duration)
delay(100);
}
}
}