diff --git a/.gitignore b/.gitignore
index 64bf1ff..1f5144d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@
*.log
logs/
+#local
+*.local*
# MISC
camera.sh
manual_transfer.py
diff --git a/ControlPanel/README.md b/ControlPanel/README.md
index a5e9fbb..0b8ee62 100644
--- a/ControlPanel/README.md
+++ b/ControlPanel/README.md
@@ -1 +1,7 @@
-This is an website built to directly interface with the garden and display status from the various modules in the system.
\ No newline at end of file
+# Control Panel
+
+This is an website built to directly interface with the garden and display status from the various modules in the system.
+
+## **Warning:** This will probably be replaced with [Home Assistant](https://www.home-assistant.io/) in the future.
+
+
diff --git a/GardenModules/README.md b/GardenModules/README.md
new file mode 100644
index 0000000..96f9103
--- /dev/null
+++ b/GardenModules/README.md
@@ -0,0 +1,3 @@
+# Garden Modules
+
+This folder houses the gardent modules. Each module represents and manages some form of input or output, e.g. a soil moisture sensor. The idea behind this approach is to make adding features as simple as adding a new module.
\ No newline at end of file
diff --git a/GardenModules/artificalLight/README.md b/GardenModules/artificalLight/README.md
new file mode 100644
index 0000000..befcf3d
--- /dev/null
+++ b/GardenModules/artificalLight/README.md
@@ -0,0 +1,3 @@
+# Artificial Light Sensor
+
+This is a module to control a relay that controls artificial lighting for plants. This module was built for the [SunFounder 2 Channel DC 5V Relay Module with Optocoupler Low Level Trigger Expansion Board for Arduino](https://www.amazon.com/gp/product/B00E0NTPP4/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
\ No newline at end of file
diff --git a/GardenModules/gardenServer/README.md b/GardenModules/gardenServer/README.md
new file mode 100644
index 0000000..b509106
--- /dev/null
+++ b/GardenModules/gardenServer/README.md
@@ -0,0 +1,3 @@
+# Garden Server
+
+This is a server that uses Flask to remotely interface with the garden. This includes a heartbeat REST endpoint, that can be used to detect if a sensor is still working.
\ No newline at end of file
diff --git a/GardenModules/gardenServer/gardenServer.py b/GardenModules/gardenServer/gardenServer.py
index c4fb05e..bb4ab3b 100644
--- a/GardenModules/gardenServer/gardenServer.py
+++ b/GardenModules/gardenServer/gardenServer.py
@@ -5,7 +5,7 @@
import logging
import time
-app = Flask(__name__, template_folder='/home/pi/Desktop/smartGarden/smartGarden/ControlPanel', static_folder="/home/pi/Desktop/smartGarden/smartGarden/ControlPanel")
+app = Flask(__name__, template_folder='./ControlPanel', static_folder="./ControlPanel")
CORS(app)
Debug(app)
@@ -105,9 +105,56 @@ def get_light():
print(e)
+@app.route('/soil')
+def soil_route():
+ try:
+ with open("./soilLog.txt") as file:
+ #lines = file.readlines()
+ table = ""
+ for count, line in reversed(list(enumerate(file))):
+ fields = line.split()
+ raw_value = fields[8]
+ percent = fields[3]
+ date = fields[4]
+ time = fields[5]
+
+ if count % 2 == 0:
+ table = table + "
"
+ else:
+ table = table + "
"
+
+ table = table + "| " + date + " | "
+ table = table + "" + time + " | "
+ table = table + "" + percent + " | "
+ table = table + "" + raw_value + " | "
+ table = table + "
"
+ return '''
+
+
+ Soil Moisture - Smart Garden
+
+
+ Soil Moisture Data
+
+
+ | Date |
+ Time |
+ Soil Moisture Percent |
+ Soil Moisture Raw Value |
+
+ ''' + table + '''
+
+
+
+ '''
+ except Exception as e:
+ logging.warn("There was an exception returning soil data to rest endpoint: " + str(e))
+ return "There was an exception: " + str(e)
+
+
@app.route('/garden')
def garden_route():
- with open("/home/pi/Desktop/smartGarden/smartGarden/logs/smartGardenLog.txt") as file:
+ with open("./logs/smartGardenLog.txt") as file:
return file.read()
@@ -119,31 +166,31 @@ def control_panel():
@app.route('/water')
def control_panel_water():
- with open('/home/pi/Desktop/smartGarden/smartGarden/ControlPanel/water.html') as file:
+ with open('./ControlPanel/water.html') as file:
return file.read()
@app.route('/light')
def control_panel_light():
- with open('/home/pi/Desktop/smartGarden/smartGarden/ControlPanel/light.html') as file:
+ with open('./ControlPanel/light.html') as file:
return file.read()
@app.route('/soilMoisture')
def control_panel_soil_moisture():
- with open('/home/pi/Desktop/smartGarden/smartGarden/ControlPanel/soilMoisture.html') as file:
+ with open('./ControlPanel/soilMoisture.html') as file:
return file.read()
@app.route('/sun_css')
def sun_css():
- with open('/home/pi/Desktop/smartGarden/smartGarden/ControlPanel/sun.css') as file:
+ with open('./ControlPanel/sun.css') as file:
return file.read()
@app.route('/status_css')
def status_css():
- with open('/home/pi/Desktop/smartGarden/smartGarden/ControlPanel/status.css') as file:
+ with open('./ControlPanel/status.css') as file:
return file.read()
# End Control Panel Endpoints
diff --git a/GardenModules/luxSensor/README.md b/GardenModules/luxSensor/README.md
new file mode 100644
index 0000000..21f33b5
--- /dev/null
+++ b/GardenModules/luxSensor/README.md
@@ -0,0 +1,3 @@
+# Lux Sensor
+
+This is a module for a [Adafruit TSL2591 High Dynamic Range Digital Light Sensor.](https://www.amazon.com/gp/product/B00XW2OFWW/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
\ No newline at end of file
diff --git a/GardenModules/luxSensor/luxSensor.py b/GardenModules/luxSensor/luxSensor.py
index 805ffd6..49b2b9f 100644
--- a/GardenModules/luxSensor/luxSensor.py
+++ b/GardenModules/luxSensor/luxSensor.py
@@ -19,7 +19,7 @@ def __init__(self, log, queue):
self._sensor.gain = 0
self._grow_light_lux = 535
self._lux_interval = 120
- self._data_file = "/home/pi/Desktop/smartGarden/smartGarden/Data/luxData.csv"
+ self._data_file = "./Data/luxData.csv"
self._log.info("Lux sensor start up successful")
except Exception as exception:
self._log.error("Lux sensor failed to start up.")
diff --git a/GardenModules/prune/prune.py b/GardenModules/prune/prune.py
index b4ba474..9142b21 100644
--- a/GardenModules/prune/prune.py
+++ b/GardenModules/prune/prune.py
@@ -3,7 +3,7 @@
def prune(file):
lines = []
try:
- logFile = open("/home/pi/Desktop/smartGarden/smartGarden/logs/" + file, "r")
+ logFile = open("./logs/" + file, "r")
for line in logFile:
lines.append(line)
except Exception as e:
@@ -12,7 +12,7 @@ def prune(file):
logFile.close()
try:
- logFile = open("/home/pi/Desktop/smartGarden/smartGarden/logs/" + file, "w")
+ logFile = open("./logs/" + file, "w")
if len(lines) > 5000:
# Only keep the last 5000 lines
for x in range(5000):
diff --git a/GardenModules/pump/README.md b/GardenModules/pump/README.md
new file mode 100644
index 0000000..130604b
--- /dev/null
+++ b/GardenModules/pump/README.md
@@ -0,0 +1,3 @@
+# Water Pump Module
+
+This module is to control a DC water pump connected to a [DROK 200203 DC 5-36V 400W Dual Large Power MOS Transistor Driving Module](https://www.amazon.com/gp/product/B01J78FX9S/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) [Here](https://www.amazon.com/gp/product/B07DW4WRV8/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) is the pump used.
\ No newline at end of file
diff --git a/GardenModules/soilMoisture/README.md b/GardenModules/soilMoisture/README.md
new file mode 100644
index 0000000..aef895c
--- /dev/null
+++ b/GardenModules/soilMoisture/README.md
@@ -0,0 +1,3 @@
+# Soil Moisture Sensor
+
+This is a module to control a [Gikfun Capacitive Soil Moisture Sensor](https://www.amazon.com/gp/product/B07H3P1NRM/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) via I2C. The soil moisture sensor is connected to a [Onyehn ADS1115 16 Byte 4 Channel I2C IIC Analog-to-Digital ADC Converter](https://www.amazon.com/gp/product/B07L3Q7N7T/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
\ No newline at end of file
diff --git a/GardenModules/soilMoisture/soil.py b/GardenModules/soilMoisture/soil.py
index ba057c4..0b9684d 100644
--- a/GardenModules/soilMoisture/soil.py
+++ b/GardenModules/soilMoisture/soil.py
@@ -23,7 +23,7 @@ def __init__(self, log, queue):
self.soilInterval = 120 # 1800
self._log.info("Channel: " + str(self.channel))
self.setName("soilThread")
- self._data_file = "/home/pi/Desktop/smartGarden/smartGarden/Data/soilMoistureData.csv"
+ self._data_file = "./Data/soilMoistureData.csv"
# Set Gain to 16 bits
# Gain = 1 # Wet: 13884 Dry: 21680
@@ -69,7 +69,7 @@ def _checkSoil(self):
self._log.exception("Error calculating soil moisture")
try:
- with open("/home/pi/Desktop/smartGarden/smartGarden/logs/soilLog.txt", "a+") as logFile:
+ with open("./logs/soilLog.txt", "a+") as logFile:
logFile.write("Soil Moisture Level: " + str(self.getSoilPercentage()) + "% " + str(
datetime.now()) + " Raw Value: " + str(self.channel.value) + "\n")
except Exception as exception:
diff --git a/GardenModules/tempSensor/README.md b/GardenModules/tempSensor/README.md
new file mode 100644
index 0000000..fc4d7e5
--- /dev/null
+++ b/GardenModules/tempSensor/README.md
@@ -0,0 +1,3 @@
+# Temperature Sensor
+
+This is a module to read data from a [DFRobot Waterproof DS18B20 Temperature Sensor Kit](https://www.amazon.com/gp/product/B07434MB77/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
\ No newline at end of file
diff --git a/ModuleTests/Data/luxData.csv b/Tests/Data/luxData.csv
similarity index 97%
rename from ModuleTests/Data/luxData.csv
rename to Tests/Data/luxData.csv
index 84f47c5..f4528b7 100644
--- a/ModuleTests/Data/luxData.csv
+++ b/Tests/Data/luxData.csv
@@ -1,3 +1,3 @@
-527.978462833967,2020-11-29 02:55:51.918946
-528.5072462839585,2020-11-29 02:56:02.070627
-529.5646851648721,2020-11-29 02:56:12.221543
+527.978462833967,2020-11-29 02:55:51.918946
+528.5072462839585,2020-11-29 02:56:02.070627
+529.5646851648721,2020-11-29 02:56:12.221543
diff --git a/ModuleTests/GardenModules/GardenModule.py b/Tests/GardenModules/GardenModule.py
similarity index 100%
rename from ModuleTests/GardenModules/GardenModule.py
rename to Tests/GardenModules/GardenModule.py
diff --git a/ModuleTests/GardenModules/artificalLight/artificalLight.py b/Tests/GardenModules/artificalLight/artificalLight.py
similarity index 100%
rename from ModuleTests/GardenModules/artificalLight/artificalLight.py
rename to Tests/GardenModules/artificalLight/artificalLight.py
diff --git a/ModuleTests/GardenModules/email/email.py b/Tests/GardenModules/email/email.py
similarity index 97%
rename from ModuleTests/GardenModules/email/email.py
rename to Tests/GardenModules/email/email.py
index 2620bbe..362f38a 100644
--- a/ModuleTests/GardenModules/email/email.py
+++ b/Tests/GardenModules/email/email.py
@@ -1,163 +1,163 @@
-from email.mime.text import MIMEText
-from email.mime.multipart import MIMEMultipart
-from email.mime.base import MIMEBase
-from email.utils import formatdate
-from email import encoders
-from datetime import datetime
-from datetime import timedelta
-import smtplib, ssl
-import logging
-
-def send_email():
- port = 465 # For SSL
- password = "al.EX.91.27"
- sender_email = "raspberry.pi.taffe@gmail.com"
- receiver_email = "taffeAlexander@gmail.com"
- message = MIMEMultipart("alternative")
- message["Subject"] = "Garden update: " + formatdate(localtime=True)
- message["From"] = sender_email
- message["To"] = receiver_email
- message["Date"] = formatdate(localtime=True)
- soilMoisture = "No Data"
- soilTimeStamp = "No Data"
- soilIterator = 0
- soilMoistureArray = []
- soilTimeStampArray = []
- currentYMD = str(datetime.now()).split()[0]
-
- # Create the body of the message (a plain-text and an HTML version).
- text = "Garden update plan text"
-
- try:
- html = """\
-
-
-
-
-
- Garden Update
-
-
- | Sunlight |
- TimeStamp |
- Soil Moisture |
- TimeStamp |
-
- """
- soilLogArray = []
- with open("/home/pi/Desktop/smartGarden/smartGarden/logs/soilLog.txt", "r") as fp2:
- for count, line in enumerate(fp2):
- soilLogArray.append(line)
-
- for line in soilLogArray:
- try:
- splitLine = line.split()
- if (currentYMD == splitLine[4]) and (len(splitLine) > 5):
- soilMoistureArray.append(splitLine[3])
- soilTimeStampArray.append(splitLine[4] + " " + splitLine[5])
- except Exception as e:
- logging.warn("Unable to parse soil moisture or time stamp for email")
- logging.warn(e)
- print("Error parsing soil log: " + str(e))
-
- with open("/home/pi/Desktop/smartGarden/smartGarden/logs/sunlightLog.txt", "r") as fp:
- for cnt, line in enumerate(fp):
- lineArray = line.split()
- highlightedRow = ""
- regularRow = " | "
- greyRow = " | "
-
- if currentYMD == lineArray[3] or currentYMD == lineArray[4]:
- if soilIterator < len(soilMoistureArray):
- soilMoisture = soilMoistureArray[soilIterator]
- soilTimeStamp = soilTimeStampArray[soilIterator]
- soilIterator = soilIterator + 1
- print("Setting moisture: " + soilMoisture)
- else:
- soilMoisture = "NO DATA"
- soilTimeStamp = "NO DATA"
- if cnt % 2 == 0:
- if "YES" in lineArray[0]:
- row = " | " + highlightedRow + lineArray[0] + " " + lineArray[1] + ""
- else:
- row = "
" + regularRow + lineArray[0] + " " + lineArray[1] + ""
-
- row = row + regularRow + lineArray[3] + " " + lineArray[4]+ ""
- row = row + regularRow + soilMoisture +"%"
- row = row + regularRow + soilTimeStamp + "
"
- else:
- if "YES" in lineArray[0]:
- row = "" + highlightedRow + lineArray[0] + " " + lineArray[1] + ""
- else:
- row = "
" + greyRow + lineArray[0] + " " + lineArray[1] + ""
- row = row + greyRow + lineArray[3] + " " + lineArray[4]+ ""
- row = row + greyRow + soilMoisture + "%"
- row = row + greyRow + soilTimeStamp + "
"
- html = html + row
- elif currentYMD == lineArray[4]:
- if cnt % 2 == 0:
- if "YES" in lineArray[0]:
- row = "" + highlightedRow + lineArray[0] + " " + lineArray[1] + " " + lineArray[2] + ""
- else:
- row = "
" + regularRow + lineArray[0] + " " + lineArray[1] + ""
- row = row + regularRow + lineArray[4] + " " + lineArray[5]+ ""
- row = row + regularRow + soilMoisture + "%"
- row = row + regularRow + soilTimeStamp + "
"
- else:
- if "YES" in lineArray[0]:
- row = "" + highlightedRow + lineArray[0] + " " + lineArray[1] + " " + lineArray[2] + ""
- else:
- row = "
" + greyRow + lineArray[0] + " " + lineArray[1] + ""
- row = row + greyRow + lineArray[4] + " " + lineArray[5]+ ""
- row = row + greyRow + soilMoisture + "%"
- row = row + greyRow + soilTimeStamp + "
"
- html = html + row
- html = html + """\
-
-
-
- """
- except Exception as e:
- logging.warn("There was an error reading html file. Defaulting to basic html page")
- html = """\
-
-
-
- Garden Update
-
-
- """
- logging.warn(e)
- print("Error sending email: " + str(e))
-
- try:
- #Open the file to be sent
- attachment = open("/home/pi/Desktop/smartGarden/smartGarden/logs/smartGardenLog.txt", "rb")
- p = MIMEBase('application', 'octet-stream')
- p.set_payload((attachment).read())
- encoders.encode_base64(p)
-
- p.add_header('Content-Disposition', "attachment; filename=%s" % "GardenLog.txt")
- message.attach(p)
- except Exception as e:
- logging.warn("There was an error opening attachment.")
- logging.warn(e)
- finally:
- attachment.close()
-
- # Record the MIME types of both parts - text/plain and text/html.
- part1 = MIMEText(text, 'plain')
- part2 = MIMEText(html, 'html')
-
- # Attach parts into message container.
- # According to RFC 2046, the last part of a multipart message, in this case
- # the HTML message, is best and preferred.
- message.attach(part1)
- message.attach(part2)
-
- # Create a secure SSL context
- context = ssl.create_default_context()
- with smtplib.SMTP_SSL("smtp.gmail.com", port) as server:
- server.login("raspberry.pi.taffe@gmail.com", password)
- server.sendmail(sender_email, receiver_email, message.as_string())
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.mime.base import MIMEBase
+from email.utils import formatdate
+from email import encoders
+from datetime import datetime
+from datetime import timedelta
+import smtplib, ssl
+import logging
+
+def send_email():
+ port = 465 # For SSL
+ password = "al.EX.91.27"
+ sender_email = "raspberry.pi.taffe@gmail.com"
+ receiver_email = "taffeAlexander@gmail.com"
+ message = MIMEMultipart("alternative")
+ message["Subject"] = "Garden update: " + formatdate(localtime=True)
+ message["From"] = sender_email
+ message["To"] = receiver_email
+ message["Date"] = formatdate(localtime=True)
+ soilMoisture = "No Data"
+ soilTimeStamp = "No Data"
+ soilIterator = 0
+ soilMoistureArray = []
+ soilTimeStampArray = []
+ currentYMD = str(datetime.now()).split()[0]
+
+ # Create the body of the message (a plain-text and an HTML version).
+ text = "Garden update plan text"
+
+ try:
+ html = """\
+
+
+
+
+
+ Garden Update
+
+
+ | Sunlight |
+ TimeStamp |
+ Soil Moisture |
+ TimeStamp |
+
+ """
+ soilLogArray = []
+ with open("/home/pi/Desktop/smartGarden/smartGarden/logs/soilLog.txt", "r") as fp2:
+ for count, line in enumerate(fp2):
+ soilLogArray.append(line)
+
+ for line in soilLogArray:
+ try:
+ splitLine = line.split()
+ if (currentYMD == splitLine[4]) and (len(splitLine) > 5):
+ soilMoistureArray.append(splitLine[3])
+ soilTimeStampArray.append(splitLine[4] + " " + splitLine[5])
+ except Exception as e:
+ logging.warn("Unable to parse soil moisture or time stamp for email")
+ logging.warn(e)
+ print("Error parsing soil log: " + str(e))
+
+ with open("/home/pi/Desktop/smartGarden/smartGarden/logs/sunlightLog.txt", "r") as fp:
+ for cnt, line in enumerate(fp):
+ lineArray = line.split()
+ highlightedRow = ""
+ regularRow = " | "
+ greyRow = " | "
+
+ if currentYMD == lineArray[3] or currentYMD == lineArray[4]:
+ if soilIterator < len(soilMoistureArray):
+ soilMoisture = soilMoistureArray[soilIterator]
+ soilTimeStamp = soilTimeStampArray[soilIterator]
+ soilIterator = soilIterator + 1
+ print("Setting moisture: " + soilMoisture)
+ else:
+ soilMoisture = "NO DATA"
+ soilTimeStamp = "NO DATA"
+ if cnt % 2 == 0:
+ if "YES" in lineArray[0]:
+ row = " | " + highlightedRow + lineArray[0] + " " + lineArray[1] + ""
+ else:
+ row = "
" + regularRow + lineArray[0] + " " + lineArray[1] + ""
+
+ row = row + regularRow + lineArray[3] + " " + lineArray[4]+ ""
+ row = row + regularRow + soilMoisture +"%"
+ row = row + regularRow + soilTimeStamp + "
"
+ else:
+ if "YES" in lineArray[0]:
+ row = "" + highlightedRow + lineArray[0] + " " + lineArray[1] + ""
+ else:
+ row = "
" + greyRow + lineArray[0] + " " + lineArray[1] + ""
+ row = row + greyRow + lineArray[3] + " " + lineArray[4]+ ""
+ row = row + greyRow + soilMoisture + "%"
+ row = row + greyRow + soilTimeStamp + "
"
+ html = html + row
+ elif currentYMD == lineArray[4]:
+ if cnt % 2 == 0:
+ if "YES" in lineArray[0]:
+ row = "" + highlightedRow + lineArray[0] + " " + lineArray[1] + " " + lineArray[2] + ""
+ else:
+ row = "
" + regularRow + lineArray[0] + " " + lineArray[1] + ""
+ row = row + regularRow + lineArray[4] + " " + lineArray[5]+ ""
+ row = row + regularRow + soilMoisture + "%"
+ row = row + regularRow + soilTimeStamp + "
"
+ else:
+ if "YES" in lineArray[0]:
+ row = "" + highlightedRow + lineArray[0] + " " + lineArray[1] + " " + lineArray[2] + ""
+ else:
+ row = "
" + greyRow + lineArray[0] + " " + lineArray[1] + ""
+ row = row + greyRow + lineArray[4] + " " + lineArray[5]+ ""
+ row = row + greyRow + soilMoisture + "%"
+ row = row + greyRow + soilTimeStamp + "
"
+ html = html + row
+ html = html + """\
+
+
+
+ """
+ except Exception as e:
+ logging.warn("There was an error reading html file. Defaulting to basic html page")
+ html = """\
+
+
+
+ Garden Update
+
+
+ """
+ logging.warn(e)
+ print("Error sending email: " + str(e))
+
+ try:
+ #Open the file to be sent
+ attachment = open("/home/pi/Desktop/smartGarden/smartGarden/logs/smartGardenLog.txt", "rb")
+ p = MIMEBase('application', 'octet-stream')
+ p.set_payload((attachment).read())
+ encoders.encode_base64(p)
+
+ p.add_header('Content-Disposition', "attachment; filename=%s" % "GardenLog.txt")
+ message.attach(p)
+ except Exception as e:
+ logging.warn("There was an error opening attachment.")
+ logging.warn(e)
+ finally:
+ attachment.close()
+
+ # Record the MIME types of both parts - text/plain and text/html.
+ part1 = MIMEText(text, 'plain')
+ part2 = MIMEText(html, 'html')
+
+ # Attach parts into message container.
+ # According to RFC 2046, the last part of a multipart message, in this case
+ # the HTML message, is best and preferred.
+ message.attach(part1)
+ message.attach(part2)
+
+ # Create a secure SSL context
+ context = ssl.create_default_context()
+ with smtplib.SMTP_SSL("smtp.gmail.com", port) as server:
+ server.login("raspberry.pi.taffe@gmail.com", password)
+ server.sendmail(sender_email, receiver_email, message.as_string())
logging.info("Email Sent "+ str(datetime.now()))
\ No newline at end of file
diff --git a/ModuleTests/GardenModules/gardenServer/gardenServer.py b/Tests/GardenModules/gardenServer/gardenServer.py
similarity index 100%
rename from ModuleTests/GardenModules/gardenServer/gardenServer.py
rename to Tests/GardenModules/gardenServer/gardenServer.py
diff --git a/ModuleTests/GardenModules/luxSensor/luxSensor.py b/Tests/GardenModules/luxSensor/luxSensor.py
similarity index 96%
rename from ModuleTests/GardenModules/luxSensor/luxSensor.py
rename to Tests/GardenModules/luxSensor/luxSensor.py
index 56d1c79..905eae8 100644
--- a/ModuleTests/GardenModules/luxSensor/luxSensor.py
+++ b/Tests/GardenModules/luxSensor/luxSensor.py
@@ -1,54 +1,54 @@
-import adafruit_tsl2561
-import busio
-import board
-import threading
-from GardenModules.GardenModule import GardenModule
-from datetime import datetime
-import csv
-import os
-
-
-class LuxSensor(GardenModule):
- def __init__(self, log, queue):
- super().__init__(queue)
- self._logging = log
- self._i2c = busio.I2C(board.SCL, board.SDA)
- self._sensor = adafruit_tsl2561.TSL2561(self._i2c)
- self._sensor.gain = 0
- self._grow_light_lux = 535
- self._lux_interval = 10
- self._data_file = "/home/pi/Desktop/smartGarden/smartGarden/ModuleTests/Data/luxData.csv"
-
- def getLux(self):
- return self._sensor.lux
-
- def isSunlight(self):
- return self._sensor.lux > self._grow_light_lux
-
- def _saveReading(self):
- if not os.path.exists(self._data_file):
- with open(self._data_file, 'w+'):
- pass
-
- with open(self._data_file, mode='a') as file:
- writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
- writer.writerow([self._sensor.lux, datetime.now()])
-
- def run(self):
- print("Starting lux sensor thread")
- timer = threading.Event()
- while not timer.wait(self._lux_interval):
- self._logging.info(self)
- print(self)
- self._saveReading()
- if self._sentinel.get(block=True):
- print("Sentinel was triggered in soil thread.")
- self._sentinel.put(True)
- self._sentinel.task_done()
- break
- self._sentinel.put(False)
- self._sentinel.task_done()
-
- def __str__(self):
- return "Current lux reading: {}".format(self.getLux())
-
+import adafruit_tsl2561
+import busio
+import board
+import threading
+from GardenModules.GardenModule import GardenModule
+from datetime import datetime
+import csv
+import os
+
+
+class LuxSensor(GardenModule):
+ def __init__(self, log, queue):
+ super().__init__(queue)
+ self._logging = log
+ self._i2c = busio.I2C(board.SCL, board.SDA)
+ self._sensor = adafruit_tsl2561.TSL2561(self._i2c)
+ self._sensor.gain = 0
+ self._grow_light_lux = 535
+ self._lux_interval = 10
+ self._data_file = "/home/pi/Desktop/smartGarden/smartGarden/ModuleTests/Data/luxData.csv"
+
+ def getLux(self):
+ return self._sensor.lux
+
+ def isSunlight(self):
+ return self._sensor.lux > self._grow_light_lux
+
+ def _saveReading(self):
+ if not os.path.exists(self._data_file):
+ with open(self._data_file, 'w+'):
+ pass
+
+ with open(self._data_file, mode='a') as file:
+ writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
+ writer.writerow([self._sensor.lux, datetime.now()])
+
+ def run(self):
+ print("Starting lux sensor thread")
+ timer = threading.Event()
+ while not timer.wait(self._lux_interval):
+ self._logging.info(self)
+ print(self)
+ self._saveReading()
+ if self._sentinel.get(block=True):
+ print("Sentinel was triggered in soil thread.")
+ self._sentinel.put(True)
+ self._sentinel.task_done()
+ break
+ self._sentinel.put(False)
+ self._sentinel.task_done()
+
+ def __str__(self):
+ return "Current lux reading: {}".format(self.getLux())
+
diff --git a/ModuleTests/GardenModules/prune/prune.py b/Tests/GardenModules/prune/prune.py
similarity index 96%
rename from ModuleTests/GardenModules/prune/prune.py
rename to Tests/GardenModules/prune/prune.py
index b4ba474..310657a 100644
--- a/ModuleTests/GardenModules/prune/prune.py
+++ b/Tests/GardenModules/prune/prune.py
@@ -1,26 +1,26 @@
-import logging
-
-def prune(file):
- lines = []
- try:
- logFile = open("/home/pi/Desktop/smartGarden/smartGarden/logs/" + file, "r")
- for line in logFile:
- lines.append(line)
- except Exception as e:
- print("Error reading log file: " + file + " for pruning")
- finally:
- logFile.close()
-
- try:
- logFile = open("/home/pi/Desktop/smartGarden/smartGarden/logs/" + file, "w")
- if len(lines) > 5000:
- # Only keep the last 5000 lines
- for x in range(5000):
- index = len(lines) - 5001 + x
- logFile.write(lines[index])
- except Exception as e:
- print("Error writing log file: " + file)
- finally:
- logFile.close()
- logging.info("Pruned Log: " + file)
+import logging
+
+def prune(file):
+ lines = []
+ try:
+ logFile = open("/home/pi/Desktop/smartGarden/smartGarden/logs/" + file, "r")
+ for line in logFile:
+ lines.append(line)
+ except Exception as e:
+ print("Error reading log file: " + file + " for pruning")
+ finally:
+ logFile.close()
+
+ try:
+ logFile = open("/home/pi/Desktop/smartGarden/smartGarden/logs/" + file, "w")
+ if len(lines) > 5000:
+ # Only keep the last 5000 lines
+ for x in range(5000):
+ index = len(lines) - 5001 + x
+ logFile.write(lines[index])
+ except Exception as e:
+ print("Error writing log file: " + file)
+ finally:
+ logFile.close()
+ logging.info("Pruned Log: " + file)
print("Pruned log: " + file)
\ No newline at end of file
diff --git a/ModuleTests/GardenModules/pump/pump.py b/Tests/GardenModules/pump/pump.py
similarity index 97%
rename from ModuleTests/GardenModules/pump/pump.py
rename to Tests/GardenModules/pump/pump.py
index 6c147ca..b218331 100644
--- a/ModuleTests/GardenModules/pump/pump.py
+++ b/Tests/GardenModules/pump/pump.py
@@ -1,91 +1,91 @@
-import RPi.GPIO as GPIO
-import time
-import threading
-from GardenModules.GardenModule import GardenModule
-from GardenModules.soilMoisture.soil import SoilMoisture
-from datetime import datetime
-
-
-class WaterPump(GardenModule):
- def __init__(self, log, queue, soil_moisture_sensor):
- super().__init__(queue)
- self.logging = log
- self._pwm = 70
- self._pin = 18
- self._pumpInterval = 60
- self.setName("pumpThread")
- self.soilMoisture = soil_moisture_sensor
-
- def _run(self, runtime=None, dutyCycle=50):
- if runtime == None:
- raise Exception("The value of run_time for the water pump was none.")
- try:
- self._setup(self._pin)
- self._togglePin(self._pin)
- p = GPIO.PWM(self._pin, self._pwm)
- p.start(dutyCycle)
- time.sleep(runtime)
- GPIO.output(self._pin, GPIO.LOW)
- p.stop()
- self.logging.info("Watered plants at: " + str(datetime.now()))
- except Exception as exception:
- self.logging.warn("There was an error watering the plants.")
- self.logging.warn(exception)
- self.logging.info(self._printWatered())
-
- def _run_sequence(self):
- self._run(10, 100)
- time.sleep(5)
- self._run(3, 70)
- time.sleep(5)
- self._run(2, 50)
-
- def run(self):
- try:
- print("Starting pump thread.")
- # self._run_sequence()
- timer = threading.Event()
- while not timer.wait(self._pumpInterval):
- if self.soilMoisture.getSoilPercentage() < 40:
- # self._run_sequence()
- print("Watering because soil moisture is at: {}\n".format(self.soilMoisture.getSoilPercentage())
- + self._printWatered())
- else:
- print("Skipping watering because soil moisture is at: {:.2f}%".format(
- self.soilMoisture.getSoilPercentage()))
- # TODO Refactor sentinel to be part of the while loop so that when it is triggered the loop ends.
- if self._sentinel.get(block=True):
- self.logging.info("Sentinel was triggered in pump thread.")
- self._sentinel.put(True)
- self._sentinel.task_done()
- break
- self._sentinel.put(False)
- self._sentinel.task_done()
- except Exception as exception:
- self.logging.info("There was an exception in the pump thread: ")
- self.logging.info(exception)
-
- def setInterval(self, interval):
- self._pumpInterval = interval
-
- def getInterval(self):
- return self._pumpInterval
-
- def _togglePin(self, pin):
- GPIO.output(pin, GPIO.HIGH)
- GPIO.output(pin, GPIO.LOW)
-
- def _setup(self, pin):
- GPIO.setmode(GPIO.BCM)
- GPIO.setup(pin, GPIO.OUT)
-
- def _printWatered(self):
- return """
- ,d
- 88
- 8b db d8 ,adPPYYba, MM88MMM ,adPPYba, 8b,dPPYba,
- `8b d88b d8' "" `Y8 88 a8P_____88 88P' "Y8
- `8b d8'`8b d8' ,adPPPPP88 88 8PP""""""" 88
- `8bd8' `8bd8' 88, ,88 88, "8b, ,aa 88
- YP YP `"8bbdP"Y8 "Y888 `"Ybbd8"' 88
- """
+import RPi.GPIO as GPIO
+import time
+import threading
+from GardenModules.GardenModule import GardenModule
+from GardenModules.soilMoisture.soil import SoilMoisture
+from datetime import datetime
+
+
+class WaterPump(GardenModule):
+ def __init__(self, log, queue, soil_moisture_sensor):
+ super().__init__(queue)
+ self.logging = log
+ self._pwm = 70
+ self._pin = 18
+ self._pumpInterval = 60
+ self.setName("pumpThread")
+ self.soilMoisture = soil_moisture_sensor
+
+ def _run(self, runtime=None, dutyCycle=50):
+ if runtime == None:
+ raise Exception("The value of run_time for the water pump was none.")
+ try:
+ self._setup(self._pin)
+ self._togglePin(self._pin)
+ p = GPIO.PWM(self._pin, self._pwm)
+ p.start(dutyCycle)
+ time.sleep(runtime)
+ GPIO.output(self._pin, GPIO.LOW)
+ p.stop()
+ self.logging.info("Watered plants at: " + str(datetime.now()))
+ except Exception as exception:
+ self.logging.warn("There was an error watering the plants.")
+ self.logging.warn(exception)
+ self.logging.info(self._printWatered())
+
+ def _run_sequence(self):
+ self._run(10, 100)
+ time.sleep(5)
+ self._run(3, 70)
+ time.sleep(5)
+ self._run(2, 50)
+
+ def run(self):
+ try:
+ print("Starting pump thread.")
+ # self._run_sequence()
+ timer = threading.Event()
+ while not timer.wait(self._pumpInterval):
+ if self.soilMoisture.getSoilPercentage() < 40:
+ # self._run_sequence()
+ print("Watering because soil moisture is at: {}\n".format(self.soilMoisture.getSoilPercentage())
+ + self._printWatered())
+ else:
+ print("Skipping watering because soil moisture is at: {:.2f}%".format(
+ self.soilMoisture.getSoilPercentage()))
+ # TODO Refactor sentinel to be part of the while loop so that when it is triggered the loop ends.
+ if self._sentinel.get(block=True):
+ self.logging.info("Sentinel was triggered in pump thread.")
+ self._sentinel.put(True)
+ self._sentinel.task_done()
+ break
+ self._sentinel.put(False)
+ self._sentinel.task_done()
+ except Exception as exception:
+ self.logging.info("There was an exception in the pump thread: ")
+ self.logging.info(exception)
+
+ def setInterval(self, interval):
+ self._pumpInterval = interval
+
+ def getInterval(self):
+ return self._pumpInterval
+
+ def _togglePin(self, pin):
+ GPIO.output(pin, GPIO.HIGH)
+ GPIO.output(pin, GPIO.LOW)
+
+ def _setup(self, pin):
+ GPIO.setmode(GPIO.BCM)
+ GPIO.setup(pin, GPIO.OUT)
+
+ def _printWatered(self):
+ return """
+ ,d
+ 88
+ 8b db d8 ,adPPYYba, MM88MMM ,adPPYba, 8b,dPPYba,
+ `8b d88b d8' "" `Y8 88 a8P_____88 88P' "Y8
+ `8b d8'`8b d8' ,adPPPPP88 88 8PP""""""" 88
+ `8bd8' `8bd8' 88, ,88 88, "8b, ,aa 88
+ YP YP `"8bbdP"Y8 "Y888 `"Ybbd8"' 88
+ """
diff --git a/ModuleTests/GardenModules/soilMoisture/soil.py b/Tests/GardenModules/soilMoisture/soil.py
similarity index 97%
rename from ModuleTests/GardenModules/soilMoisture/soil.py
rename to Tests/GardenModules/soilMoisture/soil.py
index 25775ec..434af72 100644
--- a/ModuleTests/GardenModules/soilMoisture/soil.py
+++ b/Tests/GardenModules/soilMoisture/soil.py
@@ -1,76 +1,76 @@
-import board
-import busio
-import adafruit_ads1x15.ads1115 as ADS
-import threading
-from adafruit_ads1x15.analog_in import AnalogIn
-from GardenModules.GardenModule import GardenModule
-from datetime import datetime
-from queue import Queue
-
-
-class SoilMoisture(GardenModule):
- def __init__(self, log, queue):
- super().__init__(queue)
- self.log = log
- self._i2c = busio.I2C(board.SCL, board.SDA)
- self._ads = ADS.ADS1115(self._i2c)
- self._ads.gain = 1
- self.channel = AnalogIn(self._ads, ADS.P0)
- self.soilInterval = 1800 # 1800
- self.log.info("Channel: " + str(self.channel))
- self.setName("soilThread")
-
- # Set Gain to 16 bits
- # Gain = 1 # Wet: 13884 Dry: 21680
- # Gain = 2/3 # Wet: 11031 Dry: 14989
- self.queue = Queue()
- self.sum = 0
- self.window_size = 5
- self.percentage = 0
- self.average_soil_value = 0
- for x in range(0,5):
- self._checkSoil()
- def _checkSoil(self):
- try:
- # I am using a moving average to remove sensor noise.
- value = self.channel.value
- if self.queue.qsize() >= self.window_size:
- self.sum += value
- self.sum -= self.queue.get()
- self.average_soil_value = self.sum / self.window_size
- self.percentage = ((self.sum / self.window_size) / 21680) * 100
- self.log.info("Soil Moisture Level: {} | Averaged Value: {:.2f}%".format(self.sum / self.window_size, self.getSoilPercentage()))
- print("Soil Moisture Level: {} | Averaged Value: {:.2f}%".format(self.sum / self.window_size, self.getSoilPercentage()))
- else:
- self.queue.put(value)
- self.sum += value
-
- except Exception as exception:
- self.log.exception("Error calculating soil moisture")
-
- try:
- with open("/home/pi/Desktop/smartGarden/smartGarden/logs/soilLog.txt", "a+") as logFile:
- logFile.write("Soil Moisture Level: " + str(self.getSoilPercentage()) + "% " + str(
- datetime.now()) + " Raw Value: " + str(self.channel.value) + "\n")
- except Exception as exception:
- self.log.exception("Error writing soil moisture level")
-
- def run(self):
- self._checkSoil()
- timer = threading.Event()
- while not timer.wait(self.soilInterval):
- self._checkSoil()
- # TODO create a function for the sentinel
- if self._sentinel.get(block=True):
- print("Sentinel was triggered in soil thread.")
- self._sentinel.put(True)
- self._sentinel.task_done()
- break
- self._sentinel.put(False)
- self._sentinel.task_done()
-
- def getSoilPercentage(self):
- return 100 - self.percentage
-
- def getSoilValue(self):
- return self.sum / self.window_size
+import board
+import busio
+import adafruit_ads1x15.ads1115 as ADS
+import threading
+from adafruit_ads1x15.analog_in import AnalogIn
+from GardenModules.GardenModule import GardenModule
+from datetime import datetime
+from queue import Queue
+
+
+class SoilMoisture(GardenModule):
+ def __init__(self, log, queue):
+ super().__init__(queue)
+ self.log = log
+ self._i2c = busio.I2C(board.SCL, board.SDA)
+ self._ads = ADS.ADS1115(self._i2c)
+ self._ads.gain = 1
+ self.channel = AnalogIn(self._ads, ADS.P0)
+ self.soilInterval = 1800 # 1800
+ self.log.info("Channel: " + str(self.channel))
+ self.setName("soilThread")
+
+ # Set Gain to 16 bits
+ # Gain = 1 # Wet: 13884 Dry: 21680
+ # Gain = 2/3 # Wet: 11031 Dry: 14989
+ self.queue = Queue()
+ self.sum = 0
+ self.window_size = 5
+ self.percentage = 0
+ self.average_soil_value = 0
+ for x in range(0,5):
+ self._checkSoil()
+ def _checkSoil(self):
+ try:
+ # I am using a moving average to remove sensor noise.
+ value = self.channel.value
+ if self.queue.qsize() >= self.window_size:
+ self.sum += value
+ self.sum -= self.queue.get()
+ self.average_soil_value = self.sum / self.window_size
+ self.percentage = ((self.sum / self.window_size) / 21680) * 100
+ self.log.info("Soil Moisture Level: {} | Averaged Value: {:.2f}%".format(self.sum / self.window_size, self.getSoilPercentage()))
+ print("Soil Moisture Level: {} | Averaged Value: {:.2f}%".format(self.sum / self.window_size, self.getSoilPercentage()))
+ else:
+ self.queue.put(value)
+ self.sum += value
+
+ except Exception as exception:
+ self.log.exception("Error calculating soil moisture")
+
+ try:
+ with open("/home/pi/Desktop/smartGarden/smartGarden/logs/soilLog.txt", "a+") as logFile:
+ logFile.write("Soil Moisture Level: " + str(self.getSoilPercentage()) + "% " + str(
+ datetime.now()) + " Raw Value: " + str(self.channel.value) + "\n")
+ except Exception as exception:
+ self.log.exception("Error writing soil moisture level")
+
+ def run(self):
+ self._checkSoil()
+ timer = threading.Event()
+ while not timer.wait(self.soilInterval):
+ self._checkSoil()
+ # TODO create a function for the sentinel
+ if self._sentinel.get(block=True):
+ print("Sentinel was triggered in soil thread.")
+ self._sentinel.put(True)
+ self._sentinel.task_done()
+ break
+ self._sentinel.put(False)
+ self._sentinel.task_done()
+
+ def getSoilPercentage(self):
+ return 100 - self.percentage
+
+ def getSoilValue(self):
+ return self.sum / self.window_size
diff --git a/ModuleTests/GardenModules/sunlightSensor/sunlight.py b/Tests/GardenModules/sunlightSensor/sunlight.py
similarity index 97%
rename from ModuleTests/GardenModules/sunlightSensor/sunlight.py
rename to Tests/GardenModules/sunlightSensor/sunlight.py
index d99843a..621e0fa 100644
--- a/ModuleTests/GardenModules/sunlightSensor/sunlight.py
+++ b/Tests/GardenModules/sunlightSensor/sunlight.py
@@ -1,78 +1,78 @@
-import logging
-import sqlite3
-from datetime import datetime
-from datetime import timedelta
-import RPi.GPIO as GPIO
-
-def insertSunlightRecord(message,time1, time2):
- insert_command = "INSERT INTO sunlight VALUES (\'" + message + "\',\'"+ time1 + "\',\'" + time2 + "\');"
- try:
- conn = sqlite3.connect('/home/pi/Desktop/smartGarden/smartGarden/gardenDatabase.db')
- cursor = conn.cursor()
- cursor.execute(insert_command)
- conn.commit()
- logging.info("Inserted sunlight record")
- return cursor.lastrowid
- except Exception as e:
- logging.warn(e)
- finally:
- conn.close()
-
-def prune():
- time = datetime.now()
- pruneDate = str(time - timedelta(days=30)).split()
-
- delete_command = "DELETE FROM sunlight WHERE record_timestamp LIKE '" + pruneDate[0] + "%';"
- #select_command = "SELECT * FROM sunlight WHERE record_timestamp LIKE '" + pruneDate[0] + "%';"
- #print("Prune Date: " + str(pruneDate))
- try:
- conn = sqlite3.connect('/home/pi/Desktop/smartGarden/smartGarden/gardenDatabase.db')
- cursor = conn.cursor()
- cursor.execute(delete_command)
- conn.commit()
- except Exception as e:
- print("Error: " + str(e))
- finally:
- conn.close()
-
-
-def check_sunlight():
- artificialLightHours = False
- f = None
- try:
- GPIO.setmode(GPIO.BCM)
- GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
- f = open("/home/pi/Desktop/smartGarden/smartGarden/logs/sunlightLog.txt", "a+")
- time = datetime.now()
- dateTimeString = str(time)
- cleanDateString = str(time + timedelta(days=30))
- currentTimeStamp = str(datetime.now()).split()[1]
- currentHour = currentTimeStamp.split(':')[0]
- hourAsInt = int(currentHour)
-
- if hourAsInt >= 18:
- f.write("YES Artificial Sunlight at: " + dateTimeString + "\n")
- insertSunlightRecord("YES Artificial Sunlight",dateTimeString,cleanDateString)
- artificialLightHours = True
- logging.info("Checked artificial sunlight")
- if hourAsInt >=6 and hourAsInt <= 12:
- f.write("YES Artificial Sunlight at: " + dateTimeString + "\n")
- insertSunlightRecord("YES Artificial Sunlight",dateTimeString,cleanDateString)
- artificialLightHours = True
- logging.info("Checked artificial sunlight")
-
- if not artificialLightHours:
- if not GPIO.input(4):
- f.write("YES Natural Sunlight at: " + dateTimeString + "\n")
- insertSunlightRecord("Yes Sunlight",dateTimeString,cleanDateString)
- logging.info("Checked natural sunlight")
- else:
- f.write("NO Sunlight at: " + dateTimeString + "\n")
- insertSunlightRecord("No Sunlight", dateTimeString, cleanDateString)
- logging.info("Checked natural sunlight")
- except Exception as e:
- logging.warn("There was an error writing to file.")
- logging.warn(e)
- finally:
- f.close()
-
+import logging
+import sqlite3
+from datetime import datetime
+from datetime import timedelta
+import RPi.GPIO as GPIO
+
+def insertSunlightRecord(message,time1, time2):
+ insert_command = "INSERT INTO sunlight VALUES (\'" + message + "\',\'"+ time1 + "\',\'" + time2 + "\');"
+ try:
+ conn = sqlite3.connect('/home/pi/Desktop/smartGarden/smartGarden/gardenDatabase.db')
+ cursor = conn.cursor()
+ cursor.execute(insert_command)
+ conn.commit()
+ logging.info("Inserted sunlight record")
+ return cursor.lastrowid
+ except Exception as e:
+ logging.warn(e)
+ finally:
+ conn.close()
+
+def prune():
+ time = datetime.now()
+ pruneDate = str(time - timedelta(days=30)).split()
+
+ delete_command = "DELETE FROM sunlight WHERE record_timestamp LIKE '" + pruneDate[0] + "%';"
+ #select_command = "SELECT * FROM sunlight WHERE record_timestamp LIKE '" + pruneDate[0] + "%';"
+ #print("Prune Date: " + str(pruneDate))
+ try:
+ conn = sqlite3.connect('/home/pi/Desktop/smartGarden/smartGarden/gardenDatabase.db')
+ cursor = conn.cursor()
+ cursor.execute(delete_command)
+ conn.commit()
+ except Exception as e:
+ print("Error: " + str(e))
+ finally:
+ conn.close()
+
+
+def check_sunlight():
+ artificialLightHours = False
+ f = None
+ try:
+ GPIO.setmode(GPIO.BCM)
+ GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
+ f = open("/home/pi/Desktop/smartGarden/smartGarden/logs/sunlightLog.txt", "a+")
+ time = datetime.now()
+ dateTimeString = str(time)
+ cleanDateString = str(time + timedelta(days=30))
+ currentTimeStamp = str(datetime.now()).split()[1]
+ currentHour = currentTimeStamp.split(':')[0]
+ hourAsInt = int(currentHour)
+
+ if hourAsInt >= 18:
+ f.write("YES Artificial Sunlight at: " + dateTimeString + "\n")
+ insertSunlightRecord("YES Artificial Sunlight",dateTimeString,cleanDateString)
+ artificialLightHours = True
+ logging.info("Checked artificial sunlight")
+ if hourAsInt >=6 and hourAsInt <= 12:
+ f.write("YES Artificial Sunlight at: " + dateTimeString + "\n")
+ insertSunlightRecord("YES Artificial Sunlight",dateTimeString,cleanDateString)
+ artificialLightHours = True
+ logging.info("Checked artificial sunlight")
+
+ if not artificialLightHours:
+ if not GPIO.input(4):
+ f.write("YES Natural Sunlight at: " + dateTimeString + "\n")
+ insertSunlightRecord("Yes Sunlight",dateTimeString,cleanDateString)
+ logging.info("Checked natural sunlight")
+ else:
+ f.write("NO Sunlight at: " + dateTimeString + "\n")
+ insertSunlightRecord("No Sunlight", dateTimeString, cleanDateString)
+ logging.info("Checked natural sunlight")
+ except Exception as e:
+ logging.warn("There was an error writing to file.")
+ logging.warn(e)
+ finally:
+ f.close()
+
diff --git a/Tests/README.md b/Tests/README.md
new file mode 100644
index 0000000..d6e2759
--- /dev/null
+++ b/Tests/README.md
@@ -0,0 +1,3 @@
+# Module Tests
+
+This folder is used to test new modules or just anything to do with the garden.
\ No newline at end of file
diff --git a/test/alex.txt b/Tests/alex.txt
similarity index 100%
rename from test/alex.txt
rename to Tests/alex.txt
diff --git a/test/artificial_light_test.py b/Tests/artificial_light_test.py
similarity index 100%
rename from test/artificial_light_test.py
rename to Tests/artificial_light_test.py
diff --git a/test/camera_test.py b/Tests/camera_test.py
similarity index 100%
rename from test/camera_test.py
rename to Tests/camera_test.py
diff --git a/test/database_test.py b/Tests/database_test.py
similarity index 100%
rename from test/database_test.py
rename to Tests/database_test.py
diff --git a/test/email_desktop.py b/Tests/email_desktop.py
similarity index 100%
rename from test/email_desktop.py
rename to Tests/email_desktop.py
diff --git a/test/email_test.py b/Tests/email_test.py
similarity index 100%
rename from test/email_test.py
rename to Tests/email_test.py
diff --git a/test/i2c-test.py b/Tests/i2c-test.py
similarity index 96%
rename from test/i2c-test.py
rename to Tests/i2c-test.py
index 179dacb..599e29c 100644
--- a/test/i2c-test.py
+++ b/Tests/i2c-test.py
@@ -1,20 +1,20 @@
-import board
-import busio
-import adafruit_ads1x15.ads1115 as ADS
-from adafruit_ads1x15.analog_in import AnalogIn
-import time
-
-i2c = busio.I2C(board.SCL, board.SDA)
-# Soil moisture is address 0x4a
-# Light is address 48
-soil_ads = ADS.ADS1115(i2c, address=0x4a)
-
-light_ads = ADS.ADS1115(i2c)
-light_ads.gain = 2/3
-chan1 = AnalogIn(soil_ads, ADS.P0)
-chan2 = AnalogIn(light_ads, ADS.P0)
-
-while(True):
- #print("soil value: " + str(chan1.value) + " soil voltage: " + str(chan1.voltage))
- print("light value: " + str(chan2.value) + " light voltage: " + str(chan2.voltage))
+import board
+import busio
+import adafruit_ads1x15.ads1115 as ADS
+from adafruit_ads1x15.analog_in import AnalogIn
+import time
+
+i2c = busio.I2C(board.SCL, board.SDA)
+# Soil moisture is address 0x4a
+# Light is address 48
+soil_ads = ADS.ADS1115(i2c, address=0x4a)
+
+light_ads = ADS.ADS1115(i2c)
+light_ads.gain = 2/3
+chan1 = AnalogIn(soil_ads, ADS.P0)
+chan2 = AnalogIn(light_ads, ADS.P0)
+
+while(True):
+ #print("soil value: " + str(chan1.value) + " soil voltage: " + str(chan1.voltage))
+ print("light value: " + str(chan2.value) + " light voltage: " + str(chan2.voltage))
time.sleep(1)
\ No newline at end of file
diff --git a/test/image.jpeg b/Tests/image.jpeg
similarity index 100%
rename from test/image.jpeg
rename to Tests/image.jpeg
diff --git a/test/lightTest.py b/Tests/lightTest.py
similarity index 100%
rename from test/lightTest.py
rename to Tests/lightTest.py
diff --git a/test/light_sensor_test.py b/Tests/light_sensor_test.py
similarity index 96%
rename from test/light_sensor_test.py
rename to Tests/light_sensor_test.py
index bd74ff7..69d8133 100644
--- a/test/light_sensor_test.py
+++ b/Tests/light_sensor_test.py
@@ -1,16 +1,16 @@
-import board
-import busio
-import adafruit_tsl2561
-import time
-
-i2c = busio.I2C(board.SCL, board.SDA)
-sensor = adafruit_tsl2561.TSL2561(i2c)
-sensor.gain = 0
-
-while True:
- print('Lux: {}'.format(sensor.lux))
- print('Broadband: {}'.format(sensor.broadband))
- print('Infrared: {}'.format(sensor.infrared))
- print('gain: {}'.format(sensor.gain))
- print('Luminosity: {}\n'.format(sensor.luminosity))
- time.sleep(1)
+import board
+import busio
+import adafruit_tsl2561
+import time
+
+i2c = busio.I2C(board.SCL, board.SDA)
+sensor = adafruit_tsl2561.TSL2561(i2c)
+sensor.gain = 0
+
+while True:
+ print('Lux: {}'.format(sensor.lux))
+ print('Broadband: {}'.format(sensor.broadband))
+ print('Infrared: {}'.format(sensor.infrared))
+ print('gain: {}'.format(sensor.gain))
+ print('Luminosity: {}\n'.format(sensor.luminosity))
+ time.sleep(1)
diff --git a/ModuleTests/luxTest.py b/Tests/luxTest.py
similarity index 95%
rename from ModuleTests/luxTest.py
rename to Tests/luxTest.py
index a24e660..0500e32 100644
--- a/ModuleTests/luxTest.py
+++ b/Tests/luxTest.py
@@ -1,21 +1,21 @@
-import logging
-import queue
-
-from GardenModules.luxSensor.luxSensor import LuxSensor
-
-logging.basicConfig(filename="testLog.log", level=logging.INFO)
-sentinel = queue.Queue()
-sentinel.put(False)
-
-sensor = LuxSensor(logging, sentinel)
-sensor.start()
-
-while True:
- try:
- pass
- except KeyboardInterrupt:
- sentinel.put(True)
- print("Ending test")
- break
-
-sensor.join()
+import logging
+import queue
+
+from GardenModules.luxSensor.luxSensor import LuxSensor
+
+logging.basicConfig(filename="testLog.log", level=logging.INFO)
+sentinel = queue.Queue()
+sentinel.put(False)
+
+sensor = LuxSensor(logging, sentinel)
+sensor.start()
+
+while True:
+ try:
+ pass
+ except KeyboardInterrupt:
+ sentinel.put(True)
+ print("Ending test")
+ break
+
+sensor.join()
diff --git a/test/modules/soilMoisture/soil.py b/Tests/modules/soilMoisture/soil.py
similarity index 96%
rename from test/modules/soilMoisture/soil.py
rename to Tests/modules/soilMoisture/soil.py
index fb4ce22..cc85195 100644
--- a/test/modules/soilMoisture/soil.py
+++ b/Tests/modules/soilMoisture/soil.py
@@ -1,83 +1,83 @@
-import board
-import busio
-import adafruit_ads1x15.ads1115 as ADS
-from adafruit_ads1x15.analog_in import AnalogIn
-import sys
-import time
-import keyboard
-from queue import Queue
-
-i2c = busio.I2C(board.SCL, board.SDA)
-print("i2c configured")
-ads = ADS.ADS1115(i2c, address=0x48)
-ads.gain = 1
-print("ADS configured with gain: " + str(ads.gain))
-chan = AnalogIn(ads, ADS.P0)
-
-def test_min_max():
- min_value = sys.maxsize
- max_value = -sys.maxsize
- try:
- while True:
- value = chan.value
- voltage = chan.voltage
- max_value = max([value, int(max_value)])
- min_value = min([value, int(min_value)])
- print("value: {}\nvoltage: {}\nmin: {}\nmax: {}\n".format(value,voltage, min_value, max_value))
- time.sleep(0.5)
- except KeyboardInterrupt:
- print("\nfinal min: {}\n final max: {}".format(min_value, max_value))
-
-def test_soil_moving_avg():
- window_size = int(input("Please input the window size: "))
- sum = 0
- buffer = Queue()
- while True:
- value = chan.value
- try:
- if buffer.qsize() >= window_size:
- sum += value
- sum -= buffer.get()
- percentage = ((sum / window_size) / 21680) * 100
- print("Moisture level: {}\n percentage: {:.2f}".format(sum/window_size, percentage))
- buffer.put(value)
- time.sleep(0.2)
- else:
- buffer.put(value)
- sum += value
-
- if keyboard.is_pressed('q'):
- print("Exiting...")
- sys.exit()
- except Exception as e:
- print(e)
- break
-
-def test_soil():
-
- lowest = chan.value
- highest = lowest
- min = 1061
- max = 14667
- started = False
- weight = 40
- valInt = 0
- while True:
- if started:
- rawVal = chan.value
- val = (rawVal - min) / (max - min)
- val = val * 100
- newValInt = round(val, 5)
- rawVal = (weight * newValInt) + ((1 - weight) * valInt)
- else:
- rawVal = chan.value
- #Normalization
- val = (rawVal - min) / (max - min)
- #Convert to a percentage
- val = val * 100
- valInt = round(val, 5)
-
- print("Voltage: " + str(chan.voltage) + "\t\tValue: " + str(chan.value))
-
- if not started:
- started = True
+import board
+import busio
+import adafruit_ads1x15.ads1115 as ADS
+from adafruit_ads1x15.analog_in import AnalogIn
+import sys
+import time
+import keyboard
+from queue import Queue
+
+i2c = busio.I2C(board.SCL, board.SDA)
+print("i2c configured")
+ads = ADS.ADS1115(i2c, address=0x48)
+ads.gain = 1
+print("ADS configured with gain: " + str(ads.gain))
+chan = AnalogIn(ads, ADS.P0)
+
+def test_min_max():
+ min_value = sys.maxsize
+ max_value = -sys.maxsize
+ try:
+ while True:
+ value = chan.value
+ voltage = chan.voltage
+ max_value = max([value, int(max_value)])
+ min_value = min([value, int(min_value)])
+ print("value: {}\nvoltage: {}\nmin: {}\nmax: {}\n".format(value,voltage, min_value, max_value))
+ time.sleep(0.5)
+ except KeyboardInterrupt:
+ print("\nfinal min: {}\n final max: {}".format(min_value, max_value))
+
+def test_soil_moving_avg():
+ window_size = int(input("Please input the window size: "))
+ sum = 0
+ buffer = Queue()
+ while True:
+ value = chan.value
+ try:
+ if buffer.qsize() >= window_size:
+ sum += value
+ sum -= buffer.get()
+ percentage = ((sum / window_size) / 21680) * 100
+ print("Moisture level: {}\n percentage: {:.2f}".format(sum/window_size, percentage))
+ buffer.put(value)
+ time.sleep(0.2)
+ else:
+ buffer.put(value)
+ sum += value
+
+ if keyboard.is_pressed('q'):
+ print("Exiting...")
+ sys.exit()
+ except Exception as e:
+ print(e)
+ break
+
+def test_soil():
+
+ lowest = chan.value
+ highest = lowest
+ min = 1061
+ max = 14667
+ started = False
+ weight = 40
+ valInt = 0
+ while True:
+ if started:
+ rawVal = chan.value
+ val = (rawVal - min) / (max - min)
+ val = val * 100
+ newValInt = round(val, 5)
+ rawVal = (weight * newValInt) + ((1 - weight) * valInt)
+ else:
+ rawVal = chan.value
+ #Normalization
+ val = (rawVal - min) / (max - min)
+ #Convert to a percentage
+ val = val * 100
+ valInt = round(val, 5)
+
+ print("Voltage: " + str(chan.voltage) + "\t\tValue: " + str(chan.value))
+
+ if not started:
+ started = True
diff --git a/test/opencv_test.py b/Tests/opencv_test.py
similarity index 94%
rename from test/opencv_test.py
rename to Tests/opencv_test.py
index e4ef9a9..2971d2e 100644
--- a/test/opencv_test.py
+++ b/Tests/opencv_test.py
@@ -1,15 +1,15 @@
-import cv2
-
-vid_cap = cv2.VideoCapture(0)
-vid_cap.set(3, 1280)
-vid_cap.set(4, 720)
-
-if not vid_cap.isOpened():
- raise Exception("could not open video device")
-
-for x in range(10):
- ret, frame = vid_cap.read()
-
-cv2.imwrite("test.jpg", frame)
-
+import cv2
+
+vid_cap = cv2.VideoCapture(0)
+vid_cap.set(3, 1280)
+vid_cap.set(4, 720)
+
+if not vid_cap.isOpened():
+ raise Exception("could not open video device")
+
+for x in range(10):
+ ret, frame = vid_cap.read()
+
+cv2.imwrite("test.jpg", frame)
+
vid_cap.release()
\ No newline at end of file
diff --git a/test/pump.py b/Tests/pump.py
similarity index 100%
rename from test/pump.py
rename to Tests/pump.py
diff --git a/ModuleTests/pumpTest.py b/Tests/pumpTest.py
similarity index 95%
rename from ModuleTests/pumpTest.py
rename to Tests/pumpTest.py
index 3154bfe..9599473 100644
--- a/ModuleTests/pumpTest.py
+++ b/Tests/pumpTest.py
@@ -1,25 +1,25 @@
-import queue
-import logging
-
-from GardenModules.pump.pump import WaterPump
-from GardenModules.soilMoisture.soil import SoilMoisture
-
-logging.basicConfig(filename="testLog.log", level=logging.INFO)
-sentinel = queue.Queue()
-sentinel.put(False)
-
-soilMoistureSensor = SoilMoisture(logging, sentinel)
-pump = WaterPump(logging, sentinel, soilMoistureSensor)
-
-soilMoistureSensor.start()
-pump.start()
-
-while True:
- try:
- pass
- except KeyboardInterrupt:
- sentinel.put(True)
- print("Ending test")
- break
-
-pump.join()
+import queue
+import logging
+
+from GardenModules.pump.pump import WaterPump
+from GardenModules.soilMoisture.soil import SoilMoisture
+
+logging.basicConfig(filename="testLog.log", level=logging.INFO)
+sentinel = queue.Queue()
+sentinel.put(False)
+
+soilMoistureSensor = SoilMoisture(logging, sentinel)
+pump = WaterPump(logging, sentinel, soilMoistureSensor)
+
+soilMoistureSensor.start()
+pump.start()
+
+while True:
+ try:
+ pass
+ except KeyboardInterrupt:
+ sentinel.put(True)
+ print("Ending test")
+ break
+
+pump.join()
diff --git a/test/soil_test.py b/Tests/soil_test.py
similarity index 100%
rename from test/soil_test.py
rename to Tests/soil_test.py
diff --git a/test/sunlightLog.txt b/Tests/sunlightLog.txt
similarity index 100%
rename from test/sunlightLog.txt
rename to Tests/sunlightLog.txt
diff --git a/test/tempSensor.py b/Tests/tempSensor.py
similarity index 100%
rename from test/tempSensor.py
rename to Tests/tempSensor.py
diff --git a/test/test.jpg b/Tests/test.jpg
similarity index 100%
rename from test/test.jpg
rename to Tests/test.jpg
diff --git a/build_table.py b/build_table.py
deleted file mode 100644
index 2c9e865..0000000
--- a/build_table.py
+++ /dev/null
@@ -1,106 +0,0 @@
-def build_table(ymd):
- soilLogArray = []
- with open("/home/pi/Desktop/smartGarden/smartGarden/soilLog.txt", "r") as fp2:
- for count, line in enumerate(fp2):
- soilLogArray.append(line)
-
- with open("/home/pi/Desktop/smartGarden/smartGarden/sunlightLog.txt", "r") as fp:
- for cnt, line in enumerate(fp):
- lineArray = line.split()
- currentYMD = str(datetime.now()).split()[0]
- soilMoisture = "No Data"
- soilTimeStamp = "No Data"
- if cnt < len(soilLogArray):
- try:
- splitLine = soilLogArray[cnt].split()
- soilMoisture = splitLine[3]
- soilTimeStamp = splitLine[4] + " " + splitLine[5]
- print("soilMoisture: " + soilMoisture)
- print("soil time stamp: " + soilTimeStamp)
- except Exception as e:
- logging.warn("Unable to parse soil moisture or time stamp for email.")
- logging.warn(e)
-
- if currentYMD == lineArray[3]:
- if cnt % 2 == 0:
- if "YES" in lineArray[0]:
- row = "| " + lineArray[0] + " " + lineArray[1] + " | "
- else:
- row = "
| " + lineArray[0] + " " + lineArray[1] + " | "
-
- row = row + "" + lineArray[3] + " " + lineArray[4]+ " | "
- row = row + "" + soilMoisture + " | "
- row = row + "" + soilTimeStamp + " |
"
- else:
- if "YES" in lineArray[0]:
- row = "| " + lineArray[0] + " " + lineArray[1] + " | "
- else:
- row = "
| " + lineArray[0] + " " + lineArray[1] + " | "
- row = row + "" + lineArray[3] + " " + lineArray[4]+ " | "
- row = row + "" + soilMoisture + " | "
- row = row + "" + soilTimeStamp + " |
"
- html = html + row
- elif currentYMD == lineArray[4]:
- if cnt % 2 == 0:
- if "YES" in lineArray[0]:
- row = "| " + lineArray[0] + " " + lineArray[1] + " " + lineArray[2] + " | "
- else:
- row = "
| " + lineArray[0] + " " + lineArray[1] + " | "
- row = row + "" + lineArray[4] + " " + lineArray[5]+ " | "
- row = row + "" + soilMoisture + " | "
- row = row + "" + soilTimeStamp + " |
"
- else:
- if "YES" in lineArray[0]:
- row = "| " + lineArray[0] + " " + lineArray[1] + " " + lineArray[2] + " | "
- else:
- row = "
| " + lineArray[0] + " " + lineArray[1] + " | "
- row = row + "" + lineArray[4] + " " + lineArray[5]+ " | "
- row = row + "" + soilMoisture + " | "
- row = row + "" + soilTimeStamp + " |
"
- html = html + row
- html = html + """\
-
-