Simple Coop Door
This code is for a simple coop door that opens at dawn and closes at dusk. Lights are turned on at dawn and go off 15 minutes after sunrise. The time is updated once a day at 2AM. This is for a Raspberri Pi 3 and two relays driving something with built in limit switches.
The Python code
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import schedule
import astral
import time
import smbus2
import bme280
from datetime import date, timedelta, datetime
from pytz import timezone
# basackwards relay setup
run = False
stop = True
# setup I/O Constants
DOOR_UP = 4
DOOR_DOWN = 5
DOOR_LOCK = 6
LIGHTS = 7
MAN_UP = 22
MAN_DOWN = 23
MAN_LIGHT = 24
UP_PROX = 26
DOWN_PROX = 27
# setup I/O
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(DOOR_UP, GPIO.OUT) # Motor FWD
GPIO.output(DOOR_UP, stop)
GPIO.setup(DOOR_DOWN, GPIO.OUT) # Motor REV
GPIO.output(DOOR_DOWN, stop)
GPIO.setup(DOOR_LOCK, GPIO.OUT) # Door Lock
GPIO.output(DOOR_LOCK, stop)
GPIO.setup(LIGHTS, GPIO.OUT) # Lights
GPIO.output(LIGHTS, stop)
GPIO.setup(MAN_UP, GPIO.IN,pull_up_down=GPIO.PUD_DOWN) # Manual Up Switch
GPIO.setup(MAN_DOWN, GPIO.IN,pull_up_down=GPIO.PUD_DOWN) # Manual Down Switch
GPIO.setup(MAN_LIGHT, GPIO.IN,pull_up_down=GPIO.PUD_DOWN) # Manual Light Switch
GPIO.setup(UP_PROX, GPIO.IN,pull_up_down=GPIO.PUD_DOWN) # Door Up Switch
GPIO.setup(DOWN_PROX, GPIO.IN,pull_up_down=GPIO.PUD_DOWN) # Door Down Switch
#setup BME280
port = 1
address = 0x76
bus = smbus2.SMBus(port)
calibration_params = bme280.load_calibration_params(bus, address)
# Construct our location. Longitude west and latitude south are negative
coordinates = ["Poplar Bluff", "USA", 36.763084, -90.413871, "US/Central", 110]
pbmo = astral.Location(info=(coordinates))
pbmo.solar_depression = "civil"
time_format = "%I:%M %p"
date_time_format = "%b %d %Y %I:%M %p"
doorTimer = 0
doorTimeOut = False
# initalize some flags
doorManualUp = False
doorManualDown = False
# initalize some global variables
dawn = pbmo.dawn(date.today())
sunrise = pbmo.sunrise(date.today())
sunset = pbmo.sunset(date.today())
dusk = pbmo.dusk(date.today())
def update():
dawn = pbmo.dawn(date.today())
sunrise = pbmo.sunrise(date.today())
sunset = pbmo.sunset(date.today())
dusk = pbmo.dusk(date.today())
now = datetime.now(timezone('US/Central'))
print(now.strftime(date_time_format))
print('dawn {}'.format(dawn.strftime(time_format)))
def status():
data = bme280.sample(bus, address, calibration_params)
temperature = round((data.temperature * 1.8) + 32, 1)
humidity = round(data.humidity, 1)
pressure = round(data.pressure, 1)
now = datetime.now(timezone('US/Central'))
print('{}F {}%RH {}hPa {}'.format(temperature, humidity, pressure,
now.strftime(time_format)))
schedule.every(1).minutes.do(status)
schedule.every().day.at("02:00").do(update)
update()
try:
while True:
# manual Door Up
if GPIO.input(MAN_UP) and not GPIO.input(UP_PROX):
GPIO.output(DOOR_UP, run) # Motor FWD
GPIO.output(DOOR_LOCK, run) # Door Lock
doorManualUp = True
if GPIO.input(MAN_UP) and GPIO.input(UP_PROX):
GPIO.output(DOOR_UP, stop) # Motor FWD
GPIO.output(DOOR_LOCK, stop) # Door Lock
if not GPIO.input(MAN_UP) and doorManualUp:
GPIO.output(DOOR_UP, stop) # Motor FWD
GPIO.output(DOOR_LOCK, stop) # Door Lock
doorManualUp = False
# manual Door Down
if GPIO.input(MAN_DOWN) and not GPIO.input(DOWN_PROX):
GPIO.output(DOOR_DOWN, run) # Motor REV
GPIO.output(DOOR_LOCK, run) # Door Lock
doorManualDown = True
if GPIO.input(MAN_DOWN) and GPIO.input(DOWN_PROX):
GPIO.output(DOOR_DOWN, stop)
GPIO.output(DOOR_LOCK, stop)
if not GPIO.input(MAN_DOWN) and doorManualDown:
GPIO.output(DOOR_DOWN, stop)
GPIO.output(DOOR_LOCK, stop)
doorManualDown = False
now = datetime.now(timezone('US/Central'))
# Lights
if GPIO.input(MAN_LIGHT):
GPIO.output(LIGHTS, run)
else:
if now >= dawn and now <= (sunrise + timedelta(minutes=15)):
GPIO.output(LIGHTS, run)
else:
GPIO.output(LIGHTS, stop)
# auto Door Up
if now > dawn and now < dusk:
if not GPIO.input(MAN_DOWN):
if not doorTimer: doorTimer = time.time()
if not GPIO.input(UP_PROX) and not doorTimeOut:
GPIO.output(DOOR_UP, run)
GPIO.output(DOOR_LOCK, run)
if time.time() - doorTimer > 60: doorTimeOut = True
if GPIO.input(UP_PROX) or doorTimeOut:
GPIO.output(DOOR_UP, stop)
GPIO.output(DOOR_LOCK, stop)
if GPIO.input(UP_PROX):
doorTimer = 0
# auto Door Down
if now > dusk and now < dawn:
if not GPIO.input(MAN_UP):
if not doorTimer: doorTimer = time.time()
if not GPIO.input(DOWN_PROX) and not doorTimeOut:
GPIO.output(DOOR_DOWN, run)
GPIO.output(DOOR_LOCK, run)
if time.time() - doorTimer > 60: doorTimeOut = True
if GPIO.input(UP_PROX) or doorTimeOut:
GPIO.output(DOOR_DOWN, stop)
GPIO.output(DOOR_LOCK, stop)
if GPIO.input(DOWN_PROX):
doorTimer = 0
schedule.run_pending()
time.sleep(.1)
except KeyboardInterrupt:
# here you put any code you want to run before the program
# exits when you press CTRL+C
print('\nKeyBoard Interrupt')
except Exception as e:
# this covers all other exceptions
print(str(e))
finally:
GPIO.cleanup() # this ensures a clean exit