Automatic Chicken door - Beginner needing some direction

Hi

I’m completely new to Arduino and pretty new to electronics in general. I had this idea to create and automatic chicken door. Opens when its light and closes when its dark, pretty simple. I had it going using an LDR and a latching relay with some read switches to stop it on the up and down. The problem was chickens are not that bright and they would always leave it too late to get through the door leaving half of them stuck outside.

My Arduino project was to create a program that would delay the closing by 1 hr after a certain light level.

I use the standard light senor project and added a relay which drives the 2 pole latching relay.

the basis of the program was for it to sense the light level. Once it dropped below a certain value it would record the time using the millis() function and then set a time from the current time plus a specified delay of 1 hr. It would then loop and test if that time was reached.

So far I can get the program to run for up to a value of 32500 mS delay. any longer and the whole thing does nothing, ie if I set the DoorDelay to 33000 or longer it hangs. I can’t work out why, is there a limit on the millis function?.

I would appreciate anyone giving me some keywords to look into to make this work, not necessarily after a resolved solution, happy to muddle along learning, just point me in a direction. I have tried searching the forum but when you are complete new its hard to know what to look for as there are so many topics and catagories and jargon words.

Code is below

// Pins
int sensorPin = 0;
int relayPin = 2;

// Variables
int lowThreshold = 400; // Low light threshold to close door
int highTreshold = 520; // upper light threshold to open door
int DoorDelay = 32500; // interval added to current time to close the door, needs to be 1 hr or 3600000
unsigned long currentMillis; // sets a variable to hold the time the light reached low threshold
unsigned long Doorclose = 0; // sets a variable to hold the time to close the door after low light threshold
int DoorPosition = 0; // Stores the current door position 0 open 1 closed
int sensorValue = 0; // Sets the variable to hold the LDR level

void setup() {

// Start Serial & set pin to output
Serial.begin(9600);
pinMode(relayPin,OUTPUT); // relay to switch the latching relay to drive the motor up or down

}

void loop() {

// Read the sensor pin
sensorValue = analogRead(sensorPin);

// If light level is low is detected, set the time to shut the door
if (sensorValue < lowThreshold){

if (DoorPosition == 0){ // Test door is currently open

if (Doorclose > 0){ // Test the door set time has been set

if (millis() >= Doorclose){ // check if door shut time has been reached
digitalWrite(relayPin, LOW); // close door
Doorclose = 0; // Set door close variables back to zero
DoorPosition = 1; // set the door position to closed
}
}
else
{
// If door set time has not been set

currentMillis = millis(); //get the current “time”
Doorclose = currentMillis + DoorDelay; // set the time to close the door from current time plus 1 hr
}
}
// if door is closed already do nothing
}

// If light level goes up again, open the door
if (sensorValue > highTreshold){
digitalWrite(relayPin, HIGH);
DoorPosition = 0; // set door position ready for door close if statement
}

}

int DoorDelay = 32500;

An ‘int’ can only go to 32,767

https://www.arduino.cc/reference/en/language/variables/data-types/int/

Use: ‘unsigned long’ <————<<<<< 4,294,967,295

FYI
boolean (8 bit) - simple logical true/false
byte (8 bit) - unsigned number from 0-255
char (8 bit) - signed number from -128 to 127. The compiler will attempt to interpret this data type as a character in some circumstances, which may yield unexpected results
unsigned char (8 bit) - same as ‘byte’; if this is what you’re after, you should use ‘byte’ instead, for reasons of clarity
word (16 bit) - unsigned number from 0-65535
unsigned int (16 bit)- the same as ‘word’. Use ‘word’ instead for clarity and brevity
int (16 bit) - signed number from -32768 to 32767. This is most commonly what you see used for general purpose variables in Arduino example code provided with the IDE
unsigned long (32 bit) - unsigned number from 0-4,294,967,295. The most common usage of this is to store the result of the millis() function, which returns the number of milliseconds the current code has been running
long (32 bit) - signed number from -2,147,483,648 to 2,147,483,647
float (32 bit) - signed number from -3.4028235E38 to 3.4028235E38. Floating point on the Arduino is not native; the compiler has to jump through hoops to make it work. If you can avoid it, you should. We’ll touch on this later.

