For those of you that like to tinker I'm writing my Automagic Chicken Door over with some improvements in the code and making a step by step web page to outline what I did. For those of you that just buy a door this thread is not for you. I use a Raspberry Pi 3 to control my coop. The following is the basic code to open the door at dawn and turn on the lights until 15 minutes after sunrise then close the door at dusk. It has a time out feature so if the door is stuck it stops trying. Next I'll add a simple web page that can be viewed on your LAN with the coop status. The RPi adjusts the sun times each day at 2am for the new day.
JT
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
# 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(15).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
JT