Planter for Beginners
Created by Ashley Heckman (agh93) & Maria Boza (mib57)
May 12, 2023
This final project was created by Maria Boza (mib57) & Ashley Heckman (agh93) for Cornell’s ECE 5725 Spring 2023 class. We implemented a planter that has many capabilities. The brains of our project is the Raspberry Pi 4 (RPi), which has been used all semester to work on our labs. We used four sensor readings: soil moisture, humidity, temperature, and light. These were received with a plant monitor and photoresistor sensor. We also implemented a camera to send a live feed of the plant to a website. We used python to code all of the sensor readings, the camera, and the GUI (which was displayed on the piTFT). This project is geared towards new plant owners who do not know much about plants and would like help. It is also geared towards people who cannot water their own plants.
We decided to make a product that will help plant growers have the ability to leave their plants
unattended but still have them get watered. It also supports new plant growers in understanding how
to water their new plants through the recommended watering cycles. Our system utilizes a water
reservoir and a planter, along with the RPi, sensors, and water pump. The water reservoir is
connected to one side of the water pump, and tubing leading to the planter is connected to the
other side of the water pump. We attached tubing around the edge of the planter, poking holes
facing towards the plant in order to water it.
We decided to create three watering modes: manual, moisture, and interval. Manual mode requires
that the user presses start and stop to turn the water on and off. Moisture mode will automatically
water the plant when the soil moisture drops below a set value. Interval mode will automatically
water the plant at the specified interval.
The RPi is the brains of our embedded system, and it controls the watering of the plant, reads
the sensor values, and displays/controls the GUI. We used moisture, humidity, temperature, and
light because that is the basis of what a plant needs to survive. We created a GUI that shows the
user current sensor readings, the last time the plant was watered, and the current watering schedule.
It also allows the user to change the watering schedule. We created another program that can run at
the same time as this that displays a live feed of the plant. As we started the project, we planted
the seeds in a 3D-printed planter. This was the best way to do it because it allowed us to create a
pot that precisely fits our sensors, the tubing, and our water pump. All components are described in
more detail below.
Plant Monitor
We used the Monk Makes plant monitor to measure temperature, humidity, and soil moisture. The sensor
communicates with the RPi through a serial UART connection. It has five pins: GND, 3V, TX_OUT, RX_IN,
and an analog pin to be used for just reading soil moisture. Since we wanted all of the measurements
from this sensor, we ignored the analog pin. We hooked GND up to our common ground from the RPi, 3V
up to 3.3V from the RPi, TX_OUT up to RX on the RPi, and RX_IN up to TX on the RPi. A diagram of these
connections is shown below in Drawing 2. To program this sensor, we simply went to the github page
listed on the instruction manual and copied over their functions for reading the different values.
When we wanted to read the values, we called the functions.
Light Sensor
The sunlight sensor consists of a photoresistor and a capacitor. We connected one side of the
photoresistor to 3.3V and the other side to the positive end of the capacitor. The negative end
of the capacitor was connected to ground. We then connected GPIO 16 to the junction of the
photoresistor and capacitor. We measured the amount of light by setting the GPIO as an output and
outputting low, then immediately setting it as an input and counting how long it took for the
signal to switch from low to high. The faster the signal switched, the more light in the area.
We wanted a higher number to correspond to more light, so we found the maximum time that it took
for the signal to switch, then subtracted the measured time from that value, and displayed that.
A schematic of this circuit is shown in Drawing 3.
Water Pump
We connected one end of our water pump to our water reservoir and the other to the tubing attached
to the border of our planter. The pump was controlled with a motor driver and a PWM signal. Through
trial and error, we found a frequency and duty cycle that watered the plant well. The water pump has
two inputs: power and ground. We connected power to an output on the motor controller, and ground to
our common ground. The water pump is the only external electronic that requires a power supply to work
and function as needed. It runs at 12V, and the Rpi cannot supply that much voltage. A drawing of the
water pump circuit is shown in Drawing 4.
Camera
We used a RPi Camera to display a livestream of our plant. To do this, we simply copied the web
streaming code from the PiCamera documentation. We edited the HTML website, but the underlying
code is all the same. To get this to work, we had to open the RPi configuration settings and turn
on camera support. The Rpi itself hosted this website, located at 'RPi IP Address':8000/index.html.
To find the IP address, we typed ‘ifconfig -a’ into the command line. The website is only live
while we’re running our program, so we’ve included a picture of our website.
GUI
We used PyGame to create the GUI. The GUI has 11 different screens that it can display. The first
screen is the homescreen, which displays the current sensor readings, the time the plant was last
watered, and the current watering schedule. If the system is in manual watering mode, this screen
will allow the user to start and stop the water. The user can also edit the schedule from this
screen.
If the user decides to edit the schedule, the GUI transitions to screen 1. This screen displays
all three watering modes, and gives a short description of each mode. If the user selects a mode,
it will display in blue instead of white, indicating that it’s been selected. Once the user selects
a mode and clicks next, the GUI transitions to the next screen. If the user selected manual or
interval mode, this is screen 2. If the user selected moisture mode, this is screen 3.
The second screen repeats the short description of the mode selected, then prompts the user to input
their desired value (if applicable), then set the schedule. If the user selected manual mode, there is
nothing to input. If the user selected moisture mode, they can input moisture levels from 1% to 100%.
If the user selected interval mode, they can input a wide range of intervals ranging from seconds to
days. If the user tries to input an invalid interval (for example, 10 seconds every 5 seconds), the
GUI doesn’t allow the user to proceed to the next screen. Once the user selects set, the GUI returns
to the homescreen.
The third screen is part of the moisture sensing mode, and prompts the user to enter their plant type.
There are four categories: flowers, fruits, trees/shrubs, and manual moisture value. If the user
selects ‘my own value,’ the GUI will transition to screen 2. Otherwise, if the user selects a plant
type, the GUI will transition to screen 4 for flowers, 6 for fruits, and 7 for trees. Screens 4 and
5 display the list of flowers. Screen 6 displays the list of fruits. Screens 7, 8, and 9 display the
list of trees/shrubs. The last screen for all plant types also has an ‘other’ option, which averages
the recommended moisture level for all plants in that category, then recommends that value. If the
user selects a specific plant from the list then clicks next, the GUI transitions to screen 10. If
the user selects other, the GUI advances to screen 11.
Screen 10 displays the moisture mode, the name of the plant selected, and the recommended soil
moisture value for that plant. From this screen, the user can either click set (returning to the
homescreen and updating the schedule), edit (going to screen 2 but starting with the recommended
value instead of the previous value), back, or cancel. Screen 11 displays the moisture mode, plant
type selected, and the recommended value for that plant type. The user has the same options as
screen 10 from this screen.
The GUI is controlled by a big while code_run loop. We store a global variable keeping track of the
screens, and we call the function that displays the corresponding screen in each iteration. We check
for button presses in every iteration of this loop. If we’re on the homescreen, the GUI also reads in
new sensor values in every iteration. If the GUI is on the homescreen and moisture mode is selected,
it checks if the plant is currently being watered. If it is being watered and the soil moisture is at
or equal to the selected value, it turns the water off. If it’s not being watered and the soil
moisture is below the selected value, it turns the water on. We do this instead of a while measured
moisture < desired moisture loop because it allows us to still respond to button presses. If we’re
in interval mode and on the homescreen, the GUI will check if the plant is currently being watered.
If it is, it checks if the current time is greater than or equal to the watering start time plus how
long the water needs to run, and turns the water off if this is true. If it isn’t being watered, the
GUI will check if the current time is greater than or equal to the time the water ended plus the time
between waterings, and if this is true, it will start the water.
We decided to only allow the plant to be watered when the GUI is on the homescreen. We felt that if
the user is changing the schedule, they wouldn’t want the plant to be watered during that time, so we
turn the water off when the user selects edit schedule. The GUI calculates how long to water in
internal mode by converting all times to seconds. From there, knowing that the user inputted
‘a units0 every b units1,’ we can calculate how long to wait between waterings. The water time is
simply a (in seconds), and the time between is b - a (also in seconds). Almost every screen has a
back or cancel button. A picture of the GUI homescreen is shown below.
Drawing 1 shows a high level overview of all of the hardware components of our project. The
diagram comprises the RPi/piTFT, which are placed one on top of the other and connected to the
main breadboard with the Pi Cobbler (labeled extender). This connector allows other peripherals
to link to pins that the piTFT does not use. A camera is connected to the RPi directly through a
camera port on the device. A photoresistor is connected to a capacitor and a GPIO pin on the RPi.
The motor driver is connected to a PWM pin on the RPi; the water pump’s VCC and ground connectors,
and an external power supply of 12V. One end of the water pump is connected to the reservoir (input)
and the other to the plant (output). The last thing is the plant monitor sensor. This sensor is
connected to the positive(+) and negative/ground (-) sides of the breadboard, and RX and TX pins
on the RPi. Drawings 2, 3, and 4 give a more in-depth view of the individual component hookups.
Testing was done in sections. We started by creating the 3D-printed pot; we went through about
four different iterations of the flower pot. This was because we wanted to make sure that
everything fit perfectly together. The first thing that was created was the homescreen of the
GUI. From there, we tested the water pump alongside the sensors and the camera. Once all parts
worked, we integrated them and made our final demo. The following is our testing of each of the
significant components of our project.
Plant Monitor
We worked with two different moisture sensors throughout this project. The first sensor worked,
but could only determine if the moisture level exceeded a certain threshold, which could be
changed by spinning a screw on the sensor. Because of this, we decided to try a new sensor to
measure the moisture level, and we ordered the plant monitor sensor.
The plant monitor can sense soil moisture, humidity, and temperature. This sensor was better to
use because it gave us real values and not just high/low. It also didn’t take up any GPIO pins,
as all communication with the RPi was through a serial UART connection. This sensor also had a
lot more documentation than our original sensor, making it much easier to work with.
We tested this component by holding the top part (which measures temperature and humidity), and
watching both values increase. When we released the sensor, the values both returned to around
where they were before. We repeated this with the bottom part (the prong that gets inserted into
the soil), and watched as the moisture level rose when we held it and fell when we released it.
Light Sensor
We also worked with two different light sensors. The first sensor was a board with a photoresistor,
resistor, and three pins: VCC, ground, and signal. We couldn’t find any documentation for this
sensor, and when we tried to code it and hook it up, it only read 0. We decided to change to a
regular photoresistor and capacitor instead. We tested this by holding our hand over the
photoresistor and watching the measured light level drop, then holding a flashlight up to the
photoresistor and watching the measured light level rise. While testing this sensor, we noticed
that the values were never exactly the same, so we decided to round our light value to the nearest
50. The value still changes some, but it is much more stable with this modification.
Water Pump
We obtained two pumps before starting this project. The first pump seemed much more complex,
especially since we couldn’t find any documentation for it. The second pump had more
documentation and seemed simpler, so we decided to use that pump. This pump is very similar
to a motor. Given this, we used a motor driver with a PWM signal to control the pump. To test
that the pump worked, we hooked the power and ground wires directly to our power supply, and
watched the water pump. We found that the pump only worked when placed in a specific orientation,
and mode note of this for future reference.
One interesting thing we found when implementing the water pump control was that GPIO 6 had to be
specified as an output and set to low for the pump to work. We found this surprising, as we had
power hooked up to GPIO 5 and ground hooked up to our common ground. We didn’t have anything
connected to AOUT2, so we were surprised that the AIN2 input mattered.
Camera
We tested that the camera worked by using the preview command. We learned that the module could
do some cool things to the image, such as putting a ‘filter’ on it or adding text to what the
camera sees. In the end, we didn’t use these features, but we enjoyed playing with them during
development. We tested the camera by running the live stream code and observing the website. We
quickly found that the website was indeed displaying what the camera saw, so we concluded that
the camera was working.
GUI
We tested the GUI by observing what happens when buttons are pressed. For buttons that don’t
switch screens (such as turning the water on or off), we began testing by printing out a statement
acknowledging that a certain button had been pressed. As we tested and integrated the other sensors,
we moved away from testing with print statements and towards observing what happens with the
system. We tried to (and think we succeeded with) pressing all buttons on all screens to test the
GUI, and consequently, the system as a whole.
Our project is fully functional and works as intended. Our user interface displays all of the
information that the user needs: soil moisture, humidity, air temperature, amount of light, the
last time the plant was watered, and the current watering cycle. It also gives the user a lot of
flexibility in how they want to water their plants. The soil moisture level increases as the plant
is watered (as expected), and the temperature and humidity increase if we hold those sensors
(also as expected). The light decreases if we put our hand over the sensor, and increases if we
hold a flashlight up to it. Our camera feature is also fully operational; the user can see a live
feed of their plant as long as they’re on the same network as the RPi.
The user can choose from three watering schedules: manual, moisture, and interval. The manual
option allows the user to turn the water pump on and off. The moisture mode will automatically
water the plant when the soil moisture drops below the set level. The user can input their own value
for this, or they can use our recommended values. The user selects a recommended value by picking
their plant type: flower, fruit, or tree/shrub. If their plant is in the list, they can simply select
their plant. Otherwise, they can select other and get a recommended value for their plant type as a
whole. The interval option allows for a timed approach to watering the plant. For example, the user
can set the system to water for 10 seconds every 3 days.
All in all, we created a system for both beginners and for people who can’t water their own plants.
In the end, everything performed as planned and we met all goals outlined in the project objectives.
Luckily, we didn’t run into anything that we couldn’t get working.
Future Work
Although our time in class has ended, our work on this project has not. In the future, we plan on
putting our system in a display case. This will require some modification, as we cannot have water
or motors in our display. If we had more time in this class, we would have liked to add more features
to our system.
One idea was to take pictures of our plant at a set interval, then display a time lapse on our
website. It would be nice if the camera was in the same position relative to the plant for all
pictures, so we’d also like to build a stand for the camera. Another idea was to allow the user to
edit the watering schedule through the website. We also would have liked to store previous sensor
measurements and display them in graphs on the website. Our last idea was to have our system search
the internet for recommended moisture values or watering intervals, and use that to recommend values
to the user, rather than storing specific plants in an array.
agh93@cornell.edu
mib57@cornell.edu
# Ashley Heckman (agh93) & Maria Boza (mib57) # Wednesday Lab, Team 6 # ECE 5725 Final Project # water.py import time import pygame import os from pygame.locals import* import RPi.GPIO as GPIO from plant_monitor import PlantMonitor ######################################################################################################### # TFT/Monitor Display Stuff ######################################################################################################### # Display on the piTFT (comment to display on monitor) os.putenv('SDL_VIDEODRIVER', 'fbcon') os.putenv('SDL_FBDEV', '/dev/fb0') # TFT is fb1 w monitor connected, fb0 without monitor connected os.putenv('SDL_MOUSEDRV', 'TSLIB') os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen') ######################################################################################################### # Basic Pygame Stuff ######################################################################################################### pygame.init() # Don't show mouse cursor if we're displaying on piTFT (comment if displaying on monitor) pygame.mouse.set_visible(False) black = 0 , 0 , 0 white = 255, 255, 255 red = 255, 0 , 0 green = 0 , 255, 0 blue = 0 , 0 , 255 sel = 0 , 213, 255 nsel = 70 , 70 , 70 size = width, height = 320, 240 body = pygame.font.Font(None, 20) header = pygame.font.Font(None, 25) plant = pygame.font.Font(None, 17) screen = pygame.display.set_mode(size) screen.fill(black) screen_num = 0 ######################################################################################################### # Water Pump Basic Control ######################################################################################################### # Water pump power output, don't want it to pump to start with GPIO.setmode(GPIO.BCM) GPIO.setup(5,GPIO.OUT) GPIO.output(5, GPIO.LOW) GPIO.setup(6,GPIO.OUT) GPIO.output(6, GPIO.LOW) # PWM Instance GPIO.setup(26, GPIO.OUT) pwm26 = GPIO.PWM(26, 100) pwm26.start(20) # Keep track of if we're currently watering the plant currently_watering = False # Keep track of the time that we last started and stopped the water last_water_start = time.time() last_water_end = time.time() # Keep track of if we've watered the plant yet watered = False # Start water function def start_water(): # Send power to the motor GPIO.output(5, GPIO.HIGH) # Update variable to reflect we're currently watering global currently_watering currently_watering = True # Update the last water start time global last_water_start last_water_start = time.time() # Update to reflect that plant has been watered at least once global watered watered = True # Print that we've started water along with the time print("Water Started: " + str(time.localtime(last_water_start)[1]) + "/" + str(time.localtime(last_water_start)[2]) + " @ " + str(time.localtime(last_water_start)[3]) + ":" + str(time.localtime(last_water_start)[4]) + ":" + str(time.localtime(last_water_start)[5])) # Stop water function def stop_water(): # Send power to the motor GPIO.output(5, GPIO.LOW) # Update variable to reflect we're not currently watering global currently_watering currently_watering = False # Update the last water stop time global last_water_end last_water_end = time.time() # Print that we've stopped water along with the time print("Water Stopped: " + str(time.localtime(last_water_end)[1]) + "/" + str(time.localtime(last_water_end)[2]) + " @ " + str(time.localtime(last_water_end)[3]) + ":" + str(time.localtime(last_water_end)[4]) + ":" + str(time.localtime(last_water_end)[5])) ######################################################################################################### # Quit Button ######################################################################################################### GPIO.setup(27, GPIO.IN, pull_up_down = GPIO.PUD_UP) code_run = True # Quit the program and stop the water pump def GPIO27_callback(channel): global code_run code_run = False GPIO.add_event_detect(27, GPIO.FALLING, callback = GPIO27_callback, bouncetime = 300) ######################################################################################################### # Watering Modes ######################################################################################################### schedule_type = ["Manual", "Moisture Sensor", "Intervals"] schedule_selected = 0 desired_moisture = 0 ######################################################################################################### # Setup the soil moisture/temperature/humidity sensor ######################################################################################################### moisture = 0 temp = 0 humidity = 0 pm = PlantMonitor() pm.led_off() ######################################################################################################### # Setup the light sensor ######################################################################################################### light = 0 def measure_light(): count = 0 # setup pin as output and direction low value GPIO.setup(16, GPIO.OUT) GPIO.output(16, GPIO.LOW) time.sleep(0.1) # setup pin as input and wait for low value GPIO.setup(16, GPIO.IN) # This takes about 1 millisecond per loop cycle while (GPIO.input(16) == GPIO.LOW): count += 1 # Cap count at 3000 (looks like that's the cap anyway through experimentation) if count > 3000: count = 3000 # Invert (so high value corresponds to more light) count = 3000 - count # Round count to nearest 50 count = round(count/50)*50 return count ######################################################################################################### # GUI Homescreen ######################################################################################################### # Home screen buttons home_buttons = {'Start/Stop Water':(int(width/4), 220), 'Edit Schedule':(int(3*width/4), 220)} home_buttons_rect = {} # Display the GUI homepage (screen 0) def display_home(): # Erase everything on the screen screen.fill(black) # Display moisture level moisture_text = "Soil Moisture: " + str(moisture) + "%" moisture_text_surface = body.render(moisture_text, True, white) moisture_rect = moisture_text_surface.get_rect(center = (int(width/2), 15)) screen.blit(moisture_text_surface, moisture_rect) # Display temperature temp_text = "Air Temperature: " + str(temp) + "° F" temp_text_surface = body.render(temp_text, True, white) temp_rect = temp_text_surface.get_rect(center = (int(width/2), 40)) screen.blit(temp_text_surface, temp_rect) # Display humidity humidity_text = "Humidity: " + str(humidity) + "%" humidity_text_surface = body.render(humidity_text, True, white) humidity_rect = humidity_text_surface.get_rect(center = (int(width/2), 65)) screen.blit(humidity_text_surface, humidity_rect) # Display light light_text = "Light: " + str(light) light_text_surface = body.render(light_text, True, white) light_rect = light_text_surface.get_rect(center = (int(width/2), 90)) screen.blit(light_text_surface, light_rect) # Display time the plant was last watered header water_header_text = "Last Watered" water_header_text_surface = header.render(water_header_text, True, white) water_header_rect = water_header_text_surface.get_rect(center = (int(width/2), 120)) screen.blit(water_header_text_surface, water_header_rect) # If we haven't watered the plant yet, display N/A for time plant was last watered if not watered: water_text = "N/A" water_text_surface = body.render(water_text, True, white) water_rect = water_text_surface.get_rect(center = (int(width/2), 140)) screen.blit(water_text_surface, water_rect) # Display time the plant was last watered elif not currently_watering: last_water_start_text = str(time.localtime(last_water_start)[1]) + "/" + str(time.localtime(last_water_start)[2]) + " " + str((time.localtime(last_water_start)[3], time.localtime(last_water_start)[3] - 12)[time.localtime(last_water_start)[3] > 12]) + (":", ":0")[time.localtime(last_water_start)[4] < 10] + str(time.localtime(last_water_start)[4]) + (".", ".0")[time.localtime(last_water_start)[5] < 10] + str(time.localtime(last_water_start)[5]) + (" am", " pm")[time.localtime(last_water_start)[3] > 11] last_water_end_text = str(time.localtime(last_water_end)[1]) + "/" + str(time.localtime(last_water_end)[2]) + " " + str((time.localtime(last_water_end)[3], time.localtime(last_water_end)[3] - 12)[time.localtime(last_water_end)[3] > 12]) + (":", ":0")[time.localtime(last_water_end)[4] < 10] + str(time.localtime(last_water_end)[4]) + (".", ":0")[time.localtime(last_water_end)[5] < 10] + str(time.localtime(last_water_end)[5]) + (" am", " pm")[time.localtime(last_water_end)[3] > 11] water_text = last_water_start_text + " - " + last_water_end_text water_text_surface = body.render(water_text, True, white) water_rect = water_text_surface.get_rect(center = (int(width/2), 140)) screen.blit(water_text_surface, water_rect) # If we're currently watering, it doesn't make sense to display times, so just display that we're currently watering else: water_text = "Currently Watering" water_text_surface = body.render(water_text, True, white) water_rect = water_text_surface.get_rect(center = (int(width/2), 140)) screen.blit(water_text_surface, water_rect) # Display the watering schedule header schedule_header_text = "Current Watering Schedule" schedule_header_text_surface = header.render(schedule_header_text, True, white) schedule_header_rect = schedule_header_text_surface.get_rect(center = (int(width/2), 170)) screen.blit(schedule_header_text_surface, schedule_header_rect) # Display the current watering schedule schedule_text = (("Water for " + str(interval_w_time) + " " + str(interval_units[interval_w_time_selected]) + " every " + str(interval_b_time) + " " + str(interval_units[interval_b_time_selected]), "Water when soil moisture < " + str(desired_moisture) + "%")[schedule_selected == 1], schedule_type[0])[schedule_selected == 0] schedule_text_surface = body.render(schedule_text, True, white) schedule_rect = schedule_text_surface.get_rect(center = (int(width/2), 190)) screen.blit(schedule_text_surface, schedule_rect) # Display the buttons for button_text, text_pos in home_buttons.items(): if button_text == "Start/Stop Water": text_surface = body.render(("Start Water", "Stop Water")[currently_watering], True, (nsel, white)[schedule_selected == 0]) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) home_buttons_rect[button_text] = rect # Display the new screen pygame.display.flip() ######################################################################################################### # GUI Select Mode Screen ######################################################################################################### control_buttons = {'Next':(int(width/4), 220), 'Cancel':(int(3*width/4), 220)} control_buttons_rect = {} sched_buttons = {'Manual':(30, 10), 'Moisture':(30, 88), 'Intervals':(30, 150)} sched_buttons_rect = {} manual_selected = False moisture_selected = False intervals_selected = False # Display the GUI to edit schedule page (screen 1) def display_set_schedule1(): # Erase everything on the screen screen.fill(black) # Display the control buttons for button_text, text_pos in sched_buttons.items(): if (button_text == "Manual" and manual_selected): text_surface = header.render(button_text, True, sel) elif (button_text == "Moisture" and moisture_selected): text_surface = header.render(button_text, True, sel) elif (button_text == "Intervals" and intervals_selected): text_surface = header.render(button_text, True, sel) else: text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(topleft = text_pos) screen.blit(text_surface, rect) sched_buttons_rect[button_text] = rect # Display the description for each schedule type manual_descript1_surface = body.render("The user may manually turn on and off the ", True, white) manual_descript2_surface = body.render("water. The system will not automatically", True, white) manual_descript3_surface = body.render("water the plant in this mode.", True, white) screen.blit(manual_descript1_surface, manual_descript1_surface.get_rect(topleft = (30, 30))) screen.blit(manual_descript2_surface, manual_descript2_surface.get_rect(topleft = (30, 45))) screen.blit(manual_descript3_surface, manual_descript3_surface.get_rect(topleft = (30, 60))) moisture_descript1_surface = body.render("Automatically water the plant when the", True, white) moisture_descript2_surface = body.render("soil moisture dips below a set level.", True, white) screen.blit(moisture_descript1_surface, moisture_descript1_surface.get_rect(topleft = (30, 108))) screen.blit(moisture_descript2_surface, moisture_descript2_surface.get_rect(topleft = (30, 123))) interval_descript1_surface = body.render("Automatically water the plant for a", True, white) interval_descript2_surface = body.render("set amount of time at a set interval.", True, white) screen.blit(interval_descript1_surface, interval_descript1_surface.get_rect(topleft = (30, 170))) screen.blit(interval_descript2_surface, interval_descript2_surface.get_rect(topleft = (30, 185))) # Display the control buttons for button_text, text_pos in control_buttons.items(): if (button_text == "Next" and not (manual_selected or moisture_selected or intervals_selected)): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_rect[button_text] = rect # Display the new screen pygame.display.flip() ######################################################################################################### # GUI Set Values for Selected Mode Screen ######################################################################################################### # Basic control buttons control_buttons2 = {"Set":(int(width/4), 220), "Back":(int(2*width/4), 220), "Cancel":(int(3*width/4), 220)} control_buttons2_rect = {} moisture_buttons = {"U_hund":((138,105), (141,100), (144,105)), "U_ten":((149,105), (152,100), (155,105)), "U_one":((160,105), (163,100), (166,105)), "D_hund":((138,110), (141,115), (144,110)), "D_ten":((149,110), (152,115), (155,110)), "D_one":((160,110), (163,115), (166,110))} moisture_buttons_rect = {} interval_arrows = {"U_w_ten":((45,90), (48,85), (51,90)), "U_w_one":((56,90), (59,85), (62,90)), "U_w_unit":((95,90), (100,85), (105,90)), "U_b_ten":((185,90), (188,85), (191,90)), "U_b_one":((196,90), (199,85), (202,90)), "U_b_unit":((235,90), (240,85), (245,90)), "D_w_ten":((45,95), (48,100), (51,95)), "D_w_one":((56,95), (59,100), (62,95)), "D_w_unit":((95,95), (100,100), (105,95)), "D_b_ten":((185,95), (188,100), (191,95)), "D_b_one":((196,95), (199,100), (202,95)), "D_b_unit":((235,95), (240,100), (245,95))} interval_arrows_rect = {} interval_units = ("seconds", "minutes", "hours", "days") interval_w_time_selected = 0 interval_b_time_selected = 1 interval_w_time_selected_tent = 0 interval_b_time_selected_tent = 2 moisture_thous = 0 moisture_hund = 0 moisture_ten = 0 moisture_one = 0 interval_time_b_ten = 0 interval_time_b_one = 1 interval_time_w_ten = 0 interval_time_w_one = 5 interval_b_time = 10*interval_time_b_ten + interval_time_b_one interval_w_time = 10*interval_time_w_ten + interval_time_w_one # The time for each watering is just the watering time that the user specifies water_time_sec = 10*interval_time_w_ten + interval_time_w_one if interval_w_time_selected > 0: water_time_sec *= 60 if interval_w_time_selected > 1: water_time_sec *= 60 if interval_w_time_selected > 2: water_time_sec *= 24 # The time between waterings is equal to the "every ___" time minus the time we want to water for # For example, if we want to water the plant for 1 second every 5 seconds, we would # water for 1 second, wait for 4 seconds, water for 1 second, wait for 4 seconds, etc. between_time_sec = 10*interval_time_b_ten + interval_time_b_one if interval_b_time_selected > 0: between_time_sec *= 60 if interval_b_time_selected > 1: between_time_sec *= 60 if interval_b_time_selected > 2: between_time_sec *= 24 between_time_sec -= water_time_sec # Display the GUI to edit schedule page (screen 2) def display_set_schedule2(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render((("Interval Mode","Moisture Sensing Mode")[moisture_selected],"Manual Mode")[manual_selected], True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # If user selected manual mode, nothing more for them to do. Give brief message if manual_selected: manual_sel1_surface = body.render("The user is in charge of watering the plant. ", True, white) manual_sel2_surface = body.render("The system will not automatically water the", True, white) manual_sel3_surface = body.render("plant in this mode.", True, white) manual_sel4_surface = body.render("Click set to save these changes.", True, white) manual_sel5_surface = body.render("Click back to select a different mode.", True, white) manual_sel6_surface = body.render("Click cancel to return to the homescreen", True, white) manual_sel7_surface = body.render("and discard all changes.", True, white) screen.blit(manual_sel1_surface, manual_sel1_surface.get_rect(center = (int(width/2), 50))) screen.blit(manual_sel2_surface, manual_sel2_surface.get_rect(center = (int(width/2), 70))) screen.blit(manual_sel3_surface, manual_sel3_surface.get_rect(center = (int(width/2), 90))) screen.blit(manual_sel4_surface, manual_sel4_surface.get_rect(center = (int(width/2), 130))) screen.blit(manual_sel5_surface, manual_sel5_surface.get_rect(center = (int(width/2), 150))) screen.blit(manual_sel6_surface, manual_sel6_surface.get_rect(center = (int(width/2), 170))) screen.blit(manual_sel7_surface, manual_sel7_surface.get_rect(center = (int(width/2), 185))) # If user selected moisture mode, prompt for desired moisture level elif moisture_selected: moisture_sel1_surface = body.render("The system will automatically water the plant", True, white) moisture_sel2_surface = body.render("when the soil moisture level drops below", True, white) moisture_sel3_surface = body.render(str(moisture_hund) + " " + str(moisture_ten) + " " + str(moisture_one) + " %", True, white) moisture_sel4_surface = body.render("Click set to save these changes.", True, white) moisture_sel5_surface = body.render("Click back to select a different mode.", True, white) moisture_sel6_surface = body.render("Click cancel to return to the homescreen", True, white) moisture_sel7_surface = body.render("and discard all changes.", True, white) screen.blit(moisture_sel1_surface, moisture_sel1_surface.get_rect(center = (int(width/2), 50))) screen.blit(moisture_sel2_surface, moisture_sel2_surface.get_rect(center = (int(width/2), 70))) screen.blit(moisture_sel3_surface, moisture_sel3_surface.get_rect(center = (int(width/2), 90))) screen.blit(moisture_sel4_surface, moisture_sel4_surface.get_rect(center = (int(width/2), 130))) screen.blit(moisture_sel5_surface, moisture_sel5_surface.get_rect(center = (int(width/2), 150))) screen.blit(moisture_sel6_surface, moisture_sel6_surface.get_rect(center = (int(width/2), 170))) screen.blit(moisture_sel7_surface, moisture_sel7_surface.get_rect(center = (int(width/2), 185))) # Diplay the number control arrows for label, tri_pos in moisture_buttons.items(): if (label == "U_hund"): tri = pygame.draw.polygon(screen, (nsel, white)[moisture_hund < 1], tri_pos) elif (label == "U_ten"): tri = pygame.draw.polygon(screen, (nsel, white)[moisture_ten < 9 and moisture_hund < 1], tri_pos) elif (label == "U_one"): tri = pygame.draw.polygon(screen, (nsel, white)[moisture_one < 9 and moisture_hund < 1], tri_pos) elif (label == "D_hund"): tri = pygame.draw.polygon(screen, (nsel, white)[moisture_hund > 0], tri_pos) elif (label == "D_ten"): tri = pygame.draw.polygon(screen, (nsel, white)[moisture_ten > 0], tri_pos) elif (label == "D_one"): tri = pygame.draw.polygon(screen, (nsel, white)[moisture_one > 0], tri_pos) moisture_buttons_rect[label] = tri # If user selected interval mode, prompt for desired watering interval elif intervals_selected: interval_sel1_surface = body.render("The system will automatically water the plant", True, white) interval_sel2_surface = body.render(str(interval_time_w_ten) + " " + str(interval_time_w_one) + " every " + str(interval_time_b_ten) + " " + str(interval_time_b_one) + " ", True, white) interval_sel3_surface = body.render("Click set to save these changes.", True, white) interval_sel4_surface = body.render("Click back to select a different mode.", True, white) interval_sel5_surface = body.render("Click cancel to return to the homescreen", True, white) interval_sel6_surface = body.render("and discard all changes.", True, white) screen.blit(interval_sel1_surface, interval_sel1_surface.get_rect(center = (int(width/2), 50))) screen.blit(interval_sel2_surface, interval_sel2_surface.get_rect(center = (int(width/2), 70))) screen.blit(interval_sel3_surface, interval_sel3_surface.get_rect(center = (int(width/2), 130))) screen.blit(interval_sel4_surface, interval_sel4_surface.get_rect(center = (int(width/2), 150))) screen.blit(interval_sel5_surface, interval_sel5_surface.get_rect(center = (int(width/2), 170))) screen.blit(interval_sel6_surface, interval_sel6_surface.get_rect(center = (int(width/2), 185))) interval_sel7_surface = body.render(interval_units[interval_w_time_selected_tent], True, white) screen.blit(interval_sel7_surface, interval_sel7_surface.get_rect(center = (100, 70))) interval_sel7_surface = body.render(interval_units[interval_b_time_selected_tent], True, white) screen.blit(interval_sel7_surface, interval_sel7_surface.get_rect(center = (240, 70))) # Diplay the number control arrows for label, tri_pos in interval_arrows.items(): if (label == "U_w_ten"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_w_ten < 5], tri_pos) elif (label == "U_w_one"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_w_one < 9], tri_pos) elif (label == "U_w_unit"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_w_time_selected_tent < 3 and ((interval_w_time_selected_tent + 1) <= interval_b_time_selected_tent)], tri_pos) elif (label == "U_b_ten"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_b_ten < 5], tri_pos) elif (label == "U_b_one"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_b_one < 9], tri_pos) elif (label == "U_b_unit"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_b_time_selected_tent < 3], tri_pos) elif (label == "D_w_ten"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_w_ten > 0 and (10*interval_time_w_ten + interval_time_w_one) - 10 > 0], tri_pos) elif (label == "D_w_one"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_w_one > 0 and (10*interval_time_w_ten + interval_time_w_one) - 1 > 0], tri_pos) elif (label == "D_w_unit"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_w_time_selected_tent > 0], tri_pos) elif (label == "D_b_ten"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_b_ten > 0 and (10*interval_time_b_ten + interval_time_b_one) - 10 > 0], tri_pos) elif (label == "D_b_one"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_time_b_one > 0 and (10*interval_time_b_ten + interval_time_b_one) - 1 > 0], tri_pos) elif (label == "D_b_unit"): tri = pygame.draw.polygon(screen, (nsel, white)[interval_b_time_selected_tent > 0 and (interval_w_time_selected_tent <= (interval_b_time_selected_tent - 1))], tri_pos) interval_arrows_rect[label] = tri # Display the control buttons for button_text, text_pos in control_buttons2.items(): if (intervals_selected and interval_w_time_selected_tent == interval_b_time_selected_tent and 10*interval_time_w_ten + interval_time_w_one >= 10*interval_time_b_ten + interval_time_b_one and button_text == "Set"): text_surface = body.render(button_text, True, nsel) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons2_rect[button_text] = rect else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons2_rect[button_text] = rect # Display the new screen pygame.display.flip() control_buttons_m = {"Next":(int(width/4), 220), "Back":(int(2*width/4), 220), "Cancel":(int(3*width/4), 220)} control_buttons_m_rect = {} plant_type_buttons = {"Flower":(int(width/4), 150), "Fruit":(int(2*width/4), 150), "Tree/Shrub":(int(3*width/4), 150), "My Own Value":(int(width/2), 180)} plant_type_buttons_rect = {} def display_plant_sel(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("If you would like to use pre-defined reference", True, white) moisture_m2_surface = body.render("values, select your plant type. You will be", True, white) moisture_m3_surface = body.render("prompted for a specific plant on the next page.", True, white) moisture_m4_surface = body.render("Otherwise, select 'My Own Value'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 50))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 70))) screen.blit(moisture_m3_surface, moisture_m3_surface.get_rect(center = (int(width/2), 90))) screen.blit(moisture_m4_surface, moisture_m4_surface.get_rect(center = (int(width/2), 110))) # Display the plant type for button_text, text_pos in plant_type_buttons.items(): if (button_text == "Flower" and flower_selected): text_surface = body.render(button_text, True, sel) elif (button_text == "Fruit" and fruit_selected): text_surface = body.render(button_text, True, sel) elif (button_text == "Tree/Shrub" and tree_selected): text_surface = body.render(button_text, True, sel) elif (button_text == "My Own Value" and own_selected): text_surface = body.render(button_text, True, sel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) plant_type_buttons_rect[button_text] = rect # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if button_text == "Next" and not (flower_selected or fruit_selected or tree_selected or own_selected): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Display the new screen pygame.display.flip() ######################################################################################################### # Reference Values ######################################################################################################### # Recommended Soil Moisture Percentages # All data from https://www.acurite.com/blog/soil-moisture-guide-for-plants-and-vegetables.html categories = ["Flowers", "Fruits", "Trees & Shrubs"] moisture_levels = [(0,20), (21,40), (41,60), (61,80)] Flowers1 = [("Agave", 0, 1), ("Aster", 1), ("Astilbe", 2), ("Big Blue Stem", 1), ("Bleeding Heart", 2), ("Butterfly Weed", 1), ("Cactus", 0, 1), ("Catmint", 1), ("Christmas Fern", 1), ("Coneflower", 1), ("Daffodil", 1, 2), ("Dalia", 1, 2), ("Daylilly", 1, 2), ("Gaillardia", 1), ("Heath/Heather", 1), ("Hellebores", 2), ("Hosta", 1, 2), ("Hyssop", 1), ("Iris", 1, 2), ("Ironweed", 2), ("Jack In Pulpits", 2), ("Joe-Pye Weed", 2), ("Lavendar", 1), ("Lemon Balm", 1)] Flowers2 = [("Lily", 1, 2), ("Lobellia", 2, 3), ("Lupine", 2), ("Marigold", 1), ("Marsh Marigold", 3), ("May Apple", 2), ("Meadow Rue", 2, 3), ("Monarda", 1), ("Ornamental Grasses", 1), ("Peony", 1, 2), ("Petunia", 1), ("Poppy", 1), ("Purple Coneflower", 1), ("Queen of the Prairie", 2), ("Red Milkweed", 2), ("Sedge", 1, 2, 3), ("Sedum", 0, 1), ("Pansy", 1, 2), ("Tulip", 1, 2), ("Violet", 1, 2), ("Yarrow", 0, 1), ("Yucca", 0, 1), ("Zinnia", 1)] flower1_rect = {} flower2_rect = {} Fruits = [("Apple", 1, 2), ("Grape", 1, 2), ("Fig", 1, 2), ("Peach", 1, 2), ("Pear", 1, 2), ("Raspberry", 1, 2), ("Strawberry", 1, 2), ("Blackberry", 1, 2), ("Blueberry", 2), ("Cranberry", 3)] fruit_rect = {} TreesShrubs1 = [("Alpine Current", 1), ("American Filbert", 1, 2), ("American Holly", 1), ("Amur Privet", 1), ("Arborvitae", 1), ("Azalea", 1, 2), ("Bald Cypress", 1, 2, 3), ("Barberry", 1), ("Birch", 2), ("Black Tupelo", 1), ("Chinese Juniper", 1), ("Clematis", 1, 2), ("Common Boxwood", 1), ("Common Elderberry", 2), ("Common Lilac", 1), ("Crab Apple", 1), ("Crape Myrtle", 1, 2), ("Dawn Redwood", 2, 3), ("Dogwood", 2, 3), ("Eastern Red Cedar", 1), ("Elderberry", 1, 2, 3), ("Elm", 1, 2), ("Frazier Fir", 1), ("Gardenia", 1)] TreesShrubs2 = [("Ginkgo", 1), ("Hawthorn", 1), ("Holly", 1), ("Honey Locust", 1), ("Horse Chestnut", 1), ("Hydragea", 2), ("Juniper", 1), ("Lilac", 1), ("Maple", 1), ("Mockorange", 1), ("New Jersey Tea", 1), ("Oak", 1), ("Ohio Buckeye", 1), ("Potentilla", 0, 1), ("Red Cedar", 2), ("Red Twig Dogwood", 2), ("Rhodendron", 2), ("Rose", 1), ("Rugosa Rose", 0, 1), ("Saucer Magnolia", 1), ("Serviceberry", 1, 2), ("Silver Maple", 1, 2), ("Spirea", 1), ("Spruce", 1)] TreesShrubs3 = [("Sugar Maple", 1), ("Swamp White Oak", 3), ("Sweetshrub", 1, 2), ("Tamarac/Larch", 2, 3), ("White Fir", 1), ("White Pine", 2), ("Willow", 2, 3)] tree1_rect = {} tree2_rect = {} tree3_rect = {} sum = 0 num = 0 for flower in Flowers1: sum += (moisture_levels[flower[1]][0] + moisture_levels[flower[len(flower)-1]][1])/2 num += 1 for flower in Flowers2: sum += (moisture_levels[flower[1]][0] + moisture_levels[flower[len(flower)-1]][1])/2 num += 1 generalFlower = int(round(sum / num)) print(generalFlower) sum = 0 num = 0 for fruit in Fruits: sum += (moisture_levels[fruit[1]][0] + moisture_levels[fruit[len(fruit)-1]][1])/2 num += 1 generalFruit = int(round(sum / num)) print(generalFruit) sum = 0 num = 0 for tree in TreesShrubs1: sum += (moisture_levels[tree[1]][0] + moisture_levels[tree[len(tree)-1]][1])/2 num += 1 for tree in TreesShrubs2: sum += (moisture_levels[tree[1]][0] + moisture_levels[tree[len(tree)-1]][1])/2 num += 1 for tree in TreesShrubs3: sum += (moisture_levels[tree[1]][0] + moisture_levels[tree[len(tree)-1]][1])/2 num += 1 generalTreeShrub = int(round(sum / num)) print(generalTreeShrub) ######################################################################################################### # Display select flower screen ######################################################################################################### next_screen = {'>>>':(int(width - 35), 203)} next_screen_rect = {} flower_selected = False fruit_selected = False tree_selected = False own_selected = False other_selected = False flower_sel = None fruit_sel = None tree_sel = None def display_flowers1(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("Select the flower that you want to water. If", True, white) moisture_m2_surface = body.render("it does not appear on this screen, select '>>>'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) start_center = (int(width/6), 85) for flower in Flowers1: if flower[0] == flower_sel: text_surface = plant.render(flower[0], True, sel) else: text_surface = plant.render(flower[0], True, white) rect = text_surface.get_rect(center = start_center) screen.blit(text_surface, rect) flower1_rect[flower[0]] = rect start_center = (start_center[0], start_center[1] + 15) if start_center[1] >= 205: start_center = (start_center[0] + int(2*width/6), 85) # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if (button_text == "Next" and flower_sel == None and other_selected == False): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Go to next page arrow to select plants later in alphabet for button_text, text_pos in next_screen.items(): text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) next_screen_rect[button_text] = rect # Display the new screen pygame.display.flip() no_ref = {'<<<':(35, 203), 'Other':(int(5*width/6), 195)} no_ref_rect = {} def display_flowers2(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("Select the flower that you want to water. If", True, white) moisture_m2_surface = body.render("it does not appear on this screen, select 'Other'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) start_center = (int(width/6), 85) for flower in Flowers2: if flower[0] == flower_sel: text_surface = plant.render(flower[0], True, sel) else: text_surface = plant.render(flower[0], True, white) rect = text_surface.get_rect(center = start_center) screen.blit(text_surface, rect) flower2_rect[flower[0]] = rect start_center = (start_center[0], start_center[1] + 15) if start_center[1] >= 205: start_center = (start_center[0] + int(2*width/6), 85) # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if (button_text == "Next" and flower_sel == None and other_selected == False): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Go to next page arrow to select plants later in alphabet for button_text, text_pos in no_ref.items(): if (button_text == "Other" and other_selected): text_surface = header.render(button_text, True, sel) else: text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) no_ref_rect[button_text] = rect # Display the new screen pygame.display.flip() ######################################################################################################### # Display select fruit screen ######################################################################################################### fruit_buttons = {'Other':(int(3*width/6), 125)} fruit_buttons_rect = {} def display_fruit(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("Select the fruit that you want to water. If", True, white) moisture_m2_surface = body.render("it does not appear on this screen, select 'Other'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) start_center = (int(width/6), 85) for fruit in Fruits: if fruit[0] == fruit_sel: text_surface = plant.render(fruit[0], True, sel) else: text_surface = plant.render(fruit[0], True, white) rect = text_surface.get_rect(center = start_center) screen.blit(text_surface, rect) fruit_rect[fruit[0]] = rect start_center = (start_center[0], start_center[1] + 15) if start_center[1] >= 205: start_center = (start_center[0] + int(2*width/6), 85) # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if (button_text == "Next" and fruit_sel == None and other_selected == False): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Other button for button_text, text_pos in fruit_buttons.items(): if (button_text == "Other" and other_selected): text_surface = header.render(button_text, True, sel) else: text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) fruit_buttons_rect[button_text] = rect # Display the new screen pygame.display.flip() ######################################################################################################### # Display select tree screen ######################################################################################################### tree_buttons = {">>>":(int(width - 50), 203), "<<<":(35, 203), "Other":(int(3*width/6), 140)} tree_buttons_rect = {} def display_tree1(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("Select the tree/shrub that you want to water.", True, white) moisture_m2_surface = body.render("If it does not appear on this screen, select '>>>'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) start_center = (int(width/6), 85) for tree in TreesShrubs1: if tree[0] == tree_sel: text_surface = plant.render(tree[0], True, sel) else: text_surface = plant.render(tree[0], True, white) rect = text_surface.get_rect(center = start_center) screen.blit(text_surface, rect) tree1_rect[tree[0]] = rect start_center = (start_center[0], start_center[1] + 15) if start_center[1] >= 205: start_center = (start_center[0] + int(2*width/6), 85) # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if (button_text == "Next" and tree_sel == None and other_selected == False): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Other button for button_text, text_pos in tree_buttons.items(): if (button_text == "<<<" or button_text == "Other"): continue text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) tree_buttons_rect[button_text] = rect # Display the new screen pygame.display.flip() def display_tree2(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("Select the tree/shrub that you want to water.", True, white) moisture_m2_surface = body.render("If it does not appear on this screen, select '>>>'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) start_center = (int(width/6), 85) for tree in TreesShrubs2: if tree[0] == tree_sel: text_surface = plant.render(tree[0], True, sel) else: text_surface = plant.render(tree[0], True, white) rect = text_surface.get_rect(center = start_center) screen.blit(text_surface, rect) tree2_rect[tree[0]] = rect start_center = (start_center[0], start_center[1] + 15) if start_center[1] >= 205: start_center = (start_center[0] + int(2*width/6), 85) # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if (button_text == "Next" and tree_sel == None and other_selected == False): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Other button for button_text, text_pos in tree_buttons.items(): if (button_text == "Other"): continue text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) tree_buttons_rect[button_text] = rect # Display the new screen pygame.display.flip() def display_tree3(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message prompting user if they want to use reference values or set their own values moisture_m1_surface = body.render("Select the tree/shrub that you want to water.", True, white) moisture_m2_surface = body.render("If it does not appear on this screen, select 'Other'.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) start_center = (int(width/6), 85) for tree in TreesShrubs3: if tree[0] == tree_sel: text_surface = plant.render(tree[0], True, sel) else: text_surface = plant.render(tree[0], True, white) rect = text_surface.get_rect(center = start_center) screen.blit(text_surface, rect) tree3_rect[tree[0]] = rect start_center = (start_center[0], start_center[1] + 15) if start_center[1] >= 205: start_center = (start_center[0] + int(2*width/6), 85) # Display the control buttons for button_text, text_pos in control_buttons_m.items(): if (button_text == "Next" and tree_sel == None and other_selected == False): text_surface = body.render(button_text, True, nsel) else: text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) control_buttons_m_rect[button_text] = rect # Other button for button_text, text_pos in tree_buttons.items(): if button_text == ">>>": continue if (button_text == "Other" and other_selected): text_surface = header.render(button_text, True, sel) else: text_surface = header.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) tree_buttons_rect[button_text] = rect # Display the new screen pygame.display.flip() ######################################################################################################### # Display moisture value for plant screen ######################################################################################################### specific_buttons = {"Set":(int(width/8), 220), "Edit":(int(3*width/8), 220), "Back":(int(5*width/8), 220), "Cancel":(int(7*width/8), 220)} specific_buttons_rect = {} temp_desired_val = 0 def display_specific(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Calculate the bounds and average values within those bounds lower_val = 0 upper_val = 0 if flower_selected: for flower in Flowers1: if flower[0] == flower_sel: lower_val = moisture_levels[flower[1]][0] upper_val = moisture_levels[flower[len(flower)-1]][1] for flower in Flowers2: if flower[0] == flower_sel: lower_val = moisture_levels[flower[1]][0] upper_val = moisture_levels[flower[len(flower)-1]][1] elif fruit_selected: for fruit in Fruits: if fruit[0] == fruit_sel: lower_val = moisture_levels[fruit[1]][0] upper_val = moisture_levels[fruit[len(fruit)-1]][1] elif tree_selected: for tree in TreesShrubs1: if tree[0] == tree_sel: lower_val = moisture_levels[tree[1]][0] upper_val = moisture_levels[tree[len(tree)-1]][1] for tree in TreesShrubs2: if tree[0] == tree_sel: lower_val = moisture_levels[tree[1]][0] upper_val = moisture_levels[tree[len(tree)-1]][1] for tree in TreesShrubs3: if tree[0] == tree_sel: lower_val = moisture_levels[tree[1]][0] upper_val = moisture_levels[tree[len(tree)-1]][1] global temp_desired_val temp_desired_val = int(round((lower_val + upper_val)/2)) # Display message showing recommended value for that plant moisture_m1 = "The recommended soil moisture for a" moisture_m2 = ((tree_sel, flower_sel)[flower_selected], fruit_sel)[fruit_selected] + " is " + str(temp_desired_val) + "%" moisture_m1_surface = body.render(moisture_m1, True, white) moisture_m2_surface = body.render(moisture_m2, True, white) moisture_m3_surface = body.render("Click set to proceed with recommended value.", True, white) moisture_m4_surface = body.render("Click edit to edit this value.", True, white) moisture_m5_surface = body.render("Click back to go back to plant selection.", True, white) moisture_m6_surface = body.render("Click cancel to cancel all edits and return", True, white) moisture_m7_surface = body.render("to the homescreen.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) screen.blit(moisture_m3_surface, moisture_m3_surface.get_rect(center = (int(width/2), 90))) screen.blit(moisture_m4_surface, moisture_m4_surface.get_rect(center = (int(width/2), 115))) screen.blit(moisture_m5_surface, moisture_m5_surface.get_rect(center = (int(width/2), 140))) screen.blit(moisture_m6_surface, moisture_m6_surface.get_rect(center = (int(width/2), 165))) screen.blit(moisture_m7_surface, moisture_m7_surface.get_rect(center = (int(width/2), 185))) # Display the control buttons for button_text, text_pos in specific_buttons.items(): text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) specific_buttons_rect[button_text] = rect pygame.display.flip() ######################################################################################################### # Display moisture value for general plant type screen ######################################################################################################### def display_general(): # Erase everything on the screen screen.fill(black) # Display header for type of schedule user chose sched_header_surface = header.render("Moisture Sensing Mode", True, white) screen.blit(sched_header_surface, sched_header_surface.get_rect(center = (int(width/2), 20))) # Display message showing recommended value for that plant type moisture_m1 = "The recommended soil moisture for a" moisture_m2 = "general " + (("tree", "flower")[flower_selected], "fruit")[fruit_selected] + " is " + str(((generalTreeShrub, generalFlower)[flower_selected], generalFruit)[fruit_selected]) + "%" moisture_m1_surface = body.render(moisture_m1, True, white) moisture_m2_surface = body.render(moisture_m2, True, white) moisture_m3_surface = body.render("Click set to proceed with recommended value.", True, white) moisture_m4_surface = body.render("Click edit to edit this value.", True, white) moisture_m5_surface = body.render("Click back to go back to plant selection.", True, white) moisture_m6_surface = body.render("Click cancel to cancel all edits and return", True, white) moisture_m7_surface = body.render("to the homescreen.", True, white) screen.blit(moisture_m1_surface, moisture_m1_surface.get_rect(center = (int(width/2), 45))) screen.blit(moisture_m2_surface, moisture_m2_surface.get_rect(center = (int(width/2), 65))) screen.blit(moisture_m3_surface, moisture_m3_surface.get_rect(center = (int(width/2), 90))) screen.blit(moisture_m4_surface, moisture_m4_surface.get_rect(center = (int(width/2), 115))) screen.blit(moisture_m5_surface, moisture_m5_surface.get_rect(center = (int(width/2), 140))) screen.blit(moisture_m6_surface, moisture_m6_surface.get_rect(center = (int(width/2), 165))) screen.blit(moisture_m7_surface, moisture_m7_surface.get_rect(center = (int(width/2), 185))) # Display the control buttons for button_text, text_pos in specific_buttons.items(): text_surface = body.render(button_text, True, white) rect = text_surface.get_rect(center = text_pos) screen.blit(text_surface, rect) specific_buttons_rect[button_text] = rect pygame.display.flip() ######################################################################################################### # GUI Control ######################################################################################################### code_run = True while code_run: ################################################ # GUI Homescreen Functionalilty ################################################ if ( screen_num == 0): # Get the moisture, temperature, and humidity values moisture = round(pm.get_wetness()) temp = round(9*pm.get_temp()/5 + 32) humidity = round(pm.get_humidity()) # Get the light value light = measure_light() # Display the homescreen (with the updated values) display_home() # Reset the schedule selected variables # We do this in the case the the user advances to the next screen, then hits back or cancel # because we don't want anything to be selected when going into the second screen manual_selected = False moisture_selected = False intervals_selected = False # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in home_buttons_rect.items(): if (rect.collidepoint(pos)): # If user wants to edit the schedule, advance to the next screen if (text == "Edit Schedule"): print("Edit Schedule: Advancing to 'Select Mode' Screen") screen_num = 1 stop_water() # Otherwise, if the user wants to start or stop the water (and we're in manual watering mode), # start/stop the water pump elif (text == "Start/Stop Water"): if schedule_selected == 0: if currently_watering: stop_water() else: start_water() # Water the plant for 3 seconds, wait 5 seconds, re-read moisture value, and water again if needed if schedule_selected == 1: if moisture < desired_moisture and not currently_watering: start_water() elif currently_watering and moisture > desired_moisture: stop_water() if schedule_selected == 2: if not currently_watering: if time.time() >= last_water_end + between_time_sec: start_water() else: if time.time() >= last_water_start + water_time_sec: stop_water() ################################################ # GUI Select Mode Functionality ################################################ elif ( screen_num == 1 ): # Display the select mode screen display_set_schedule1() own_selected = False flower_selected = False fruit_selected = False tree_selected = False # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in control_buttons_rect.items(): if (rect.collidepoint(pos)): # If the next button is hit and a mode is selected, go to the next screen # If the next button is hit but a mode is not selected, stay on this screen if (text == "Next"): if (manual_selected or intervals_selected): print("Next: Advancing to 'Set Values for Selected Mode' Screen") screen_num = 2 if moisture_selected: print("Next: Advancing to 'Select Plant' Screen") screen_num = 3 # If intervals are selected, reset the tentative interval variables # This is used in the case that the user selects intervals, changes the frequency, # but cancels changes before saving. We want the initial numbers to match the current interval if intervals_selected: interval_b_time_selected_tent = interval_b_time_selected interval_w_time_selected_tent = interval_w_time_selected # If cancel is pressed, go back to the home screen elif (text == "Cancel"): print("Cancel: Going Back to 'Home' Screen") screen_num = 0 # Update the variables for which mode the user has tentatively selected. Set all # other modes to false for (text, rect) in sched_buttons_rect.items(): if (rect.collidepoint(pos)): if (text == "Manual"): manual_selected = True moisture_selected = False intervals_selected = False print("Manual Mode Selected") elif (text == "Moisture"): manual_selected = False moisture_selected = True intervals_selected = False print("Moisture Mode Selected") elif ( text == "Intervals"): manual_selected = False moisture_selected = False intervals_selected = True print("Interval Mode Selected") #################################################### # GUI Set Values for Selected Mode Screen #################################################### elif ( screen_num == 2 ): display_set_schedule2() for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in control_buttons2_rect.items(): if (rect.collidepoint(pos)): if (text == "Set"): if manual_selected: screen_num = 0 schedule_selected = 0 print("Manual Mode Set, Returning to Homepage") elif moisture_selected: screen_num = 0 schedule_selected = 1 desired_moisture = 100*moisture_hund + 10*moisture_ten + moisture_one print("Moisture Mode Selected, Returning to Homepage") else: if not (interval_w_time_selected_tent == interval_b_time_selected_tent and 10*interval_time_b_ten + interval_time_b_one <= 10*interval_time_w_ten + interval_time_w_one): screen_num = 0 schedule_selected = 2 interval_b_time = 10*interval_time_b_ten + interval_time_b_one interval_w_time = 10*interval_time_w_ten + interval_time_w_one interval_b_time_selected = interval_b_time_selected_tent interval_w_time_selected = interval_w_time_selected_tent print("Interval Mode Selected, Returning to Homepage") start_water() elif (text == "Back"): if moisture_selected: moisture_thous = int(desired_moisture/1000) moisture_hund = int((desired_moisture - 1000*moisture_thous)/100) moisture_ten = int((desired_moisture - 1000*moisture_thous - 100*moisture_hund)/10) moisture_one = desired_moisture % 10 elif intervals_selected: interval_time_w_ten = int(interval_w_time/10) interval_time_w_one = interval_w_time % 10 interval_w_time_selected_tent = interval_w_time_selected interval_time_b_ten = int(interval_b_time/10) interval_time_b_one = interval_b_time % 10 interval_b_time_selected_tent = interval_b_time_selected print("Going Back a Level") screen_num = 1 elif (text == "Cancel"): if moisture_selected: moisture_thous = int(desired_moisture/1000) moisture_hund = int((desired_moisture - 1000*moisture_thous)/100) moisture_ten = int((desired_moisture - 1000*moisture_thous - 100*moisture_hund)/10) moisture_one = desired_moisture % 10 elif intervals_selected: interval_time_w_ten = int(interval_w_time/10) interval_time_w_one = interval_w_time % 10 interval_w_time_selected_tent = interval_w_time_selected interval_time_b_ten = int(interval_b_time/10) interval_time_b_one = interval_b_time % 10 interval_b_time_selected_tent = interval_b_time_selected print("Canceling Edits, Returning to Homepage") screen_num = 0 # If we're editing the desired moisture level, have arrows increase or decrease the desired moisture level if moisture_selected: for (text, rect) in moisture_buttons_rect.items(): if (rect.collidepoint(pos)): if (text == "U_hund"): if moisture_hund < 1: moisture_hund += 1 moisture_ten = 0 moisture_one = 0 elif (text == "U_ten"): if moisture_ten < 9 and moisture_hund < 1: moisture_ten += 1 elif (text == "U_one"): if moisture_one < 9 and moisture_hund < 1: moisture_one += 1 elif (text == "D_hund"): if moisture_hund > 0: moisture_hund -= 1 elif (text == "D_ten"): if moisture_ten > 0: moisture_ten -= 1 elif (text == "D_one"): if moisture_one > 0: moisture_one -= 1 if intervals_selected: for (text, rect) in interval_arrows_rect.items(): if (rect.collidepoint(pos)): if (text == "U_w_ten"): if (interval_time_w_ten < 5): interval_time_w_ten += 1 elif (text == "U_w_one"): if (interval_time_w_one < 9): interval_time_w_one += 1 elif (text == "U_w_unit"): if (interval_w_time_selected_tent < 3 and ((interval_w_time_selected_tent + 1) <= interval_b_time_selected_tent)): interval_w_time_selected_tent += 1 elif (text == "U_b_ten"): if (interval_time_b_ten < 5): interval_time_b_ten += 1 elif (text == "U_b_one"): if (interval_time_b_one < 9): interval_time_b_one += 1 elif (text == "U_b_unit"): if (interval_b_time_selected_tent < 3): interval_b_time_selected_tent += 1 elif (text == "D_w_ten"): if (interval_time_w_ten > 0 and (10*interval_time_w_ten + interval_time_w_one) - 10 > 0): interval_time_w_ten -= 1 elif (text == "D_w_one"): if (interval_time_w_one > 0 and (10*interval_time_w_ten + interval_time_w_one) - 1 > 0): interval_time_w_one -= 1 elif (text == "D_w_unit"): if (interval_w_time_selected_tent > 0): interval_w_time_selected_tent -= 1 elif (text == "D_b_ten" and (10*interval_time_b_ten + interval_time_b_one) - 10 > 0): if (interval_time_b_ten > 0): interval_time_b_ten -= 1 elif (text == "D_b_one"): if (interval_time_b_one > 0 and (10*interval_time_b_ten + interval_time_b_one) - 1 > 0): interval_time_b_one -= 1 elif (text == "D_b_unit"): if (interval_b_time_selected_tent > 0 and (interval_w_time_selected_tent <= (interval_b_time_selected_tent - 1))): interval_b_time_selected_tent -= 1 # The time for each watering is just the watering time that the user specifies water_time_sec = 10*interval_time_w_ten + interval_time_w_one if interval_w_time_selected > 0: water_time_sec *= 60 if interval_w_time_selected > 1: water_time_sec *= 60 if interval_w_time_selected > 2: water_time_sec *= 24 # The time between waterings is equal to the "every ___" time minus the time we want to water for # For example, if we want to water the plant for 1 second every 5 seconds, we would # water for 1 second, wait for 4 seconds, water for 1 second, wait for 4 seconds, etc. between_time_sec = 10*interval_time_b_ten + interval_time_b_one if interval_b_time_selected > 0: between_time_sec *= 60 if interval_b_time_selected > 1: between_time_sec *= 60 if interval_b_time_selected > 2: between_time_sec *= 24 between_time_sec -= water_time_sec #################################################### # GUI Select Plant Type Screen #################################################### elif ( screen_num == 3 ): # Display the select plant type screen display_plant_sel() flower_sel = None fruit_sel = None tree_sel = None other_selected = False # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in plant_type_buttons_rect.items(): if (rect.collidepoint(pos)): if (text == "Flower"): flower_selected = True fruit_selected = False tree_selected = False own_selected = False elif (text == "Fruit"): flower_selected = False fruit_selected = True tree_selected = False own_selected = False elif (text == "Tree/Shrub"): flower_selected = False fruit_selected = False tree_selected = True own_selected = False elif (text == "My Own Value"): flower_selected = False fruit_selected = False tree_selected = False own_selected = True for (text, rect) in control_buttons_m_rect.items(): if (rect.collidepoint(pos)): if (text == "Next"): # If the user has selected a mode, advance to the next screen if flower_selected: screen_num = 4 elif fruit_selected: screen_num = 6 elif tree_selected: screen_num = 7 elif own_selected: screen_num = 2 elif (text == "Back"): flower_selected = False fruit_selected = False tree_selected = False own_selected = False print("Going Back a Level") screen_num = 1 elif (text == "Cancel"): flower_selected = False fruit_selected = False tree_selected = False own_selected = False print("Canceling Edits, Returning to Homepage") screen_num = 0 #################################################### # GUI Select Flower Screen 1 #################################################### elif ( screen_num == 4 ): # Display the select flower screen display_flowers1() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in flower1_rect.items(): if rect.collidepoint(pos): flower_sel = text for (text,rect) in next_screen_rect.items(): if rect.collidepoint(pos): if text == ">>>": print("Going to next page of flowers") screen_num = 5 for (text,rect) in control_buttons_m_rect.items(): if rect.collidepoint(pos): if text == "Next": if flower_sel != None: screen_num = 10 elif text == "Back": flower_sel = None screen_num = 3 elif text == "Cancel": flower_sel = None flower_selected = False screen_num = 0 #################################################### # GUI Select Flower Screen 2 #################################################### elif ( screen_num == 5 ): # Display the select flower screen display_flowers2() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in flower2_rect.items(): if rect.collidepoint(pos): flower_sel = text other_selected = False for (text,rect) in no_ref_rect.items(): if rect.collidepoint(pos): if text == "<<<": print("Going to previous page of flowers") screen_num = 4 elif text == "Other": other_selected = True flower_sel = None for (text,rect) in control_buttons_m_rect.items(): if rect.collidepoint(pos): if text == "Next": if flower_sel != None: print("Next: Advancing to specific plant page") screen_num = 10 elif other_selected: print("Next: Advancing to general value page") screen_num = 11 elif text == "Back": flower_sel = None other_selected = False screen_num = 3 elif text == "Cancel": flower_sel = None flower_selected = False other_selected = False screen_num = 0 #################################################### # GUI Select Fruit Screen #################################################### elif ( screen_num == 6 ): # Display the select fruit screen display_fruit() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in fruit_rect.items(): if rect.collidepoint(pos): fruit_sel = text other_selected = False for (text,rect) in fruit_buttons_rect.items(): if rect.collidepoint(pos): if text == "Other": other_selected = True fruit_sel = None for (text,rect) in control_buttons_m_rect.items(): if rect.collidepoint(pos): if text == "Next": if fruit_sel != None: print("Next: Advancing to specific plant page") screen_num = 10 elif other_selected: print("Next: Advancing to general value page") screen_num = 11 elif text == "Back": fruit_sel = None other_selected = False screen_num = 3 elif text == "Cancel": flower_sel = None flower_selected = False other_selected = False screen_num = 0 #################################################### # GUI Select Tree/Shrub Screen 1 #################################################### elif ( screen_num == 7 ): # Display the select fruit screen display_tree1() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in tree1_rect.items(): if rect.collidepoint(pos): tree_sel = text other_selected = False for (text,rect) in tree_buttons_rect.items(): if rect.collidepoint(pos): if text == "Other": other_selected = True tree_sel = None elif text == ">>>": print("Going to next page of trees") screen_num = 8 for (text,rect) in control_buttons_m_rect.items(): if rect.collidepoint(pos): if text == "Next": if tree_sel != None: print("Next: Advancing to specific plant page") screen_num = 10 elif other_selected: print("Next: Advancing to general value page") screen_num = 11 elif text == "Back": tree_sel = None other_selected = False screen_num = 3 elif text == "Cancel": screen_num = 0 #################################################### # GUI Select Tree/Shrub Screen 2 #################################################### elif ( screen_num == 8 ): # Display the select fruit screen display_tree2() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in tree2_rect.items(): if rect.collidepoint(pos): tree_sel = text other_selected = False for (text,rect) in tree_buttons_rect.items(): if rect.collidepoint(pos): if text == "Other": other_selected = True tree_sel = None elif text == ">>>": print("Going to next page of trees") screen_num = 9 elif text == "<<<": print("Going to previous page of trees") screen_num = 7 for (text,rect) in control_buttons_m_rect.items(): if rect.collidepoint(pos): if text == "Next": if tree_sel != None: print("Next: Advancing to specific plant page") screen_num = 10 elif other_selected: print("Next: Advancing to general value page") screen_num = 11 elif text == "Back": tree_sel = None other_selected = False screen_num = 3 elif text == "Cancel": screen_num = 0 #################################################### # GUI Select Tree/Shrub Screen 3 #################################################### elif ( screen_num == 9 ): # Display the select fruit screen display_tree3() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in tree3_rect.items(): if rect.collidepoint(pos): tree_sel = text other_selected = False for (text,rect) in tree_buttons_rect.items(): if rect.collidepoint(pos): if text == "Other": other_selected = True tree_sel = None elif text == "<<<": print("Going to previous page of trees") screen_num = 8 for (text,rect) in control_buttons_m_rect.items(): if rect.collidepoint(pos): if text == "Next": if tree_sel != None: print("Next: Advancing to specific plant page") screen_num = 10 elif other_selected: print("Next: Advancing to general value page") screen_num = 11 elif text == "Back": tree_sel = None other_selected = False screen_num = 3 elif text == "Cancel": screen_num = 0 #################################################### # GUI Confirm Plant Moisture Value Screen #################################################### elif ( screen_num == 10 ): # Display the general moisture value screen display_specific() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in specific_buttons_rect.items(): if rect.collidepoint(pos): if text == "Set": desired_moisture = temp_desired_val schedule_selected = 1 screen_num = 0 elif text == "Edit": moisture_hund = int((temp_desired_val / 100)) moisture_ten = int((temp_desired_val / 10)) moisture_one = (temp_desired_val % 10) screen_num = 2 elif text == "Back": if flower_selected: screen_num = 4 elif fruit_selected: screen_num = 6 elif tree_selected: screen_num = 7 elif text == "Cancel": flower_selected = False fruit_selected = False tree_selected = False flower_sel = None fruit_sel = None tree_sel = None moisture_selected = False screen_num = 0 #################################################### # GUI Confirm General Plant Moisture Value Screen #################################################### elif ( screen_num == 11 ): # Display the specific moisture value screen display_general() # Check for button press. If button is pressed, perform its action for event in pygame.event.get(): if ( event.type is MOUSEBUTTONUP ): pos = pygame.mouse.get_pos() x,y = pos for (text, rect) in specific_buttons_rect.items(): if rect.collidepoint(pos): if text == "Set": working = ((generalTreeShrub, generalFlower)[flower_selected], generalFruit)[fruit_selected] desired_moisture = working schedule_selected = 1 screen_num = 0 elif text == "Edit": working = ((generalTreeShrub, generalFlower)[flower_selected], generalFruit)[fruit_selected] moisture_hund = int(working / 100) moisture_ten = int(working / 10) moisture_one = (working % 10) screen_num = 2 elif text == "Back": if flower_selected: screen_num = 4 elif fruit_selected: screen_num = 6 elif tree_selected: screen_num = 7 elif text == "Cancel": flower_selected = False fruit_selected = False tree_selected = False flower_sel = None fruit_sel = None tree_sel = None moisture_selected = False screen_num = 0 # Stop the water if currently_watering: stop_water() # Nicely end the GPIO stuff GPIO.cleanup()
# Ashley Heckman (agh93) & Maria Boza (mib57) # Wednesday Lab, Team 6 # ECE 5725 Final Project # plant_monitor.py import serial import time class PlantMonitor: """A Class for the MonkMakes Plant Monitor""" wetness = 0 temp = 0 humidity = 0 ser = None delay_period = 0.1 def __init__(self): self.ser = serial.Serial("/dev/serial0", 9600) def get_wetness(self): self.send("w") self._wait_for_message() return self.wetness def get_temp(self): self.send("t") self._wait_for_message() return self.temp def get_humidity(self): self.send("h") self._wait_for_message() return self.humidity def led_off(self): self.send("l") def led_on(self): self.send("L") def send(self, message): self.ser.write(bytes(message+"\n", 'utf-8')) time.sleep(self.delay_period) def _wait_for_message(self): time.sleep(self.delay_period) # give attiny time to respond incoming_message = str(self.ser.readline()[:-2].decode("utf-8")) # rem> message_parts = incoming_message.split("=") if len(message_parts) == 2: code, value = message_parts if code == "w": self.wetness = float(value) elif code == "t": self.temp = float(value) elif code == "h": self.humidity = float(value)
# Ashley Heckman (agh93) & Maria Boza (mib57) # Wednesday Lab, Team 6 # ECE 5725 Final Project # surveillance.py # Source code from the official PiCamera package # http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming import io import picamera import logging import socketserver from threading import Condition from http import server from threading import Thread watering_sched = [] PAGE="""\ <html> <head> <title>Automatic Plant Waterer</title> <meta charset = "UTF-8"> <meta name = "viewport" content = "width = device-width, initial-scale = 1"> <link href = "https://agheck.github.io/style.css" rel="stylesheet" type="text/css"> <script defer src="http://pyscript.net/alpha/pyscript.js"></script> <style> body { font-family: Arial, Helvetica, sans-serif; } </style> </head> <body> <div id = "everything"> <div id = "main-title"> Automatic Plant Waterer </div> <div id = "class-info"> <center>Ashley Heckman (agh93) & Maria Boza (mib57)</center> <center>ECE 5725 Final Project</center> <center>Spring 2023</center> </div> <br> <div id = "all-but-title"> <div id = "subtitle"> Livestream </div> <div class = "main-text"> Check out the live camera stream to see how your plant is doing! Watch those plants grow!<br> </div> <center><img src="stream.mjpg" width="320" height="240"></center> <br> </div> </div> </body> </html> """ class StreamingOutput(object): def __init__(self): self.frame = None self.buffer = io.BytesIO() self.condition = Condition() def write(self, buf): if buf.startswith(b'\xff\xd8'): # New frame, copy the existing buffer's content and notify all # clients it's available self.buffer.truncate() with self.condition: self.frame = self.buffer.getvalue() self.condition.notify_all() self.buffer.seek(0) return self.buffer.write(buf) class StreamingHandler(server.BaseHTTPRequestHandler): def do_GET(self): if self.path == '/': self.send_response(301) self.send_header('Location', '/index.html') self.end_headers() elif self.path == '/index.html': content = PAGE.encode('utf-8') self.send_response(200) self.send_header('Content-Type', 'text/html') self.send_header('Content-Length', len(content)) self.end_headers() self.wfile.write(content) elif self.path == '/stream.mjpg': self.send_response(200) self.send_header('Age', 0) self.send_header('Cache-Control', 'no-cache, private') self.send_header('Pragma', 'no-cache') self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME') self.end_headers() try: while True: with output.condition: output.condition.wait() frame = output.frame self.wfile.write(b'--FRAME\r\n') self.send_header('Content-Type', 'image/jpeg') self.send_header('Content-Length', len(frame)) self.end_headers() self.wfile.write(frame) self.wfile.write(b'\r\n') except Exception as e: logging.warning( 'Removed streaming client %s: %s', self.client_address, str(e)) else: self.send_error(404) self.end_headers() class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer): allow_reuse_address = True daemon_threads = True output = StreamingOutput() class Cam(Thread): def __init__(self): Thread.__init__(self) self.daemon = True self.start() def run(self): with picamera.PiCamera(resolution='640x480', framerate=24) as camera: #Uncomment the next line to change your Pi's Camera rotation (in degrees) #camera.rotation = 90 camera.start_recording(output, format='mjpeg') try: address = ('', 8000) server = StreamingServer(address, StreamingHandler) server.serve_forever() finally: camera.stop_recording() a = 0 class Control(Thread): def __init__(self): Thread.__init__(self) self.daemon = True self.start() def run(self): while True: global a #a += 1 #print(str(a)) Cam() Control() while True: pass