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