Introduction: Plant Care Automation With Arduino and Raspberry Pi Expansion
An Automated System that waters and looks after your plant. features expandability and a wide range of sensors and features.
Supplies
Materials
- 2 Containers
- 1 Pump 5 volt
- 1 Arduino
- 1 Raspberry Pi (for expansion)
- 1 Water level sensor
- 1 Capacitive moisture sensor
- 1 Dht11 temp and humidity sensor
- 1 SPI oled display (128x64)
- 1 Five volt relay
- 1 Power supply board (look up Elegoo) and a 9 volt battery
- 1 Power bank for Pi and/or Arduino
- 1 Breadboard
- Cables
- Tubing and cable ties
Tools
- Double sided tape
- Duct tape and bluetack is useful but not necessary
- Screw driver flathead
- Drill
Software
- Arduino ide
Step 1: What the System Is Built for and What It Does
So this system is built to water and display data about the plant and the enviroment around it. It uses a DHT11 sensor to get temprature and humidity. Uses Capacitive soil moisture Sensor to get the moisture levels of the soil and tell the pump if the plant needs more water. Uses a Water level Sensor to prevent the pump from running dry. All of this infomation is displayed to a 1.3" ips Oled Display. You can expand on this system with a Raspberry Pi and Python adding things such as a camera to monitor the plant from somewhere else, saving the data to a file, sending emails to fill the container, display info on a public website and more. This guide is only covering the Arduino side of things.
Step 2: Setting Up Bread Board Power
- Add power supply to breadboard
- Connect 3.3v to a rail on breadboard
- Connect GND to GND on Breadboard
Step 3: Wiring the Sensors
DHT11:
Connect Signal to A0 on Arduino
Connect negative to GND rail on breadboard
Connect positive to 3.3v rail on breadboard (The 3.3v from the arduino)
Capacitive soil sensor:
Connect GND to GND rail on breadboard
Connect VCC to 3.3v rail (same as the DHT11)
Connect Aout (signal) to A1 on Arduino
Water Level Sensor:
Connect negative to GND rail on breadboard
Connect positive to Pin 7 on Arduino
Connect Signal to A3 on Arduino
Step 4: Pump and Relay
Relay:
Connect negative to GND rail on breadboard
Connect positive to 5v on Arduino
Connect Signal to Pin 4 on Arduino
Need Screwdriver for next two
Unscrew and Connect C (the middle slot) to Power Rail. Make sure to screw it back in
Unscrew and connect the NO slot to the Positive of the pump. I would suggest using an alligator clip or a female to male connector wire for the pump wires.
Don't connect the pump negative to the GND rail on the breadboard until you are ready to test it. Make sure you have water as to not burnout the pump. Alternatively you can use a motor to test the code as they are functionally the same thing. When you are planning on using the Pump make sure the power supply module is on.
Step 5: Oled Display
Oled:
Connect GND to GND on Arduino
Connect VCC to Power rail on Breadboard
Connect CLK (D0) to Pin 13 on Arduino
Connect MOSI (D1) to Pin 11 on Arduino
Connect RES to Pin 8 on Arduino
Connect DC to Pin 9 on Arduino
Connect CS to Pin 10 on Arduino
You can display different images on the Oled besides the included image. Im not covering that here but I'll link some GUIDES for those who want to explore that option. The image that is included is Patrick Bateman, because why not.
Step 6: Birds Nest
If wired up correctly you should end up with this birds nest of wires.
grab two container, 1 for the pump and water level sensor. The other to house all the electronics.
Double sided tape is your Friend. I also Drilled holes in the lids of the containers to allow the sensors and cables out while protecting the electronics. If your worried about the sensors getting water damage you can use a couple layers of clear nail polish to Protect them from the water. Bluetack and duct tape is also a good combo for water proofing the holes in the container.
Step 7: CODE
#include "U8glib.h" // Libraries
#include "dht.h"
#define dht_apin A0 // Define DHT pin
#define sensorPower 7 // Define water level pin
#define sensorPin A2
#define requiredWaterLevel 110 // Minimum water level requirement till the pump stops working
#define minute5_to_seconds 300 // Convert 5 minutes into seconds
long current_seconds = 0; // declare globally
int sensor_moist = A1; // Signal from the capacitive soil moisture sensor
int output_value ; // Value of soil moisture
int pump = 4; // Digital pin where the relay is plugged in
int threshold = 19; // Threshold value to trigger pump
int val = 0; // Value for storing water level
int level = 0;
bool hasWater = false; // Check if the pump has water to start off with
void runPump(int output_value);
void stopRun();
void render();
dht DHT;
U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8); // D0=13, D1=11, CS=10, DC=9, Reset=8 // tells u8.glib what model screen is used
// Image in the oled
const uint8_t Bate_bitmap[] PROGMEM = {
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00,
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x3F, 0xE0, 0x00, 0x00, 0x00,
0xF0, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0xF8, 0x00, 0x00, 0x01, 0xE0, 0x1F, 0xF8, 0x00,
0x00, 0x01, 0xC0, 0x1F, 0xFC, 0x00, 0x00, 0x00, 0x80, 0x3F, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x1F,
0xFC, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0xFC, 0x00, 0x00, 0x01, 0x80, 0x0F, 0xFC, 0x00, 0x00, 0x01,
0x80, 0x0F, 0xFC, 0x00, 0x00, 0x01, 0x80, 0x0F, 0xFC, 0x00, 0x00, 0x01, 0x80, 0x03, 0x7C, 0x00,
0x00, 0x01, 0x00, 0x03, 0x3C, 0x00, 0x00, 0x01, 0x00, 0x23, 0x0C, 0x00, 0x00, 0x01, 0x00, 0x03,
0x0C, 0x00, 0x00, 0x01, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x01, 0x00, 0x63, 0xBC, 0x00, 0x00, 0x01,
0x01, 0xE3, 0xFC, 0x00, 0x00, 0x01, 0x81, 0xE3, 0xFC, 0x00, 0x00, 0x03, 0x81, 0xE3, 0xFC, 0x00,
0x00, 0x03, 0xD1, 0xC3, 0xFC, 0x00, 0x00, 0x00, 0xD0, 0x03, 0xFC, 0x00, 0x0C, 0x00, 0xD0, 0x01,
0xBC, 0x00, 0x1C, 0x00, 0x10, 0x03, 0xF8, 0x00, 0x0C, 0x01, 0x80, 0x03, 0xDF, 0x00, 0x0C, 0x00,
0x10, 0x0F, 0xCF, 0x00, 0x00, 0x00, 0x10, 0x1F, 0xDF, 0x00, 0x00, 0x00, 0x12, 0x1F, 0xFE, 0x00,
0x00, 0x18, 0x12, 0x0F, 0xE0, 0x00, 0x00, 0x18, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x38, 0x00, 0x1F,
0xE0, 0x00, 0x00, 0x38, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x70,
0x00, 0x0F, 0xE0, 0x00, 0x00, 0x70, 0x00, 0x5F, 0xE0, 0x00, 0x00, 0x00, 0x10, 0x1F, 0xC0, 0x00,
0x00, 0x00, 0x10, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x10, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x30, 0x07,
0xE0, 0x00, 0x00, 0x00, 0x70, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x07, 0xE0, 0x00, 0x00, 0x00,
0x90, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00,
0x00, 0x00, 0x03, 0x03, 0xE0, 0x00, 0x11, 0x03, 0xA6, 0xB6, 0x48, 0xF2, 0x3C, 0x05, 0x3D, 0x5B,
0xEC, 0x12,
};
void draw() {
u8g.drawBitmapP( 76, 5, 6, 50, Bate_bitmap); // Put bitmap
//u8g.setFont(u8g_font_unifont); // Select font
u8g.setFont(u8g_font_6x13); // Smaller font
u8g.drawStr(0, 10, "Temp: "); // Put string of display at position X, Y
u8g.drawStr(0, 25, "Hum: ");
u8g.drawStr(0, 40, "Soil: ");
u8g.drawStr(0, 55, "Water: ");
u8g.setPrintPos(44, 10); // Set position
u8g.print(DHT.temperature, 0); // Display temperature from DHT11
u8g.drawStr(60, 10, "c ");
u8g.setPrintPos(44, 25);
u8g.print(DHT.humidity, 0); // Display humidity from DHT11
u8g.drawStr(60, 25, "% ");
u8g.setPrintPos(44, 40);
u8g.print(output_value); // Display soil moisture from sensor
u8g.drawStr(60, 40, "%");
u8g.setPrintPos(44, 55);
u8g.print(level < requiredWaterLevel ? "Fill" : "Good"); // Display water level from sensor
}
void setup() {
Serial.begin(9600);
pinMode(sensorPower, OUTPUT); // Set D7 as an OUTPUT
digitalWrite(sensorPower, LOW); // Set to LOW so no power flows through the sensor
pinMode(sensor_moist, INPUT); // Setup for the soil moisture sensor aka INPUt
pinMode(pump, OUTPUT); // Setup for the pump aka OUTPUT
level = readSensor();
Serial.println("Reading From the Sensor ...");
delay(1000); // 1 second delay
}
void loop() {
current_seconds++; // increment by one every second.
output_value = analogRead(sensor_moist); // Gets the value from the soil moisture sensor
output_value = map(output_value, 550, 0, 0, 100); // This sets the percentage value
Serial.print("Moisture : ");
Serial.print(output_value); // Print the percent of soil moisture - max is 33% if dipped in a cup of water
Serial.println("%");
if ((current_seconds % minute5_to_seconds) == 0 && hasWater) runPump(output_value);
if ((current_seconds % minute5_to_seconds) == 1) stopPump();
level = readSensor(); // Get the reading from the function below and print it
Serial.print("Water level: ");
Serial.println(level);
DHT.read11(dht_apin); // Read apin on DHT11
render();
delay(1000);
}
int readSensor() {
// Water level sensor code
digitalWrite(sensorPower, HIGH); // Turn the sensor ON
delay(10); // Wait 10 milliseconds
val = analogRead(sensorPin); // Read the analog value form sensor
digitalWrite(sensorPower, LOW); // Turn the sensor OFF
hasWater = val > requiredWaterLevel; // Update variable based on water level
if (!hasWater)
Serial.println("Fill me up");
return val; // Send current reading
}
void runPump(int output_value) {
if (output_value < threshold) // If the soil is dry then pump out water for 1 second
{
digitalWrite(pump, HIGH);
Serial.println("pump on for 1 second");
}
else
{
digitalWrite(pump, LOW);
Serial.println("do not turn on pump");
}
}
void stopPump() {
digitalWrite(pump, LOW);
Serial.println("pump off");
}
void render() {
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
}
// dont copy after here
//Copy this Code into your IDE and when your ready to test the whole circuit plug the Pump ground into the GND rail //of the breadboard.
You can change the time it takes for the pump to check if it needs watering by changing the number after
#define minute5_to_seconds
I have it set up for 300 which is 5 minutes. other times include 10 = 600, 15 = 900 so on.
You can also change the level of water you need for the pump to run with by changing the number after
#define requiredWaterLevel
I have it set at 110 for leniency but you can go lower or higher for your use case. This is so the pump doesnt run dry and burn out.
You can change the degree of moisture in the soil required to turn the pump on by changing the number after
int threshold = ;
I would suggest testing your soil sensor in dry soil and in water to get the min and max readings as there are variation between them as they can give wildly differant readings from sensor to sensor. I found dry soil for mine to be about 18 ~ 21 I chose 18 but the type of plant matters as well.
Make sure You Download This DHT lib. For the U8Glib library download it straight of the IDE just look up U8Glib.
Step 8: Final Product
Put the soil sensor into the plant and make sure everything is wired up and that theres water in the pump container.
If all is done properly then you have a working and automated plant care system.
The Raspberry pi is for further expansion at your own leisure.
*Note Be careful when turning on the power supply and battery pack as if you used water proofed the holes like i did you might disconnect the cables when lifting the lid up too far.
Step 9: Let Me Know How You Did
I hope this was useful For some College students in a couple of years. And to everyone else thanks for getting this far.
Step 10: Sites, Guides and Further Learning
Here are the sites I used and drew inspiration from:
Coraline Dunn and her plant watering automation:
https://github.com/carolinedunn/Plant-Watering
https://github.com/carolinedunn/Plant_Management_ESP8266
Her Youtube Vids: Plant watering and Plant watering with wifi capabilities
Brainy Bits and there DHT11 and Oled
https://www.brainy-bits.com/post/how-to-connect-and-use-an-spi-oled-display
His Youtube Vids: DHT11 and Oled and DHT11
Last Minute Engineers and there Tutorials on the Oled and Water Level Sensor
https://lastminuteengineers.com/water-level-sensor-arduino-tutorial/
https://lastminuteengineers.com/oled-display-arduino-tutorial/
Oliver Kraus for His U8Glib library.
https://github.com/olikraus/U8glib_Arduino
*Challenge: Change the image to this as a gif while running everything else.