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>


