Plant Water Tracker
By Carmyn Talento
Overview
A plant water tracking device with a screen to display the moisture level on a scale of 0-100 and how many minutes for the demo mode/days for the regular mode since the last watering. Three lights on the top correspond to the plant's need for water similar to a stop light.
This project helps me to keep track of the moisture level in the soil of one of my orchids and lights up to remind me when I need to water them again. The display both gives me a reading of the most current moisture level on a scale of 0-100 and how many days it has been since the last watering. The sensor takes a reading once per hour. Additionally, the tracker has a three light system on the top that lights up a red LED when the moisture level is below 25, a yellow light when the moisture level is between 26 and 50, and a green light when the moisture level is above 50.
A side by side comparison of the Plant Water Tracker with its final (non-demo) code being used with a real plant. The soil moisture sensor is placed in the pot of the plant on the shelf directly below the device. In the left image, the red LED indicator light is on, and the moisture level is noted as zero, meaning the plant desperately needs to be watered. In the right image, the green LED indicator light is on, and the moisture level is reading at 60, meaning the plant has recently been watered and is doing well.
Features
LCD Display Screen - a small screen that displays two lines. The top line reads the moisture level on a scale of 0-100. The bottom line is a time counter, reading minutes for the demo mode or days for the real mode since the last watering.
LED Lights - Three LED lights on the top of the device are used similar to a stop light. The red light glows when the moisture level reading is below 25, the yellow light when the moisture is between 25 and 50, and the green when the moisture is above 50.
Hinged Back Panel - A hinged back panel allows for easy access to the internal electrical components of the device. This is necessary because this allows me to make small changes to the code and update the Arduino based on the needs of the specific plant I am using the device for. Additionally, this allows me to change the battery on the Real Time Clock (RTC) module.
Panel Mount Connector - A panel mount connector is being used for the two wires that are necessary to pertrude from the box. This is a piece of hardware that is designed to have a clean and organized connection of wires from one side of a wall to another. This is a necessary part because there are two wires that need to be external: the sensor and the power.
Functionality
In this video, I show the functionality of the Planet Water Tracker device in its demo mode. I use my hand to grip and cover the moisture sensor so the sensor shows a high reading of 98 and the green LED lights up in the beginning. Prior to the video start, I had allowed for a few minutes to pass by to show that the minute (or day for the real mode) counter was updating. Once I let go of the sensor and a reading takes place, the display updates to show that the moisture level dropped to 0, the green light turned off, and the red light turned on. The minute (or day) counter resets when the moisture level increases significantly between readings.
Process
Seeing how to wire, program, and test the moisture sensor, as this is a component I was unfamiliar with before this project.
Starting to put together all the different aspects of the overall circuitry. This did not end up being the most efficient use of boards, but was a good middle step in figuring out how to get everything to work together.
The parts of the device's box just after being laser cut. The parts are made of 3mm thick blue acrylic. The front panel needed to be recut because the holes for the bolts were too small and slightly off from where they needed to be. I also made the text slightly larger. The top also needed to be recut to make the holes for the LED lights slightly larger to fit more comfortably.
The final pieces of the box put together loosely and held together with tape to make sure all the pieces fit correctly and all electrical components that need mounted onto the box directly get mounted on the correct side with the correct orientation.
Hinges were cut to size and added to the back panel. One small part of the hinges slightly blocks the hole for the panel mount connector, so I made another small cut to the hinges before the final assembly.
The electrical components of the circuitry were soldered and mounted as necessary to the sides of the box before the box was completely glued together.
The device after its final assembly of all the electrical and fabricated components.
An aspect of the process that does not have associated images is the programming progress. This was notably difficult, particularly for the real time clock (RTC) module because it was hard to find good working libraries, and the good libraries did not have a lot of useful examples for how to use them. It took longer, but I did get it to work. Additionally, there was something weird going on with the screen not updating properly, which had me move where the screen updates are placed within the code. The placement of the screen before and after based on code tracing did not (and still doesn't) seem like it would make a difference, but it does. Other than these two things, the rest of the programming went fairly smooth.
Discussion
Overall, I am satisfied with the outcome of my Plant Water Tracker device. Throughout the development process, I confronted and overcame a lot of self doubt, particularly in programming and fabrication. One significant obstacle was the design of the hinged back panel, which presented several complexities such as the hinge obstructing the panel mount connector initially, the need for a mechanism to open it, and ensuring it did not fall into the body of the device.
Reflecting on the project, I acknowledge areas for potential improvement, notably in the final wiring. I wish I had more considerations for the final wiring, possibly using stranded wires instead of solid to allow for more flexibility, as well as choosing to use longer wires for the internal circuitry so it can easily be pulled out if the RTC battery needs changed or a repair is necessary.
Looking ahead, I see a possibility of creating a new version of this device. If I do, I would like to create a more adaptable design capable of accommodating a wider range of plant types. I would do this by “considering a simple interface with three values (low, medium, high) of water needs for different plants” as suggested during the final critique of the project. This would involve having a few preset settings of mapped values of the soil moisture sensor to the moisture levels that trigger the light indicators instead of the current method of having to manually adjust the code and re-upload it to the Arduino.
Furthermore, if I were to make an improved edition of the Plant Water Tracker, I would also like to explore the suggestion of enabling the device to monitor multiple plants simultaneously, as proposed during the critique. Particularly, I liked the idea of having “one LED per plant to make it user friendly where each light maps to a wire.” This would allow for multiple plants to have their own sensors, indicator lights, and day counters at the same time. As a plant person owning well over one plant, I would find this feature incredibly useful.
These proposed improvements really stuck with me, and I am interested in the possibility of incorporating them into a future iteration of the Plant Water Tracker device some day. However, I am proud of the product that I was able to produce in the short period of time allotted and the large learning curve surrounding the software and equipment involved in the making of this device.
Technical Information
Block Diagram
Electrical Schematic
Programming
Real Final Code
/*
Physical Computing Project 2: Plant Water Tracker
Carmyn Talento
A soil moisture sensor is placed in the soil of a plant. Every so often, the soil moisture sensor checks the
moisture level and sends a reading to the LCD screen to show the user how well watered the plant is at that
time (maybe mapped on a 1-100% scale). A green LED will stay on when the plant is sufficiently watered, a yellow
LED will stay on when the plant needs to be watered soon, and a red LED will stay on when the plant DESPERATELY
needs to be watered. The LCD screen will also display how many days have passed since the most recent watering,
which is updated automatically when the moisture level spikes.
Sources:
https://learn.sparkfun.com/tutorials/soil-moisture-sensor-hookup-guide?_gl=1*szrgra*_ga*MTQ2NjE3ODAwNC4xNzA3OTI3NTk1*_ga_T369JS7J9N*MTcwNzkyNzU5NC4xLjAuMTcwNzkyNzU5NC42MC4wLjA.&_ga=2.70253269.439661174.1707927595-1466178004.1707927595#hardware-overview-and-assembly
Also referenced the ds3231 example code from the RTCLib by NeiroN library for the real time clock
Pin mapping:
Arduino pin | role | details
------------------------------
A0 input soil moisture sensor reader
7 output soil moisture sensor power
13 output green LED
12 output yellow LED
8 output red LED
*/
// insert library and set up values for screen display
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C screen(0x27, 16, 2);
int x = 123;
// insert library and set up real time clock
#include <RTClib.h>
DS3231 rtc;
// set up soil moisture sensor values and pins
int soilPin = A0; // soil moisture sensor pin
int soilPower = 7; // soil moisture sensor power pin, can't be powered all the time or risk of corrosion
int days = 0; // starting value for days since watering
bool moistureIncreased = false; // check if the moisture level increased (use to reset day timer)
int oldSoilVal = 0; // previous soil moisture initial value
int newSoilVal = 0; // new soil moisture initial value
// buffer for DateTime.tostr
char buf[20];
// set up system
void setup() {
// turn on serial library
Serial.begin(9600);
// check soil moisture
newSoilVal = readSoil();
// initialize real time clock
Wire.begin();
rtc.begin();
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(__DATE__, __TIME__));
}
// set up pins
pinMode(soilPower, OUTPUT); // soil moisture sensor power
pinMode(13, OUTPUT); // green LED
pinMode(12, OUTPUT); // yellow LED
pinMode(8, OUTPUT); // red LED
// write to serial reader
digitalWrite(soilPower, LOW); //Set to LOW so no power is flowing through the sensor
// LCD screen set up
screen.init();
screen.backlight();
screen.home();
}
// loop through the commands of taking measurement from soil moisture sensor, send signal to LED, update LCD, updating day counter if necessary
void loop() {
DateTime now = rtc.now();
// check if moisture level has increased at the start of each hour
if (now.minute() == 0 && now.second() == 0) { // run this if statement every hour on the hour
oldSoilVal = newSoilVal; // loading previous new value into old value
newSoilVal = readSoil(); // current soil moisture reading
// compare old and new to update day tracker if new is much larger than old soil moisture values
if (newSoilVal > (oldSoilVal + 10)) {
moistureIncreased = true;
} else {
moistureIncreased = false;
}
// update day counter
if (moistureIncreased == false) {
days = days + 1;
}
else {
days = 0;
}
delay(1500);
}
// print soil moisture values and time in serial monitor
Serial.print("Mapped Soil Moisture = ");
Serial.println(readSoil()); // get soil moisture value from the function below and print it
Serial.print("Real Soil Moisture = ");
Serial.println(map(readSoil(), 0, 100, 0, 900));
Serial.print("Time = ");
Serial.println(now.tostr(buf)); // get current time
delay(1000); // wait one second before repeating
// update the LEDs based on soil moisture level
// if the moisture level is high, turn on green LED, turn off any other LEDs
if (newSoilVal >= 50) {
digitalWrite(8, LOW);
digitalWrite(12, LOW);
digitalWrite(13, HIGH);
}
// if the moisture level is low, turn on the yellow LED
else if (newSoilVal >= 25) {
digitalWrite(8, LOW);
digitalWrite(13, LOW);
digitalWrite(12, HIGH);
}
// if the moisture level is REALLY low, turn on the red LED
else {
digitalWrite(13, LOW);
digitalWrite(12, LOW);
digitalWrite(8, HIGH);
}
// clear the LCD screen to update properly
screen.clear();
// write to LCD screen - moisture level and how many days it has been since the last watering
screen.print("Moisture:");
screen.print(newSoilVal);
screen.setCursor(0, 1);
screen.print("Days:"); // change to minutes for demo mode
screen.print(days); // change to minutes for demo mode
delay(1000); // delay for safety, might not be necessary
}
// function used to get the soil moisture content (taken from website for soil moisture sensor Sparkfun website in sources)
int readSoil() {
int soilVal = 0;
digitalWrite(soilPower, HIGH); // turn pin 7 (soil moisture power) "On"
delay(10); // wait 10 milliseconds
soilVal = analogRead(soilPin); // Read the SIG value form sensor
digitalWrite(soilPower, LOW); // turn pin 7 (soil moisture power) "Off"
return map(soilVal, 0, 900, 0, 100); // send current moisture value, map to a percentage scale
Serial.print(soilVal);
Serial.print(map(soilVal, 0, 900, 0, 100));
}
Demo Mode Code
/*
Physical Computing Project 2: Planet Water Tracker - Demo Mode
Carmyn Talento
A soil moisture sensor is placed in the soil of a plant. Every so often, the soil moisture sensor checks the
moisture level and sends a reading to the LCD screen to show the user how well watered the plant is at that
time (maybe mapped on a 1-100% scale). A green LED will stay on when the plant is sufficiently watered, a yellow
LED will stay on when the plant needs to be watered soon, and a red LED will stay on when the plant DESPERATELY
needs to be watered. The LCD screen will also display how many minutes have passed since the most recent watering,
which is updated automatically when the moisture level spikes.
Sources:
https://learn.sparkfun.com/tutorials/soil-moisture-sensor-hookup-guide?_gl=1*szrgra*_ga*MTQ2NjE3ODAwNC4xNzA3OTI3NTk1*_ga_T369JS7J9N*MTcwNzkyNzU5NC4xLjAuMTcwNzkyNzU5NC42MC4wLjA.&_ga=2.70253269.439661174.1707927595-1466178004.1707927595#hardware-overview-and-assembly
Also referenced the ds3231 example code from the RTCLib by NeiroN library for the real time clock
Pin mapping:
Arduino pin | role | details
------------------------------
A0 input soil moisture sensor reader
7 output soil moisture sensor power
13 output green LED
12 output yellow LED
8 output red LED
*/
// insert library and set up values for screen display
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C screen(0x27, 16, 2);
int x = 123;
// insert library and set up real time clock
#include <RTClib.h>
DS3231 rtc;
// set up soil moisture sensor values and pins
int soilPin = A0; // soil moisture sensor pin
int soilPower = 7; // soil moisture sensor power pin, can't be powered all the time or risk of corrosion
int minutes = 0; // starting value for minutes since watering
bool moistureIncreased = false; // check if the moisture level increased (use to reset minute timer)
int oldSoilVal = 0; // previous soil moisture initial value
int newSoilVal = 0; // new soil moisture initial value
// buffer for DateTime.tostr
char buf[20];
// set up system
void setup() {
// turn on serial library
Serial.begin(9600);
// check soil moisture
newSoilVal = readSoil();
// initialize real time clock
Wire.begin();
rtc.begin();
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(__DATE__, __TIME__));
}
// set up pins
pinMode(soilPower, OUTPUT); // soil moisture sensor power
pinMode(13, OUTPUT); // green LED
pinMode(12, OUTPUT); // yellow LED
pinMode(8, OUTPUT); // red LED
// write to serial reader
digitalWrite(soilPower, LOW); //Set to LOW so no power is flowing through the sensor
// LCD screen set up
screen.init();
screen.backlight();
screen.home();
}
// loop through the commands of taking measurement from soil moisture sensor, send signal to LED, update LCD, updating minute counter if necessary
void loop() {
DateTime now = rtc.now();
// check if moisture level has increased at the start of each hour
if (now.second() == 0) { // run this if statement every minute on the minute
oldSoilVal = newSoilVal; // loading previous new value into old value
newSoilVal = readSoil(); // current soil moisture reading
// compare old and new to update minute tracker if new is much larger than old soil moisture values
if (newSoilVal > (oldSoilVal + 10)) {
moistureIncreased = true;
}
else {
moistureIncreased = false;
}
// update minute counter
if (moistureIncreased == false) {
minutes = minutes + 1;
}
else {
minutes = 0;
}
delay(100);
}
// print soil moisture values and time in serial monitor
Serial.print("Mapped Soil Moisture = ");
Serial.println(readSoil()); // get soil moisture value from the function below and print it
Serial.print("Real Soil Moisture = ");
Serial.println(map(readSoil(), 0, 100, 0, 900));
Serial.print("Time = ");
Serial.println(now.tostr(buf)); // get current time
delay(1000); // wait one second before repeating
// update the LEDs based on soil moisture level
// if the moisture level is high, turn on green LED, turn off any other LEDs
if (newSoilVal >= 50) {
digitalWrite(8, LOW);
digitalWrite(12, LOW);
digitalWrite(13, HIGH);
}
// if the moisture level is low, turn on the yellow LED
else if (newSoilVal >= 25) {
digitalWrite(8, LOW);
digitalWrite(13, LOW);
digitalWrite(12, HIGH);
}
// if the moisture level is REALLY low, turn on the red LED
else {
digitalWrite(13, LOW);
digitalWrite(12, LOW);
digitalWrite(8, HIGH);
}
// clear the LCD screen to update properly
screen.clear();
// write to LCD screen - moisture level and how many minutes it has been since the last watering
screen.print("Moisture:");
screen.print(newSoilVal);
screen.setCursor(0, 1);
screen.print("Minutes:");
screen.print(minutes);
delay(1000); // delay for safety, might not be necessary
}
// function used to get the soil moisture content (taken from website for soil moisture sensor Sparkfun website in sources)
int readSoil() {
int soilVal = 0;
digitalWrite(soilPower, HIGH); // turn pin 7 (soil moisture power) "On"
delay(10); // wait 10 milliseconds
soilVal = analogRead(soilPin); // Read the SIG value form sensor
digitalWrite(soilPower, LOW); // turn pin 7 (soil moisture power) "Off"
return map(soilVal, 0, 900, 0, 100); // send current moisture value, map to a percentage scale
Serial.print(soilVal);
Serial.print(map(soilVal, 0, 900, 0, 100));
}