Auto Chicken Coop Door

jthornton

Free Ranging
6 Years
Aug 30, 2017
5,037
10,305
682
Poplar Bluff, MO
My Coop
My Coop
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.

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
 
I've been tweaking the code a lot and this is the most simple version to just say it's time to open the door or not. It was quite a pain to deal with dates and times with Python but I finally got it whipped.

Code:
#!/usr/bin/env python3

#import datetime
from datetime import date
from datetime import datetime
import time
import astral
import pytz
import schedule

localTz = 'US/Central'

coordinates = ["Poplar Bluff", "USA", 36.763084, -90.413871, localTz, 110]
pbmo = astral.Location(info=(coordinates))
pbmo.solar_depression = "civil"

dateFormat = '%b %d %Y'
timeFormat = '%I:%M %p'

#for event, time in pbmo.sun(date.today()).items():
#    print(event, 'at', time)
today = datetime.now(pytz.timezone(localTz))
day_start = datetime.combine(today, datetime.min.time())
midnight = datetime.combine(today, datetime.max.time())

central = pytz.timezone(localTz)

midnight_local = central.localize(midnight)

#print(midnight)
 
print('Today Min: %s ' % (day_start) )
print('Midnight: %s ' % (midnight) )

events = pbmo.sun(datetime.now(pytz.timezone(localTz)))
dawn = events['dawn']
sunrise = events['sunrise']
sunset = events['sunset']
dusk = events['dusk']
now = datetime.now(pytz.timezone(localTz))
print('Today Date {}'.format(now.strftime(dateFormat)))
print('Inital Door Open == {}'.format(now > dawn and now < dusk))
print('Dawn {}'.format(dawn.strftime(timeFormat)))
print('Sunrise {}'.format(sunrise.strftime(timeFormat)))
print('Now {}'.format(now.strftime(timeFormat)))
print('Sunset {}'.format(sunset.strftime(timeFormat)))
print('Dusk {}'.format(dusk.strftime(timeFormat)))
#print(now > sunrise)
#print(now > sunrise and now < dusk)
#print(now > midnight_local)

def update():
    events = pbmo.sun(datetime.now(pytz.timezone(localTz)))
    dawn = events['dawn']
    sunrise = events['sunrise']
    sunset = events['sunset']
    dusk = events['dusk']

def status():
    now = datetime.now(pytz.timezone(localTz))
    print('Time {} Door Open == {}'.format(now.strftime(timeFormat),
    now > dawn and now < dusk))

schedule.every(5).minutes.do(status)
schedule.every().day.at("00:01").do(update)

try:
    while True:
        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))

"""
city_name = 'Poplar Bluff'

a = Astral()

a.solar_depression = 'civil'

city = a[city_name]

#print('Information for {}/{}\n'.format(city_name, city.region))


from pytz import all_timezones
for timezone in all_timezones:
    print(timezone)
"""
# US/Central

JT
 
I've been brainstorming a bit about my code algorithm and if anyone here wants to join in here is what I'm thinking today.

The basic idea:
If natural daylight is greater than 14h open door and turn on light at dawn
If natural daylight is decreasing when 10h is reached start adding 5 minutes per day extra light in the morning until 14h is reached then hold until natural daylight is greater than 14h.

The lights go out at sunrise + any extra time I set. I'm also considering turning on the lights on very overcast days up to some time before sunset.

The door closes at dusk.

JT
 
I wish there was someone here that did tinker with electronics, it would be much more fun collaborating with them.

JT

I do although I am still new to it though.

After your post in the other thread you probably recognize me it might be a good idea to go with raspberry pi instead of arduino. I think it will be time to get myself a raspberry pi board pretty soon
 
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

the LAN part is the part I really have been looking for.
 
I do although I am still new to it though.

After your post in the other thread you probably recognize me it might be a good idea to go with raspberry pi instead of Arduino. I think it will be time to get myself a raspberry pi board pretty soon

Yea I've found the Raspberry Pi 3 B to be a rock solid single board computer. Add the screw terminal block breakout board for the RPi for the I/O (Inputs and Out puts) and it's so much easier to connect things up. While I'm linking stuff this it the relay board I use it has 4 relays so you can control motor forward, motor reverse, lights and something extra. And while I'm babbling on I should mention the I2C bus on the RPi can connect many things up like temperature probe, OLED and LCD displays, weather board that has temperature, humidity, and pressure as well as many more things.

As for the LAN if you want to have some cameras look for POE switch, this just plugs into your router and provides Power Over Ethernet for cameras as well as normal LAN.

You should put your location in your profile...

JT
 
I've been working on some code to do the following algorithm:
Code:
Summer Test
If natural daylight is greater than 14h
    Open door and turn on light at dawn

Fall Test
If natural daylight is less than 14h and more than 10h and decreasing
    Open door and turn on light at dawn

Winter Test
If natural daylight is less than 10h and decreasing
    Find the last date of 10h daylight
        Add 5 minutes per day from that date

Spring Test
If natural daylight is less than 10h and increasing
    Find the last date of 10h of daylight with daylight decreasing
        Add 5 minutes per day from that date

Using seed dates for each test the output from that code:
Code:
pi@raspberrypi:~ $ coop5
Summer Test
Test Date Jul 17 2018
More than 14 hours of natural daylight
Natural Daylight 14:24
Door Opens at sunrise 05:55 AM

Fall Test
Test Date Aug 17 2018
Less than 14 hours of natural daylight
Natural Daylight 13:31
Yesterday was Aug 16 2018
Decreasing daylight
Door Opens at sunrise 06:20 AM

Winter Test
Test Date Dec 17 2018
Natural Daylight 9:39
Yesterday was Dec 16 2018
Increasing daylight
Last 10h Daylight was 24 days ago
Total Light Time 11:39
10h Daylight Date Nov 23 2018
Test Daylight 10:01
Dawn 06:39 AM
Door Opens at 05:36 AM

Spring Test
Test Date Jan 04 2019
Less than 14 hours of natural daylight
Natural Daylight 9:43
Yesterday was Jan 03 2019
Increasing daylight
Dawn 06:45 AM
Door Opens at 04:13 AM
Set Date is Nov 23 2018 days ago 42

I've attached the sample code for anyone that is curious, just need to remove the '.txt' extension I had to use to upload it.

JT
 

Attachments

  • coop5.txt
    6.6 KB · Views: 9
Hey JT,

This is great stuff. I am an EE and a lot more experienced with C++ and Python, but will be using your code as soon as my coop gets built. Just finished painting the framework this morning.

BIG thanks for the info and once I get caught up I will gladly see if I can help out with some of the code optimization.
 

New posts New threads Active threads

Back
Top Bottom