Automatic Plant Watering

Hello everyone,

I'm trying to make an Arduino UNO watering device that will water my plants twice a day on a given schedule. Here is how it will work first, the uno will read the soil moisture level using the digital reading of the hl 69 soil moisture sensor and will display it on the 16x2 i2c LCD. Then it will check the time in the ds3231 RTC module, if the time matches the given schedule and the soil moisture is dry it will turn on the pump until the soil is wet. My problem is when the first function is completed, if I lift the soil moisture sensor the Uno turns on the water pump even if the time doesn't match the given schedule.

I also want to be able to turn on/off the water pump using Bluetooth if I send a character, for example "W" for turn on and "S" or if the soil is wet for off. The problem is the water pump does not turn off even when the soil is wet. Your help will be greatly appreciated.

here is my code

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

// Define the I2C LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Define the DS3231 RTC
RTC_DS3231 rtc;

const int hc05_rxPin = 10; // SoftwareSerial rx pin
const int hc05_txPin = 11; // SoftwareSerial tx pin
const int waterPumpPin = 8; // Relay pin
const int soilMoistureSensor = 6; // Soil Moisture pin

// Define the watering times
const int wateringHour1 = 8; // 8 AM
const int wateringHour2 = 20; // 8 PM

// Initialize software serial for HC-05 Bluetooth module
SoftwareSerial bluetooth(hc05_rxPin, hc05_txPin);

void setup() {
  // Initialize the LCD
  lcd.init();
  lcd.backlight();

  // Initialize the RTC
  rtc.begin();
  
  pinMode(waterPumpPin, OUTPUT); // Set the water pump pin as an output
  digitalWrite(waterPumpPin, HIGH); // Set the water pump as turned off initially

  Serial.begin(9600); // Initialize serial communication with the computer (USB)
  bluetooth.begin(9600); // Initialize serial communication with the HC-05 Bluetooth module
  Serial.println("Bluetooth Serial started at 9600 baud");
}

void loop() {
  // Read the current time
  DateTime now = rtc.now();

  // Read the soil moisture level
  bool soilIsDry = digitalRead(soilMoistureSensor);

  // Display the soil moisture level on the LCD
  lcd.setCursor(0, 0);
  lcd.print("Soil Moisture: ");
  lcd.setCursor(0, 1);
  lcd.print(soilIsDry ? "Low" : "High");

  // Bluetooth function
  if (bluetooth.available()) { 
    char receivedChar = bluetooth.read();
    
    // Turn on the water pump
    if (receivedChar == 'W') {
      digitalWrite(waterPumpPin, LOW);
      Serial.println("Water pump turned ON");
    }
    
    // Turn off the water pump
    else if (receivedChar == 'S' || !soilIsDry) {
      digitalWrite(waterPumpPin, HIGH);
      Serial.println("Water pump turned OFF");
    }
  }

  // Scheduled watering function 
  else if ((now.hour() == wateringHour1 || now.hour() == wateringHour2) && soilIsDry) {
    // Turn on the water pump
    digitalWrite(waterPumpPin, LOW);

    // Wait until the soil is wet enough
    while (digitalRead(soilMoistureSensor)) {
      delay(1000);
    }
    // Turn off the water pump
    digitalWrite(waterPumpPin, HIGH);
  }

  // Wait for a second before the next loop
  delay(1000);
}

Given that the Uno is a 5V board, could you explain why you have chosen to power both the DS3231 RTC and the hygrometer from 3.3V? Your problem could be as simple as the the digital output from the hygrometer not meeting the minimum Vih of 3.0V for the ATmega328P and soilIsDry thereby never being true.

I think your are missing

pinMode(soilMoistureSensor,INPUT);// INPUT_PULLUP?

somewhere

Every pin is INPUT after starting a board.

I have tried powering the hygrometer with 5v but the code still doesn't work, and I think it the hygrometer is working because it's showing its reading on the lcd.

i have added it in the code but it's still not working.

I might have to clarify that the turning off by soil moisture reading is only not working when I turn on the water pump by Bluetooth. But when it is turned on by the scheduled time, the turning off by soil moisture reading is working.

Do you have a DMM? Digital MultiMeter?

Measure the 3V3 supply with the modules connected.
The 3V3 regulator on the UNO may not be able to supply the current that they need.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

1 Like

Unfortunately I don't have a digital multimeter but I already transferred the ds3231 and hygrometer from 3.3v to 5v. but it still doesn't work

Unfortunately I don't have a digital multimeter but I already transferred the ds3231 and hygrometer from 3.3v to 5v. but the code still doesn't work.

I'll run your code when I am in the lab next, but for sure the first thing I would do is add printing statements in a several more places.

The code looks logically correct, at a glance, but this does depend on the sensor reading, especially the while loop.

Print statements will allow you to see the values of key variables, and confirm that they are pro informing the flow thought your code.

L8R

a7

Your drawing shows the sensor wires from the second sensor connected in parallel with the first sensor. Please explain this and post a link to your FC-28 datasheet.

1 Like

