Introduction: Plant Waterer

Like me, always forgetting to water your plants and always end up with a pile of brown leaves? salvation is here! this device waters your plants once the soil gets too dry.

Step 1: Required Components

- Arduino Nano

- 1x transistor BC547B

- 1x relay 5V

- 1x resistor 1,5 kΩ

- 1x diode 1N4148

- Humistor 1x

- resistor 10K 5x

- Momentary push button 4x

- 3x Screw terminal

- 300x400x3mm triplex for the casing

- 12 M3 bolts

- 12 M3 nuts

- 12V diaphragm pump

- 12V power supply

- LM7305 regulator

- Prototyping board
- Some kind of hinge
- 16x2 i2c LCD screen

Step 2: Casing

I used a laser cutter to cut my casing. I've used 3mm plywood as a material.

As an image i've supplied the rough vector drawing.

Sizes are: 180x120x40mm

Step 3: Assemble PCB

Use prototyping board or a simple breadboard. Up to your preference.

Step 4: Upload This Code and You're All Set!

#include <wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
<wire.h>LiquidCrystal_I2C lcd(0x3F, 2, 16);</wire.h>
<wire.h>enum ScreenPosition {
  HUMIDITY,
  DURATION
};
//digital inputs
const int MODE_SET = 2;const int MODE_DOWN = 3;
const int MODE_UP = 4;
const int MODE_SELECT = 5;//relay location
const int SWITCH = 7;//save the desired duration of 1 spraying cycle. Make 2, for the sake of the settings menu
int desired_duration;
int setduration;
int sethum;
int desired_humidity;//booleans to keep track of the menu positon
bool setmode = false;
bool set_humidity = false;
bool set_duration = false;//enum keeps track of what is being set: humidity or spray-duration
ScreenPosition screen = HUMIDITY;//keep 20 seconds between each spraying cycle
long lastSpray;
long interval = 20000;void setup()
{
  //duration and humidity preferences are set in the non-volatile memory to prevent loss after power loss
  EEPROM.get(0, desired_duration);
  EEPROM.get(1, desired_humidity);
  sethum = desired_humidity;
  setduration = desired_duration;  //lets keep at least 20 seconds between switching on and spraying for the first time
  lastSpray = millis();  pinMode(SWITCH, OUTPUT);  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.home();
  printMovingText("Welkom", lcd);
  delay(2000);
  lcd.clear();}void loop()
{
  /*
   * The below code is a lot of repetition. 
   * first of all, the setmode field checks if the user wants to set a field. If setmode is set to true,
   * the user can either go back by pressing the setmode button again, or proceed to setting the duration
   * of spraying, or setting the desired humidity.
   */
  if (isDown(MODE_SET)) {
    delay(1000);
    if (!setmode)
    {
      delay(1000);
      if (isDown(MODE_SET))
      {
        lcd.clear();
        printMovingText("Instellingsmenu starten... een ogenblik geduld", lcd);
        delay(1000);
        lcd.clear();
        setmode = true;
      }
    }    else
    {
      delay(1000);
      if (isDown(MODE_SET))
      {
        lcd.clear();
        setmode = false;
      }
    }
  }  if (setmode && set_duration) {
    printLcd("Aantal seconden: " + String(setduration), lcd);
    if (isDown(MODE_DOWN))
    {
      delay(500);
      if (isDown(MODE_DOWN))
      {
        if (setduration > 0) {
          setduration--;
        }
        //cant be lower than 0, set to 100
        else {
          setduration = 100;
        }
        lcd.clear();      }
    }    else if (isDown(MODE_UP))
    {
      delay(500);
      if (isDown(MODE_UP))
      {
        if (setduration <= 60) {
          setduration++;
        }
        else {
          setduration = 0;
        }
        lcd.clear();      }
    }    else if (isDown(MODE_SELECT))
    {
      /*
       * press button for 5 seconds to make changes definitive. 
       * release earlier to keep the old settings
       */
      lcd.clear();
      printMovingText("Opslaan... Houd ingedrukt om door te gaan...", lcd);
      lcd.clear();
      //nice little countdown
      for (int i = 5; i > 0; i--)
      {
        printLcd(String(i) + " sec resterend", lcd);
        delay(1000);
      }
      if (isDown(MODE_SELECT))
      {
        //save changes to memory
        desired_duration = setduration;
        EEPROM.put(0, desired_duration);
        setmode = false;
      }
      lcd.clear();
    }  }  //below is mostly equal to the logic of the above (setting the duration)
  else if (setmode && set_humidity) {
    printLcd("Gewenste verzadiging: " + String(sethum) + "%", lcd);
    if (isDown(MODE_DOWN))
    {
      delay(500);
      if (isDown(MODE_DOWN))
      {
        if (sethum > 0) {
          sethum--;
        }
        else {
          sethum = 100;
        }
        lcd.clear();      }
    }    else if (isDown(MODE_UP))
    {
      delay(500);
      if (isDown(MODE_UP))
      {
        if (sethum < 100) {
          sethum++;
        }
        else {
          sethum = 0;
        }
        lcd.clear();
      }
    }    else if (isDown(MODE_SELECT))
    {
      lcd.clear();
      printMovingText("Opslaan... Houd ingedrukt om door te gaan...", lcd);
      lcd.clear();      for (int i = 5; i > 0; i--)
      {
        printLcd(String(i) + " sec resterend", lcd);
        delay(1000);
      }      if (isDown(MODE_SELECT))
      {
        desired_humidity = sethum;
        EEPROM.put(1, desired_humidity);
        setmode = false;
      }      lcd.clear();
    }
  }//settings menu
  else if (setmode) {
    if (screen == HUMIDITY) {
      printLcd("Verzadigingspercentage", lcd);
      if (isDown(MODE_DOWN)) {
        delay(1000);
        if (isDown(MODE_DOWN)) {
          screen = DURATION;
          lcd.clear();
        }
      }      if (isDown(MODE_SELECT)) {
        delay(1000);
        if (isDown(MODE_SELECT))
        {
          set_humidity = true;
          printMovingText("Veranderen van modus... een ogenblik geduld", lcd);
          delay(1500);
        }
      }
    }
    else if (screen == DURATION) {
      printLcd("Duur bevochtiging", lcd);
      if (isDown(MODE_UP)) {
        delay(1000);
        if (isDown(MODE_UP)) {
          screen = HUMIDITY;
          lcd.clear();
        }
      }      if (isDown(MODE_SELECT)) {
        delay(1000);
        if (isDown(MODE_SELECT))
        {
          set_duration = true;
          printMovingText("Veranderen van modus... een ogenblik geduld", lcd);
          delay(1500);
        }
      }    }  }  else {
    setmode = false;
    set_humidity = false;
    set_duration = false;    int saturation = int(100.0 / 1024.0 * ((double)analogRead(0)));    printLcd("Verzadiging: " + String(saturation) + "%", lcd);
    printLcd("Instelling: " + String(desired_humidity) + "%", lcd, 1);    if (saturation < desired_humidity)
    {
      Spray();
    }
  }}void Spray(){
  //keep an interval between each spray to prevent drowning of plants
  if(millis()-lastSpray > interval){
    digitalWrite(SWITCH, HIGH);
    lcd.clear();
    printMovingText("Sproeien...", lcd);
    delay(desired_duration*1000);
    lcd.clear();
    digitalWrite(SWITCH, LOW);
    lastSpray = millis();
  }
}boolean isDown(int button) {
  return digitalRead(button) == 0;
}/*
 * Because the lcd i used didn't really work well with the i2c library
 * I had to write some code of myself.
 */void printLcd(String input, LiquidCrystal_I2C display) {
  int row = 0;
  for (int i = 0; i < input.length(); i++) {
    if (i == 16)
    {
      row = 1;
    }    int cursorloc = i;
    if (i > 15)
    {
      cursorloc -= 16;
    }    display.setCursor(cursorloc, row);    display.print(input[i]);
    if (i == 32)
    {
      break;
    }
  }
}void printLcd(String input, LiquidCrystal_I2C display, int row) {
  for (int i = 0; i < input.length(); i++) {
    if (i == 16)
    {
      break;
    }    display.setCursor(i, row);    display.print(input[i]);
  }
}//this method prints text like it's being written, interval of 50ms between each char being
//written.
void printMovingText(String input, LiquidCrystal_I2C display) {
  display.clear();  int selectedrow = 0;
  int counter = 0;  for (int i = 0; i < input.length(); i++) {
    delay(50);
    if (i % 16 == 0 && i != 0) {
      counter = 0;
      if (selectedrow == 0) {
        selectedrow = 1;
      }
      else {
        selectedrow = 0;
        display.clear();
      }    }
    display.setCursor(counter, selectedrow);
    display.print(input[i]);
    counter++;
  }
}</wire.h>