Read Robin2’s discussion, Demonstration code for several things at the same time:

millis() overflow … a bad thing?
http://www.gammon.com.au/forum/?id=12127

FYI

In the future use code tags.

Use CTRL T to format your code.
Attach your ‘complete’ sketch between code tags, use the </> icon in the posting menu.
[code]Paste your sketch here[/code]

Show us a good schematic of your circuit.
Show us a good image of your wiring.
Give links to components.
Posting images:

Thanks

I didn't think about the storage value of the door close time. Cheers.

I specifically formatted my code so I could follow it with the embedded if statement, didn't know about the magical CNTRL T. Here I was thinking I was doing so well with all of the tag labels explaining the code.

I didn't think the schematic would help as I was just wanting some general advice but I have attached it along with a picture of the wiring for completeness.

// Pins
int sensorPin = 0;
int relayPin = 2;

// Variables
int lowThreshold = 400;          // Low light threshold to close door
int highTreshold = 520;          // upper light threshold to open door
unsigned long DoorDelay = 3600000; // interval added to current time to close the door
unsigned long currentMillis;    // sets a varible to hold the time the light reached low threshold
unsigned long Doorclose = 0;    // sets a varible to hold the time to close the door after low light threshold
int DoorPosition = 0;          // Stores the current door position 0 open 1 closed
int sensorValue = 0;           // Sets the varible to hold the LDR level

void setup() {

  // Start Serial & set pin to output
  Serial.begin(9600);
  pinMode(relayPin, OUTPUT); // relay to switch the latching realy to drive the motor up or down


}

void loop() {

  // Read the sensor pin
  sensorValue = analogRead(sensorPin);

  // If light level is low is detected, set the time to shut the door
  if (sensorValue < lowThreshold) {

    if (DoorPosition == 0) {   // Test door is currently open

      if (Doorclose > 0) {  // Test the door set time has been set

        if (millis() >= Doorclose) { // check if door shut time has been reached
          digitalWrite(relayPin, LOW);  // close door
          Doorclose = 0; // Set door close variables back to zero
          DoorPosition = 1;  // set the door position to closed
        }
      }
      else
      {
        // If door set time has not been set

        currentMillis = millis();  //get the current "time"
        Doorclose = currentMillis + DoorDelay; // set the time to close the door from current time plus 1 hr
      }
    }
    // if door is closed alread do nothing
  }



  // If light level goes up again, open the door
  if (sensorValue > highTreshold) {
    digitalWrite(relayPin, HIGH);
    DoorPosition = 0; // set door position ready for door close if statement
  }

}

I've always been intrigued by the many threads about chicken coops, and the need for having a door in the first place.

If the chickens know that they should go inside at dusk (or some reasonable time thereafter) what's the point of closing the door? They're inside already: if they know to go in for whatever reason like it's warmer, surely they'l stay inside for their own comfort. And if they don't know to go in in the first place, you won't get them to go in no matter how long you leave the door open after dusk.