@JCA34F
If it is the FC 28 Soil Hygrometer and the FC 28 Soil Hygrometer Probe,
When I saw the image, I also thought the same thing, but then I noticed that one is the module and the other is the probe.

hello again everyone, I have an update, I have already fix the issue I've mentioned in my first paragraph. the only thing I am having trouble right now is on the bluetooth function, which is when I turn on the water pump using bluetooth it does not automatically turn off even if the soil moisture level is high.

here is my updated code

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

// Define the I2C LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Define the DS3231 RTC
RTC_DS3231 rtc;

const int hc05_rxPin = 10; // SoftwareSerial rx pin
const int hc05_txPin = 11; // SoftwareSerial tx pin
const int waterPumpPin = 8; // Relay pin
const int soilMoistureSensor = 6; // Soil Moisture pin

// Define the watering times
const int wateringHour1 = 7; // 8 AM
const int wateringMin1 = 48;
const int wateringHour2 = 19; // 8 PM
const int wateringMin2 = 49;

// Initialize software serial for HC-05 Bluetooth module
SoftwareSerial bluetooth(hc05_rxPin, hc05_txPin);

void setup() {
  // Initialize the LCD
  lcd.init();
  lcd.backlight();

  // Initialize the RTC
  rtc.begin();
  
  pinMode(waterPumpPin, OUTPUT); // Set the water pump pin as an output
  digitalWrite(waterPumpPin, HIGH); // Set the water pump as turned off initially

  Serial.begin(9600); // Initialize serial communication with the computer (USB)
  bluetooth.begin(9600); // Initialize serial communication with the HC-05 Bluetooth module
  Serial.println("Bluetooth Serial started at 9600 baud");
}

void loop() {

  // Read the current time
  DateTime now = rtc.now();

  // Read the soil moisture level
  bool soilIsDry = digitalRead(soilMoistureSensor);

  // Display the soil moisture level on the LCD
  lcd.setCursor(0, 0);
  lcd.print("Soil Moisture: ");
  lcd.setCursor(0, 1);
  lcd.print(soilIsDry ? "Low" : "High");


  // Bluetooth function
  if (bluetooth.available()) { 
    char receivedChar = bluetooth.read();
    
    // Turn on the water pump
    if (receivedChar == 'W') {
      digitalWrite(waterPumpPin, LOW);
      Serial.println("Water pump turned ON");
    }
    
    // Turn off the water pump
    else if (receivedChar == 'S' || !soilIsDry) {
      digitalWrite(waterPumpPin, HIGH);
      Serial.println("Water pump turned OFF");
    }
  }

  //Scheduled watering function 
  else if ((now.hour() == wateringHour1 && now.minute() == wateringMin1 || now.hour() == wateringHour2 && now.minute() == wateringMin2) && soilIsDry) {
    // Turn on the water pump
    digitalWrite(waterPumpPin, LOW);

    // Wait until the soil is wet enough
    while (digitalRead(soilMoistureSensor)) {
      delay(1000);
    }
    // Turn off the water pump
    digitalWrite(waterPumpPin, HIGH);
  }

  // Wait for a second before the next loop
  delay(1000);
}

I don't have the datasheet, but here is the link where I bought it.
https://s.lazada.com.ph/s.Pk8dQ

I am out of time - she who must not be kept waiting has texted, and we will be rolling towards the beach soon.

But I did uncover some fighting between the two sections that have the power to turn on, or off, the water.

One thing I cannot test is whether your bluetooth is sending more than 'W' or 'S'. I was using the serial monitor input capability as a proxy for bluetooth, and noticed that the line ending characters were allowing this

    // Turn off the water pump
    else if (receivedChar == 'S' || !soilIsDry) {
      digitalWrite(waterPumpPin, HIGH);
      Serial.println("Water pump turned OFF");
    }

to turn off the pump. If there is no character received, it can't check.

(The timing section works for me with some minor changes, perhaps the same ones you implemented.)

You have to figure out another method to turn off the pump if it was turned on by bluetooth.

First, don't let BT turn on the pump if the soil is wet, instead say you aren't gonna water wet soil. But if it does turn on the pump, remember that, and add a statement at the top level of the loop (not buried in any control structure) that basically say "oh, I am pumping because of BT, but now the soil is wet, so Imma turn off the pump".

You may want to add somethings like this

//... print once when we fall into the watering loop
    bool hasSaid = false;
    // Wait until the soil is wet enough
    while (digitalRead(soilMoistureSensor)) {
      if (!hasSaid) {
        Serial.println("watering... looping");
        hasSaid = true;
      }
      delay(500);
    }
    Serial.println("           and wet, so done.");
    // Turn off the water pump
    digitalWrite(waterPumpPin, HIGH);

which doesn't just die when it gets stuck pumping until the soil is wet, but says that's why things look dead.

I have the hole thing working well, with proxies for all the hardware, but it is prolly best for you to consider my observations and do the slight further fixing this needs.

In the future, this could be written so there is no blocking loop that waters until the cows come home - a damaged sensor would mean water water everywhere, nor any means to check that it should be turned off, like been running for 7.77 minutes.

