Compare commits
11 Commits
b1782a703c
...
dd33a33f1f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd33a33f1f | ||
|
|
a0ea4c743d | ||
|
|
ec287ae047 | ||
|
|
f53a5183bc | ||
|
|
69a3e06dfc | ||
|
|
86394d8b5f | ||
|
|
7b57a8b793 | ||
|
|
954a38fa46 | ||
|
|
f7aa608ae7 | ||
|
|
11a1477d6c | ||
|
|
9f3da5e663 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -138,3 +138,5 @@ dmypy.json
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# Secrets
|
||||
.creds*
|
||||
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"python.pythonPath": "relay/venv/bin/python3"
|
||||
}
|
||||
11
README.md
11
README.md
@@ -1,3 +1,14 @@
|
||||
# garden
|
||||
|
||||
Python project for building an indoor garden with the Setlock ladies.
|
||||
|
||||
## BCM Pin Assignments
|
||||
|
||||
| BCM Number | Device | Function |
|
||||
|------------|--------|----------|
|
||||
| 4 | Green Pushbutton | Sequence Start |
|
||||
| 27 | Yellow Pushbutton | Lamp |
|
||||
| 13 | Blue Pushbutton | Water Pump |
|
||||
| 26 | Relay 1 | N.O. Pump |
|
||||
| 20 | Relay 2 | *Unassigned* |
|
||||
| 21 | Relay 3 | N.O. Lamp |
|
||||
33
automatic/input.py
Normal file
33
automatic/input.py
Normal file
@@ -0,0 +1,33 @@
|
||||
#! env/bin/python3
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
def get_pin_input():
|
||||
|
||||
# Pin Assignments
|
||||
PB1_BCM = 4 # Green
|
||||
PB2_BCM = 27 # Yellow
|
||||
PB3_BCM = 13 # Blue
|
||||
RELAY1_PIN = 26 # Water Pump
|
||||
RELAY2_PIN = 20 # Unassigned
|
||||
RELAY3_PIN = 21 # Lamp
|
||||
|
||||
# Get current time.
|
||||
now = datetime.now()
|
||||
hour = now.hour
|
||||
minute = now.minute
|
||||
|
||||
# Define alias variables for input devices.
|
||||
inputs = {
|
||||
'green_button' : GPIO.input(PB1_BCM),
|
||||
'yellow_button' : GPIO.input(PB2_BCM),
|
||||
'blue_button' : GPIO.input(PB3_BCM),
|
||||
'pump' : GPIO.input(RELAY1_PIN),
|
||||
'lamp' : GPIO.input(RELAY3_PIN),
|
||||
'hour' : hour,
|
||||
'minute' : minute,
|
||||
}
|
||||
|
||||
return inputs
|
||||
20
automatic/output.py
Normal file
20
automatic/output.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#! env/bin/python3
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
def write_pin_output(outputs):
|
||||
|
||||
# Setup for Hardware
|
||||
RELAY1_PIN = 26 # Water Pump
|
||||
RELAY2_PIN = 20 # Unassigned
|
||||
RELAY3_PIN = 21 # Lamp
|
||||
|
||||
# Write outputs.
|
||||
if outputs['detect']:
|
||||
time.sleep(1.0)
|
||||
|
||||
GPIO.output(RELAY1_PIN, outputs['pump'])
|
||||
GPIO.output(RELAY2_PIN, False)
|
||||
GPIO.output(RELAY3_PIN, outputs['lamp'])
|
||||
69
automatic/routine.py
Normal file
69
automatic/routine.py
Normal file
@@ -0,0 +1,69 @@
|
||||
#! env/bin/python3
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
from input import get_pin_input
|
||||
from state_trans import check_state
|
||||
from output import write_pin_output
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
# Pin Assignments
|
||||
PB1_BCM = 4 # Green
|
||||
PB2_BCM = 27 # Yellow
|
||||
PB3_BCM = 13 # Blue
|
||||
RELAY1_PIN = 26 # Water Pump
|
||||
RELAY2_PIN = 20 # Unassigned
|
||||
RELAY3_PIN = 21 # Lamp
|
||||
|
||||
# Setup the Inputs to use the internal pull-down.
|
||||
GPIO.setup(PB1_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB2_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB3_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
|
||||
# Setup the Outputs.
|
||||
GPIO.setup(RELAY1_PIN, GPIO.OUT)
|
||||
GPIO.setup(RELAY2_PIN, GPIO.OUT)
|
||||
GPIO.setup(RELAY3_PIN, GPIO.OUT)
|
||||
|
||||
try:
|
||||
|
||||
auto_mode = False
|
||||
|
||||
while True:
|
||||
|
||||
# Detect user input.
|
||||
inputs = get_pin_input()
|
||||
|
||||
# Activate auto mode if the Green PB is pressed.
|
||||
if auto_mode or inputs['green_button'] == True:
|
||||
|
||||
inputs['mode'] = "AUTO"
|
||||
auto_mode = True
|
||||
|
||||
# Activate manual mode if the Yellow or Blue PB's are pressed.
|
||||
if not auto_mode or inputs['yellow_button'] == True or inputs['blue_button'] == True:
|
||||
|
||||
inputs['mode'] = "MANUAL"
|
||||
auto_mode = False
|
||||
|
||||
# Make any transitions based on mode and inputs.
|
||||
outputs = check_state(inputs)
|
||||
|
||||
# Write the outputs which correspond to the desired state.
|
||||
write_pin_output(outputs)
|
||||
|
||||
# Avoid maxxing out a single thread.
|
||||
time.sleep(0.1)
|
||||
|
||||
# Cleanup on Exit.
|
||||
finally:
|
||||
GPIO.output(RELAY1_PIN, False)
|
||||
GPIO.output(RELAY2_PIN, False)
|
||||
GPIO.output(RELAY3_PIN, False)
|
||||
GPIO.cleanup()
|
||||
|
||||
68
automatic/state_trans.py
Normal file
68
automatic/state_trans.py
Normal file
@@ -0,0 +1,68 @@
|
||||
#! env/bin/python3
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
def check_state(inputs):
|
||||
|
||||
# Define alias variables for input devices.
|
||||
green_button = inputs['green_button']
|
||||
yellow_button = inputs['yellow_button']
|
||||
blue_button = inputs['blue_button']
|
||||
|
||||
# Define state variables for each of the output devices.
|
||||
pump_state = inputs['pump']
|
||||
lamp_state = inputs['lamp']
|
||||
|
||||
# Get mode and schedule information.
|
||||
mode = inputs['mode']
|
||||
hour = inputs['hour']
|
||||
minute = inputs['minute']
|
||||
|
||||
# Determine state.
|
||||
|
||||
# Assume no change in state.
|
||||
pump_out = pump_state
|
||||
lamp_out = lamp_state
|
||||
|
||||
# Automatic mode.
|
||||
if mode == "AUTO":
|
||||
|
||||
detect = False
|
||||
|
||||
if 6 < hour < 22:
|
||||
lamp_out = True
|
||||
pump_out = True
|
||||
else:
|
||||
lamp_out = False
|
||||
pump_out = False
|
||||
|
||||
# Manual mode.
|
||||
if mode == "MANUAL":
|
||||
|
||||
detect = False
|
||||
|
||||
# Pump Flip-Flop
|
||||
if not detect and blue_button and pump_state:
|
||||
pump_out = False
|
||||
detect = True
|
||||
if not detect and blue_button and not pump_state:
|
||||
pump_out = True
|
||||
detect = True
|
||||
# Lamp Flip-Flop
|
||||
if not detect and yellow_button and lamp_state:
|
||||
lamp_out = False
|
||||
detect = True
|
||||
if not detect and yellow_button and not lamp_state:
|
||||
lamp_out = True
|
||||
detect = True
|
||||
|
||||
# Define alias variables for input devices.
|
||||
outputs = {
|
||||
'detect' : detect,
|
||||
'pump' : pump_out,
|
||||
'lamp' : lamp_out,
|
||||
}
|
||||
|
||||
return outputs
|
||||
73
db_tools/db_writer.py
Normal file
73
db_tools/db_writer.py
Normal file
@@ -0,0 +1,73 @@
|
||||
#! env/bin/python3
|
||||
|
||||
# import the psycopg2 database adapter for PostgreSQL
|
||||
import psycopg2
|
||||
from psycopg2.extras import Json
|
||||
import json
|
||||
import sys
|
||||
|
||||
def connect_db(db: str,host: str,user: str,passwd: str):
|
||||
try:
|
||||
# declare a new PostgreSQL connection object
|
||||
conn = psycopg2.connect(
|
||||
dbname = db,
|
||||
user = user,
|
||||
host = host,
|
||||
password = passwd,
|
||||
# attempt to connect for 3 seconds then raise exception
|
||||
connect_timeout = 3
|
||||
)
|
||||
|
||||
except (Exception, psycopg2.Error) as err:
|
||||
#print ("\npsycopg2 connect error:", err)
|
||||
conn = None
|
||||
return conn
|
||||
|
||||
def get_db_creds(file: str):
|
||||
with open(file) as cred_file:
|
||||
creds = json.load(cred_file)
|
||||
return creds
|
||||
|
||||
def insert_data(conn, data):
|
||||
|
||||
# insert a new vendor into the vendors table
|
||||
sql = """
|
||||
INSERT INTO
|
||||
air(datetime, temperature, humidity)
|
||||
VALUES
|
||||
(%s, %s, %s)
|
||||
"""
|
||||
|
||||
try:
|
||||
# open cursor on our db connection
|
||||
cur = conn.cursor()
|
||||
|
||||
# execute the INSERT statement
|
||||
data = (data["datetime"], data["temperature"], data["humidity"])
|
||||
cur.execute(sql,data)
|
||||
|
||||
# commit the changes to the database
|
||||
conn.commit()
|
||||
|
||||
# close communication with the database
|
||||
cur.close()
|
||||
|
||||
except (Exception, psycopg2.DatabaseError) as error:
|
||||
print(error)
|
||||
|
||||
finally:
|
||||
if conn is not None:
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
data = {
|
||||
"datetime": "2021-10-23 01:58:08.205911",
|
||||
"temperature": "73.4",
|
||||
"humidity": "49.2"
|
||||
}
|
||||
|
||||
creds = get_db_creds("./.creds.json")
|
||||
|
||||
conn = connect_db(creds["db"], creds["host"], creds["user"], creds["passwd"])
|
||||
|
||||
insert_data(conn, data)
|
||||
13
db_tools/requirements.txt
Normal file
13
db_tools/requirements.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
black==21.9b0
|
||||
click==8.0.3
|
||||
importlib-metadata==4.8.1
|
||||
mypy-extensions==0.4.3
|
||||
pathspec==0.9.0
|
||||
platformdirs==2.4.0
|
||||
psycopg2-binary==2.9.1
|
||||
regex==2021.10.8
|
||||
RPi.GPIO==0.7.0
|
||||
tomli==1.2.1
|
||||
typed-ast==1.4.3
|
||||
typing-extensions==3.10.0.2
|
||||
zipp==3.6.0
|
||||
1523
dht22/log.csv
1523
dht22/log.csv
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,7 @@ if __name__ == "__main__":
|
||||
# Setup for Hardware
|
||||
DHT22_PIN = 4
|
||||
dht_device = adafruit_dht.DHT22(4)
|
||||
file = '/home/pi/code/dht22/log.csv'
|
||||
file = '/home/pi/code/garden/dht22/log.csv'
|
||||
|
||||
with open(file,'a') as f:
|
||||
|
||||
@@ -29,10 +29,10 @@ if __name__ == "__main__":
|
||||
data = get_sensor_data(dht22=dht_device)
|
||||
if data:
|
||||
temperature, humidity = get_sensor_data(dht22=dht_device)
|
||||
current_time = datetime.now().strftime("%H:%M:%S")
|
||||
current_time = datetime.now().strftime("%D %H:%M:%S")
|
||||
print(f'{humidity:.2f}% {temperature:.2f}degF')
|
||||
f.write(f'{current_time},{humidity:.2f},{temperature:.2f}\n')
|
||||
time.sleep(60)
|
||||
time.sleep(14.9)
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
28
functional_decription.md
Normal file
28
functional_decription.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Functional Description - Garden Logic
|
||||
|
||||
### Table of Contents
|
||||
1. Routines
|
||||
1. Scan Inputs
|
||||
2. Collect Program State
|
||||
3. Manipulate Program State
|
||||
4. Write Outputs
|
||||
5. Log to Database
|
||||
2. References
|
||||
|
||||
|
||||
## Routines
|
||||
|
||||
### Scan Inputs
|
||||
`./input/inputs.py`
|
||||
|
||||
### Collect Program State
|
||||
`./states/state.py`
|
||||
|
||||
### Manipulate Program State
|
||||
`./states/state.py`
|
||||
|
||||
### Write Outputs
|
||||
`./output/outputs.py`
|
||||
|
||||
### Log to Database
|
||||
`./logging/db.py`
|
||||
77
manual/manual.py
Normal file
77
manual/manual.py
Normal file
@@ -0,0 +1,77 @@
|
||||
#! env/bin/python3
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
||||
# Setup for Hardware
|
||||
PB1_BCM = 4 # Green
|
||||
PB2_BCM = 27 # Yellow
|
||||
PB3_BCM = 13 # Blue
|
||||
RELAY1_PIN = 26 # Water Pump
|
||||
RELAY2_PIN = 20 # Unassigned
|
||||
RELAY3_PIN = 21 # Lamp
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
# Setup the Inputs to use the internal pull-down.
|
||||
GPIO.setup(PB1_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB2_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB3_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
|
||||
# Setup the outputs to be initialized as OFF.
|
||||
GPIO.setup(RELAY1_PIN, GPIO.OUT)
|
||||
GPIO.output(RELAY1_PIN, False)
|
||||
GPIO.setup(RELAY2_PIN, GPIO.OUT)
|
||||
GPIO.output(RELAY2_PIN, False)
|
||||
GPIO.setup(RELAY3_PIN, GPIO.OUT)
|
||||
GPIO.output(RELAY3_PIN, False)
|
||||
|
||||
# Define alias variables for input devices.
|
||||
green_button = False
|
||||
yellow_button = False
|
||||
blue_button = False
|
||||
|
||||
# Define state variables for each of the output devices.
|
||||
pump_state = False
|
||||
lamp_state = False
|
||||
|
||||
# Begin detected presses.
|
||||
try:
|
||||
while True:
|
||||
|
||||
# Detect inputs.
|
||||
detect = False
|
||||
green_button = GPIO.input(PB1_BCM)
|
||||
yellow_button = GPIO.input(PB2_BCM)
|
||||
blue_button = GPIO.input(PB3_BCM)
|
||||
|
||||
# Determine state.
|
||||
if not detect and blue_button and pump_state:
|
||||
pump_state = False
|
||||
detect = True
|
||||
if not detect and blue_button and not pump_state:
|
||||
pump_state = True
|
||||
detect = True
|
||||
# Lamp
|
||||
if not detect and yellow_button and lamp_state:
|
||||
lamp_state = False
|
||||
detect = True
|
||||
if not detect and yellow_button and not lamp_state:
|
||||
lamp_state = True
|
||||
detect = True
|
||||
|
||||
# Write outputs.
|
||||
if detect:
|
||||
time.sleep(1.0)
|
||||
GPIO.output(RELAY1_PIN, pump_state)
|
||||
GPIO.output(RELAY3_PIN, lamp_state)
|
||||
|
||||
# Avoid running a single thread maxxed out.
|
||||
time.sleep(0.1)
|
||||
|
||||
finally:
|
||||
GPIO.cleanup()
|
||||
21
pb/pb.py
21
pb/pb.py
@@ -6,21 +6,34 @@ import time
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Setup for Hardware
|
||||
PB_PIN = 22
|
||||
PB1_BCM = 4 # Green
|
||||
PB2_BCM = 27 # Yellow
|
||||
PB3_BCM = 13 # Blue
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
# Use the internal pull-down.
|
||||
GPIO.setup(PB_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB1_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB2_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(PB3_BCM, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
|
||||
# Begin detected presses.
|
||||
i = 0
|
||||
try:
|
||||
while True:
|
||||
if not GPIO.input(PB_PIN):
|
||||
# Green
|
||||
if GPIO.input(PB1_BCM):
|
||||
i += 1
|
||||
print(f"Hi Gabby! Did you push the button? i = {i}")
|
||||
print(f"Hi Gabby! Did you push the GREEN button? i = {i}")
|
||||
# Yellow
|
||||
if GPIO.input(PB2_BCM):
|
||||
i += 1
|
||||
print(f"Hi Gabby! Did you push the YELLOW button? i = {i}")
|
||||
# Blue
|
||||
if GPIO.input(PB3_BCM):
|
||||
i += 1
|
||||
print(f"Hi Gabby! Did you push the BLUE button? i = {i}")
|
||||
time.sleep(0.1)
|
||||
|
||||
finally:
|
||||
|
||||
37
relay/relay.py
Normal file
37
relay/relay.py
Normal file
@@ -0,0 +1,37 @@
|
||||
#! env/bin/python3
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Setup for Hardware
|
||||
RELAY1_PIN = 26
|
||||
RELAY2_PIN = 20
|
||||
RELAY3_PIN = 21
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
# Setup the output pin; initialize OFF.
|
||||
GPIO.setup(RELAY1_PIN, GPIO.OUT)
|
||||
GPIO.output(RELAY1_PIN, False)
|
||||
GPIO.setup(RELAY2_PIN, GPIO.OUT)
|
||||
GPIO.output(RELAY2_PIN, False)
|
||||
GPIO.setup(RELAY3_PIN, GPIO.OUT)
|
||||
GPIO.output(RELAY3_PIN, False)
|
||||
|
||||
|
||||
# Short toggle.
|
||||
i = 0
|
||||
try:
|
||||
time.sleep(10.0)
|
||||
GPIO.output(RELAY1_PIN, True)
|
||||
GPIO.output(RELAY3_PIN, True)
|
||||
time.sleep(60.0)
|
||||
GPIO.output(RELAY1_PIN, False)
|
||||
GPIO.output(RELAY3_PIN, False)
|
||||
time.sleep(1.0)
|
||||
|
||||
finally:
|
||||
GPIO.cleanup()
|
||||
13
relay/requirements.txt
Normal file
13
relay/requirements.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
black==21.9b0
|
||||
click==8.0.3
|
||||
importlib-metadata==4.8.1
|
||||
mypy-extensions==0.4.3
|
||||
pathspec==0.9.0
|
||||
pkg-resources==0.0.0
|
||||
platformdirs==2.4.0
|
||||
regex==2021.10.8
|
||||
RPi.GPIO==0.7.0
|
||||
tomli==1.2.1
|
||||
typed-ast==1.4.3
|
||||
typing-extensions==3.10.0.2
|
||||
zipp==3.6.0
|
||||
Reference in New Issue
Block a user