(The technicalities of measuring light or perhaps using an RTC and a lookup table for time of dusk through the year, and operating a door accordingly and again in the morning are almost trivial: but I'm really keen to understand the logic behind this whole coop thing.)

what's the point of closing the door?

To keep out crepuscular & nocturnal predators.

Chickens, like all birds, have a natural roosting instinct. It's based on light levels, their internal body-clocks, and other factors.

I have noticed that our chooks will roost a little earlier as the days increase in length, and a little later as the days grow shorter, like their internal body-clocks are always lagging behind the length of day.

Another factor is the weather. If it rains most of the day, but the sun comes out in the evening, they will stay out as long as they dare, making the most of the late sun. If it's sunny all day, and they have been out and about exploring and scratching about, they will roost earlier, perhaps because they feel tired.

meltDown

PaulRB is correct. predators are a major issue, chickens will happily trot off to roost at night. In New Zealand we don't have foxes but we do have possums and rats. Both will get into a coop and cause havoc. Although generally only looking for eggs, chickens are not too bright and can run into objects as they have poor night vision and snap their own necks. I never said they were the brightest of g_ds creatures. Plus I hate getting up at 6am to let them out again when its -6 deg C (21 deg F)

So far so good on on the revised code, I didn't even think of the interger for the door close having to be a long unsigned integer.

Forums are great !

PaulRB:
To keep out crepuscular & nocturnal predators.

Wow! What a word! Those crepuscular critters can be nasty!

PaulRB:
I have noticed that our chooks will roost a little earlier as the days increase in length, and a little later as the days grow shorter, like their internal body-clocks are always lagging behind the length of day.

That sounds a bit like they are "working to rule", tending to have the same "working day" length despite the seasons.

Paul__B:
That sounds a bit like they are "working to rule", tending to have the same "working day" length despite the seasons.

Interesting theory, its hard to be sure because of other factors. The length of day varies between about 7 and 16 hours here in Yorkshire. The chooks certainly don't roost 1~2 hours before or after sunset. The effect I'm describing is perhaps a 15~20 minute lag behind the length of day.

You'd think by now that the predators would have this sussed and just wait inside to get locked in with their prey...

(Next we'll have keypads and the birds will have to tap out a code to open the door :wink: )

Well, dogs & cats often have RFID tags inserted under their skin, and you can buy automatic cat flaps which only open for your cat and not the neighbours.

I guess, if you were willing to pay for it, you could have RFID tags in your chickens, and the coop door could count them in before closing the door.

meltDown:
You’d think by now that the predators would have this sussed and just wait inside to get locked in with their prey…

Probably won’t have to worry about that 'til they figure out how to avoid becoming road kill.

We have a sort of wiring diagram but need a schematic :frowning: .

Here is the schematic. Originally it was using transistors to turn on a "flexi timer" (electronics kit consisting of a 555 IC and a 4020 IC). It didn't work very well but as I started out not knowing anything about electronics last week I did OK. Someone suggested to do the whole thing via an IC rather than transistors so I brought my first Arduino on Friday along with a ATMega326p chip and crystal to be able to assemble my own board, first ever electronics project completed. Chickens will be happy.

Looks like you are advancing quite well.

The 328 needs decoupling ‘ceramic’ .1uF capacitors on the power pins.

The crystal needs 22pF capacitors to GND.

Relay need kickback diodes across coils.

7805 needs a ceramic .1uF capacitor from input to GND (as close to the pins as possible).

Motor needs noise suppression of some kind.

Might be wise to fuse the battery.

Make sure D1 is of sufficient size for power flowing

That schematic looks substantially over-complex!

If you connected the LDR between the pin and ground,. you could use INPUT_PULLUP for an effective 47 k pull-up and not need an external resistor. The other advantage would be that it would be referenced to ground and you would not be extending your 5 V line out of the box with an ever-so-minor risk of shorting to ground.

I am puzzled as to why you have a latching relay. Was it simply something you had to hand?

The whole thing could be done much more simply using one of the readily available two relay modules and using just pushbuttons for the manual operation as the microcontroller can adjudicate the desired actions. While the limit switches are appropriate, having both up and down functions under the microcontroller control means that after a delay calculated to be the maximum time for the door to operate, the power to the motor would be switched off irrespective of whether the action had completed.

Thanks Paul__B

The project was an evolution of design. Originally an off the shelf LDR/relay connected to automotive relays with a small low RPM motor. the switches are two reed switches that are tripped by the door moving past.

The LDR relay packed up and I thought I could make my own. It consisted of multiple transistors both NPN and PNP (didn't know what they were but learnt heaps) and voltage dividers etc. It was complex and although I could get it working on a breadboard, it was so complex that making a prototype was frustrating. Plus I had to add in a delay timer. My problem was it would turn on and off repeatedly at dusk as the light changed causing the NPN transistor to pull up and then drop out. I needed someway to prevent that using a capacitor.

So it became an Arduino project as of last Friday, the latching relay was what I had to hand as the original design cut power to each side so i didn't have to "hold" it open. Trying to minimize power consumption. The reed switches are already in place so i kept them in play.

Thanks for the comments regarding how I could do it differently, I don't fully understand them yet, I'm still working this out, I'm only up to "Blink without delay" lesson. The push buttons sound like a good idea rather than the bulky switches. I did think about the possibility of running the motor in each direction for a set period of time.

R3 of the chicken door might have sensors to detect the door position rather than mechanical switches and may send a predetermined email or SMS that the door is closed and open again in the morning.

Cheers
Al

larryd:
Looks like you are advancing quite well.

The 328 needs decoupling ‘ceramic’ .1uF capacitors on the power pins.

The crystal needs 22pF capacitors to GND.

Relay need kickback diodes across coils.

7805 needs a ceramic .1uF capacitor from input to GND (as close to the pins as possible).

Motor needs noise suppression of some kind.

Might be wise to fuse the battery.

Make sure D1 is of sufficient size for power flowing

Thanks Larryd

I'll add that those items in, I forgot about the diodes on the relay. I also need to add a small diode and a bit of code to to turn the diode on during the 1hr count down so you can see at what light level the countdown starts. I have done it on the Uno just using the internal LED which works, unfortunately my prototype doesn't have an on board LED.

The 328 chip I brought came proloaded with a bootloader. However the whole thing runs 15x slower than my Uno. ie to time 1 hr is 240,000 ms not the 3,600,000 on the Uno.

I checked the crystal and it is definitely 16MHz.

Would missing out those capacitors causes this? Or is it something deeper in the chip itself ? I read stuff about various fuses but haven't got that far yet and other than a stopwatch I don't know how to check the speed of the chip.

// Pins
int sensorPin = 0;
int relayPin = 2;
int LEDtimer = 8;

// Variables
int lowThreshold = 400;          // Low light threshold to close door
int highTreshold = 520;          // upper light threshold to open door
unsigned long DoorDelay = 5000; // interval added to current time to close the door - test 5 secs set to 3600000 for 1 hr delay
unsigned long currentMillis;    // sets a variable to hold the time the light reached low threshold
unsigned long Doorclose = 0;    // sets a variable to hold the time to close the door after low light threshold
int DoorPosition = 0;          // Stores the current door position 0 open 1 closed
int sensorValue = 0;           // Sets the variable to hold the LDR level

void setup() {

  // Start Serial & set pin to output
  Serial.begin(9600);
  pinMode(relayPin, OUTPUT); // relay to switch the latching relay to drive the motor up or down
  pinMode(LEDtimer, OUTPUT); // 3mm LED to show that the count down has started


}

void loop() {

  // Read the sensor pin
  sensorValue = analogRead(sensorPin);

  // If light level is low is detected, set the time to shut the door
  if (sensorValue < lowThreshold) {

    if (DoorPosition == 0) {   // Test door is currently open

      if (Doorclose > 0) {  // Test the door set time has been set

        if (millis() >= Doorclose) { // check if door shut time has been reached
          digitalWrite(relayPin, LOW);  // close door
          Doorclose = 0; // Set door close variables back to zero
          DoorPosition = 1;  // set the door position to closed
          digitalWrite(LEDtimer, LOW); // Turn off count down LED
        }
      }
      else
      {
        // If door set time has not been set

        currentMillis = millis();  //get the current "time"
        Doorclose = currentMillis + DoorDelay; // set the time to close the door from current time plus 1 hr
        digitalWrite(LEDtimer, HIGH); // Start count down LED
      }
    }
    // if door is closed already do nothing
  }



  // If light level goes up again, open the door
  if (sensorValue > highTreshold) {
    digitalWrite(relayPin, HIGH);
    DoorPosition = 0; // set door position ready for door close if statement
    Doorclose = 0; // Set door close variables back to zero, this resets the countdown if the light goes back up
    digitalWrite(LEDtimer, LOW); // turn off count down LED
  }

}

Revised code to add in the LED and also reset the counter to zero if the light gets brighter, ie passing cloud at dusk.

Schematic.
Added in the capacitors for the crystal and the 5v supply, I think I could combine C6 and C7, I have found a wiring diagram for the chip. I hadn't seen the full wiring diagram and followed an incorrect example on the internet.

Cheers
Al