Such a check could be added to the blocking loop which starts with

    while (digitalRead(soilMoistureSensor)) {

HTH

a7

A fellow member of the UA who will not be named has pointed out that you can just put a simple statement anywhere that turns the pump off if the soil is wet.

This simplifies the timed section, which only needs take responsibility for turning in the pump if it is time and the soil is dry. It would not have to block.

This simplifies BT section as well, as it could then only turn off under command, and leave the wet check for that single point where the pumps get turned off if the soil is wet.

pseudocode

if we get a 'W' and the soil is dry turn on the pump 

if we get an 'S' turn off the pump

if it is time and the soil is dry turn on the pump

if the soil is wet turn off the pump

No blocking anymore, which makes implementing a turn off the pump if it has been running too long thing easier too.

It's hot as hot gets, so there may be a defect in the reasoning here. No one thinks so. :expressionless:

a7

like this?

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

// Define the I2C LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Define the DS3231 RTC
RTC_DS3231 rtc;

const int hc05_rxPin = 10; // SoftwareSerial rx pin
const int hc05_txPin = 11; // SoftwareSerial tx pin
const int waterPumpPin = 8; // Relay pin
const int soilMoistureSensor = 6; // Soil Moisture pin

// Define the watering times
const int wateringHour1 = 8; // 8 AM
const int wateringMin1 = 25;
const int wateringHour2 = 19; // 8 PM
const int wateringMin2 = 49;

// Initialize software serial for HC-05 Bluetooth module
SoftwareSerial bluetooth(hc05_rxPin, hc05_txPin);

void setup() {
  // Initialize the LCD
  lcd.init();
  lcd.backlight();

  // Initialize the RTC
  rtc.begin();
  
  pinMode(waterPumpPin, OUTPUT); // Set the water pump pin as an output
  digitalWrite(waterPumpPin, HIGH); // Set the water pump as turned off initially

  Serial.begin(9600); // Initialize serial communication with the computer (USB)
  bluetooth.begin(9600); // Initialize serial communication with the HC-05 Bluetooth module
  Serial.println("Bluetooth Serial started at 9600 baud");
}

void loop() {

  // Read the current time
  DateTime now = rtc.now();

  // Read the soil moisture level
  bool soilIsDry = digitalRead(soilMoistureSensor);


  // Display the soil moisture level on the LCD
  lcd.setCursor(0, 0);
  lcd.print("Soil Moisture: ");
  lcd.setCursor(0, 1);
  lcd.print(soilIsDry ? "Low" : "High");


  // Bluetooth function
  if (bluetooth.available()) { 
    char receivedChar = bluetooth.read();
    
    // Turn on the water pump
    if (receivedChar == 'W' && soilIsDry) {
      digitalWrite(waterPumpPin, LOW);
      Serial.println("Water pump turned ON");
    }

    
    // Turn off the water pump
    else if (receivedChar == 'S') {
      digitalWrite(waterPumpPin, HIGH);
      Serial.println("Water pump turned OFF");
    }
  }

  //Scheduled watering function 
  if ((now.hour() == wateringHour1 && now.minute() == wateringMin1 || now.hour() == wateringHour2 && now.minute() == wateringMin2) && soilIsDry) {
    // Turn on the water pump
    digitalWrite(waterPumpPin, LOW);
  }

  if (!soilIsDry) {
    digitalWrite(waterPumpPin, HIGH);
  }

  

  // Wait for a second before the next loop
  delay(1000);
}

it does work for when I turned on the pump using bluetooth, I can turn off the water pump by bluetooth or have it turned off by the soil moisture reading. but when the pump is turned on by the timed section, I can't turn it off by bluetooth.

Does the message that BT is turning it off issue?

    else if (receivedChar == 'S') {
      digitalWrite(waterPumpPin, HIGH);
      Serial.println("Water pump turned OFF");
    }

I am again inconvenienced, but I would add

  if ((now.hour() == wateringHour1 && now.minute() == wateringMin1 || now.hour() == wateringHour2 && now.minute() == wateringMin2) && soilIsDry) {
    // Turn on the water pump
    digitalWrite(waterPumpPin, LOW);
    Aerial.println("time and dry, turn on the pump");
  }

and might expect to see the pump being turned right back on, for the full minute (now) that the time and conditions warrant.

Outside that minute it certainly looks like you should be able turn off the pump with BT.

Do you want to have absolute control with BT, or should wet soil not be watered?

There are only a handful of places where the pump is turnt on or off, print at those points and print the values of the variables that got you there.

I can try your new code and do that, you may get to it sooner.

  if (!soilIsDry) {
    digitalWrite(waterPumpPin, HIGH);
    Serial.println("soil is wet, the pump is now off.");
  }

HTH

a7

Does the message that BT is turning it off issue?

when the pump is turned on by bluetooth and turned off by bluetooth, Yes. but if the pump is turned on by the time and dry, and then I try to turn off the pump using bluetooth, No.

Do you want to have absolute control with BT, or should wet soil not be watered?

I want to have both, what I'm trying to do is being able to turn off the water pump using bluetooth when the water pump is turned on by the time and dry.