After a long hiatus, I finally got my code finalized. When I first started drafting it, I made the code way too simple and did not take into account multiple hurdles I had to work around. This post will serve to describe what kinds of problems I was running into while coding up the software that would make this device work and what my thinking process was like in building this code. The script I wrote does not work around every possible set back that could happen, but I made it work for my current environment; I will elaborate on this throughout the post. Here is the completed code base for this project:
#sprinkler prototype code
#code to make script run once every day
from Arduino import Arduino
import datetime
from datetime import datetime, timedelta
from threading import Timer
import csv as csv
import numpy as np
import time
flag_system = open("flag_matrix.csv", "wb")
open_file_object = csv.writer(flag_system)
open_file_object.writerow(["Date","Type_of_Shutdown"]) #type 1 = 48 hr; type 2 = 1 week
flag_system.close()
x = datetime.today()
y = (x + timedelta(days=1)).replace(hour=12, minute=50, second=0)
delta_t = y - x
secs=delta_t.seconds+1
def sprinkler_manager():
#Will return a giant convoluted dictionary of info
import pywapi
import re
weather_com_results = pywapi.get_weather_from_weather_com('91326')
led_pin = 13
board = Arduino("9600", port="/dev/cu.usbmodem1411")
board.Servos.attach(9)
def will_it_rain_forecast(weather_com_results):
all_rain_predictions = []
#weather.com only forecasts five days in advance
for i in range(0,5):
all_rain_predictions.append(weather_com_results["forecasts"][i]["day"]["chance_precip"])
#storing values in a list to use later
return all_rain_predictions
check_list = will_it_rain_forecast(weather_com_results)
#This will check at what day specifically it will rain. It will return a list of
#the days where it is predicted to rain
def rain_check(check_list):
rain_days=[]
for i in range(0,5):
if check_list[i] > 0:
rain_days.append(weather_com_results["forecasts"][i]["date"])
return rain_days
test = rain_check(check_list)
#The rain_check function returns a list of dates in unicode. This function will
#clean up the list and return another list of just the days of the forecasted
#5 days that it will rain in an integer for so that it is easier to compare
#the dates with the function datetime.today()
def date_cleaner(test):
stage_1=[]
for i in range(len(test)):
stage_1.append(test[i].split(" "))
stage_2 =[]
for i in range(len(stage_1)):
stage_2.append(stage_1[i][1])
stage_2 = [int(i) for i in stage_2]
return stage_2
date_today = date.today()
date_today_checker = date_today.strftime("%Y-%m-%d")
date_today_checker = date_today_checker.split("-")
rain_days_list = date_cleaner(test)
if len(rain_days_list) > 1:
#shut off sprinkler system for the week
board.Servos.write(9, 180)
flag_system = open("flag_matrix.csv", "a")
open_file_object = csv.writer(flag_system)
open_file_object.writerow([date.today(),2])
elif len(rain_days_list) == 1:
#see if that day matches today. If it does, then shut off sprinkler system
#for 48 hours and then turn back on
if int(date_today_checker[2]) == rain_days_list[0]:
#shut off 48 hours
board.Servos.write(9, 180)
flag_system = open("flag_matrix.csv", "a")
open_file_object = csv.writer(flag_system)
open_file_object.writerow([date.today(),1])
flag_system.close()
t = Timer(secs, sprinkler_manager)
t.start()
############################################################################
from Arduino import Arduino
import datetime
from datetime import datetime, timedelta, date
from threading import Timer
import csv as csv
import numpy as np
import time
x2 = datetime.today()
y2 = (x2 + timedelta(days=1)).replace(hour=12, minute=52, second=0)
delta_t2 = y2 - x2
secs2=delta_t2.seconds+1
#For this part of the code I am loading the csv file that has all the flags
#of when the sprinkler has been shut off
def arduino_controller_checker():
led_pin = 13
board = Arduino("9600", port="/dev/cu.usbmodem1411")
board.Servos.attach(9)
csv_file_object = csv.reader(open('/Users/vonschoeneck/Desktop/flag_matrix.csv', 'rb'))
header = csv_file_object.next()
data = []
for row in csv_file_object:
data.append(row)
data = np.array(data)
#Now I am grabbing the info I need from the file
last_row = data[-1]
#Remember: type 1 = 48 hours, type 2= 1 week
type_of_shutoff = int(last_row[1])
date_of_shutoff = last_row[0]
#Date of shutoff is coverted into a numpy string when written to csv so I
#need to convert date_of_shutoff back into a datetime object to be
#able to use timedelta to see the difference in time
date_of_shutoff= datetime.strptime(date_of_shutoff, "%Y-%m-%d")
#Checks when 2 days have passed and when a week has passed
d2 = datetime.today() - timedelta(days = 2)
d7 = datetime.today() - timedelta(days = 7)
if type_of_shutoff == 1: #48 hr type
if d2.day == date_of_shutoff.day:
#turn back on
board.Servos.write(9, 0)
elif type_of_shutoff == 2:
if d7.day == date_of_shutoff.day:
#turn back on
board.Servos.write(9, 0)
#have now loaded the csv file successfully. This file contains all the flags
#when the sprinkler has been shut off and what type of shut off it has been
#now I want to figure out what kind of shut off it has been and see how many
#days it has passed since the shut off
t2 = Timer(secs2, arduino_controller_checker)
t2.start()
A quick rundown of the code
The First Half
The goal of this code is to request from pywapi (a weather API for python) a dictionary of the weather report for whatever zipcode you are interested in and then evaluate whether the sprinkler should be shut off or not.
The will_it_rain function then filters out the forecasted chance of precipitation percentages and stores them in a list. The pywapi only gives you forecasts for 5 days. The rain_check function returns a list of the exact dates when it is predicted to rain. The date_cleaner function converts the dates (which are unicode dates) into strings and then a list of integers of just the actual day. For example it takes the date: "u'Jun 20" into just the integer 20. We also store today's date by using datetime and converting that datetime object into a string and then into an integer like we did for the date returned from pywapi earlier.
Now that we have the dates where it is forecasted to rain, we test a couple conditions. We are interested in testing whether during the next 5 days it'll rain more than one day, only one day, or if it will rain at all. If it only rains one day and that day is today, then we want to shut off the sprinkler for 48 hours. If it rains twice or more in the next 5 days then we want to shut off the system for the rest of that week. If it doesn't rain at all we don't do anything and leave the sprinkler system do its normal thing. To be able to keep track of how many days have passed if we find it does rain during some time, we want to store these values in a csv file that we can call them later. We only store the date and type of shut off if we have decided to shut off the sprinkler system (type 1= 48 hours, type 2= 1 week). This is where the next piece of code comes into play.
The Second Half
The next piece of code, separated by the line of ##### is where we read in the information from the csv file we created. We take the most recent row that was written and store the date and the type in the variables date_of_shufoff and type_of_shutoff respectively. To be able to determine how many days have passed, today's date and the date from date_of_shutoff have to be a datetime object. However, in the previous snippet of code, the date is stored as a numpy string. Therefore we have to take some extra steps to convert date_of_shutoff back into a datetime object before we can use it. Now we create some variables d2 and d7 that store the date it should be if we were to subtract 2 or 7 days from today's date. Finally, we compare the d2 and d7 dates (depending on what type of shut off it was) and see if those dates match the date_of_shutoff date. If they do, then enough time has passed and we can turn the sprinklers back on.
There are some issues with this code that can be improved upon. Firstly, if you live in an area where it rains a lot, you may end up with a very big csv file if you are to keep all those flag values over some time. The area I tested around does not have a lot of rain, so the csv file will remain very small and manageable over time. You also may prefer to run the first main function sprinkler_manager every 5 days since that will avoid looking at the same dates every day and storing those values over again. Again, this issue won't be very big in the area I picked to test this in (91326) because it rarely rains there. You could also make a nice GUI for this code so its more user friendly and allow the user to input their desired zip code before running the program. There are lots of improvements that could be made to this code but the goal for this project was to make a rough prototype that could take information from the internet and make a simple decision: to shut off the sprinkler system or leave it open.
For some final comments, building this code was lots of fun! I used a lot of data munging techniques that I learned from the Kaggle titanic competition tutorials to transform the information into something useful and learned a lot about other tools such as string parsing and using datatime objects. I also learned a lot about the Arduino Python API and how to code in python for my Arduino projects. I combined a lot of ideas from the Arduino Networked Lamp, other Arduino weather station projects that I saw online, and data clean up techniques learned from Kaggle and books such as Python for Data Analysis (an O'reilly book). Overall I really did enjoy this and hope to come up with another cool project.
The goal of this code is to request from pywapi (a weather API for python) a dictionary of the weather report for whatever zipcode you are interested in and then evaluate whether the sprinkler should be shut off or not.
The will_it_rain function then filters out the forecasted chance of precipitation percentages and stores them in a list. The pywapi only gives you forecasts for 5 days. The rain_check function returns a list of the exact dates when it is predicted to rain. The date_cleaner function converts the dates (which are unicode dates) into strings and then a list of integers of just the actual day. For example it takes the date: "u'Jun 20" into just the integer 20. We also store today's date by using datetime and converting that datetime object into a string and then into an integer like we did for the date returned from pywapi earlier.
Now that we have the dates where it is forecasted to rain, we test a couple conditions. We are interested in testing whether during the next 5 days it'll rain more than one day, only one day, or if it will rain at all. If it only rains one day and that day is today, then we want to shut off the sprinkler for 48 hours. If it rains twice or more in the next 5 days then we want to shut off the system for the rest of that week. If it doesn't rain at all we don't do anything and leave the sprinkler system do its normal thing. To be able to keep track of how many days have passed if we find it does rain during some time, we want to store these values in a csv file that we can call them later. We only store the date and type of shut off if we have decided to shut off the sprinkler system (type 1= 48 hours, type 2= 1 week). This is where the next piece of code comes into play.
The Second Half
The next piece of code, separated by the line of ##### is where we read in the information from the csv file we created. We take the most recent row that was written and store the date and the type in the variables date_of_shufoff and type_of_shutoff respectively. To be able to determine how many days have passed, today's date and the date from date_of_shutoff have to be a datetime object. However, in the previous snippet of code, the date is stored as a numpy string. Therefore we have to take some extra steps to convert date_of_shutoff back into a datetime object before we can use it. Now we create some variables d2 and d7 that store the date it should be if we were to subtract 2 or 7 days from today's date. Finally, we compare the d2 and d7 dates (depending on what type of shut off it was) and see if those dates match the date_of_shutoff date. If they do, then enough time has passed and we can turn the sprinklers back on.
There are some issues with this code that can be improved upon. Firstly, if you live in an area where it rains a lot, you may end up with a very big csv file if you are to keep all those flag values over some time. The area I tested around does not have a lot of rain, so the csv file will remain very small and manageable over time. You also may prefer to run the first main function sprinkler_manager every 5 days since that will avoid looking at the same dates every day and storing those values over again. Again, this issue won't be very big in the area I picked to test this in (91326) because it rarely rains there. You could also make a nice GUI for this code so its more user friendly and allow the user to input their desired zip code before running the program. There are lots of improvements that could be made to this code but the goal for this project was to make a rough prototype that could take information from the internet and make a simple decision: to shut off the sprinkler system or leave it open.
For some final comments, building this code was lots of fun! I used a lot of data munging techniques that I learned from the Kaggle titanic competition tutorials to transform the information into something useful and learned a lot about other tools such as string parsing and using datatime objects. I also learned a lot about the Arduino Python API and how to code in python for my Arduino projects. I combined a lot of ideas from the Arduino Networked Lamp, other Arduino weather station projects that I saw online, and data clean up techniques learned from Kaggle and books such as Python for Data Analysis (an O'reilly book). Overall I really did enjoy this and hope to come up with another cool project.