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>