How to delay closing door?

Hi There,

I need advice on what is the best solution for the following problem –

I have a built a simple chicken coop door which opens and closes via a LDR.
(This was made possible from lots of good help received from this forum
Link to thread if you are interested - Chicken Coop door hardware not working - Project Guidance - Arduino Forum)

Now to the problem at hand, I have discovered that the closing time is too early as the chickens are still out. So ideally I want to delay the closing time by a half hour. The way I see it, could try and only delay closing time or delay closing and opening time, to ensure opening is still about the present time I would decrease the LDR setting.

Now over to you what is the best way of achieving this? I presume using the millis function?
or is there better way?

Present code below.

Thanks in advance
Tony

// Chicken Coop Code 16/08/2017

// darkthreshold 2 (Really dark)

// Define pins & variables

const int EnMotorPin = 9;          // enable motor  - pin 9  PWM
const int CloseDoorPin = 8;  // direction close motor - pin 8
const int OpenDoorPin = 7;   // direction open motor  - pin 7

const int photocellPin = A0;                 // photocell connected to analog 0
int photocellVal;             // analog reading of the photocel
bool daylight = true; // daylight status
int darkthreshold = 2;
int daythreshold = 175;  // sets hysteresis limits to stop door jittering

int systemState = 0;
int SPEED = 220;

// Reed switches top and bottom of coop door

int bottomSwitchPin = 2;
int topSwitchPin = 4;
bool topSwitchState; // true if door is up
bool bottomSwitchState; // true if door is down
void setup() {

  Serial.begin(9600);
  pinMode(bottomSwitchPin, INPUT);
  pinMode(topSwitchPin, INPUT);
  pinMode(EnMotorPin, OUTPUT);
  pinMode(CloseDoorPin, OUTPUT);
  pinMode(OpenDoorPin, OUTPUT);
}

void loop() {
  systemState = 0;
  photocellVal = analogRead(photocellPin); // read inputs
  if (photocellVal > daythreshold)
  {
    daylight = true;
  }
  if (photocellVal < darkthreshold)
  {
    daylight = false;
  }
  topSwitchState = digitalRead(topSwitchPin);
  bottomSwitchState = digitalRead(bottomSwitchPin);
  //  read system status
  if (daylight == true && topSwitchState == true)
  {
    systemState = 0;   // motor stop
  }
  if (daylight == true && topSwitchState == false)
  {
    systemState = 1;  // drive door up
  }
  if (daylight == false && bottomSwitchState == true)
  {
    systemState = 0;    // motor stop
  }
  if (daylight == false && bottomSwitchState == false)
  {
    systemState = 2;  // drive door down
  }
  DispVals();
  switch (systemState) {
    case 0: // motor stop
      digitalWrite(CloseDoorPin, LOW);
      digitalWrite(OpenDoorPin, LOW);
      analogWrite(EnMotorPin, 0);
      break;
    case 1:  //drive door up
      digitalWrite(CloseDoorPin, LOW);
      digitalWrite(OpenDoorPin, HIGH);
      analogWrite(EnMotorPin, SPEED);
      break;
    case 2:  // drive door down
      digitalWrite(CloseDoorPin, HIGH);
      digitalWrite(OpenDoorPin, LOW);
      analogWrite(EnMotorPin, SPEED);
      break;
    default:
      digitalWrite(CloseDoorPin, LOW);
      digitalWrite(OpenDoorPin, LOW);
      analogWrite(EnMotorPin, 0);
      break;
  }
}

void DispVals()
{
  Serial.print("topSW ");
  Serial.print(topSwitchState);
  Serial.print("\t");
  Serial.print("botSW ");
  Serial.print(bottomSwitchState);
  Serial.print("\t");
  Serial.print("PhotoVal ");
  Serial.print(photocellVal);
  Serial.print("\t");
  Serial.print("daylight ");
  Serial.print(daylight);
  Serial.print("\t");
  Serial.print("systemState ");
  Serial.print(systemState);
  Serial.print("\t");
  if (systemState == 0)
  {
    Serial.println("\t door stopped");
  }
  if (systemState == 1)
  {
    Serial.println("\t door driving up");
  }
  if (systemState == 2)
  {
    Serial.println("\t door driving down");
  }
}

You could set a flag when the LDR detects evening.
The code looks for this flag being set and the resets and starts the close timer ex: 30 minutes at which time the door is closed.

.

Is an LDR sensical? How sensitive is it to clouds, moonlight, debris?
I'm thinking an RTC module would be more reliable.

INTP:
Is an LDR sensical? How sensitive is it to clouds, moonlight, debris?
I'm thinking an RTC module would be more reliable.

It's amazing how many of these projects don't use an RTC.

A person could easily write an algorithm to account for seasonal sun movement too.

.

I don't know much about chickens but I do know roosters are up and about before what I would consider LDR distinguishable range from variances in moonlight.
I'd much sooner try counting chickens going in/out than try an LDR.

Well, you definitely do not want to count your chickens before they are hatched.

.

Well, obviously since everyone knows the egg came first, you literally can't count chickens before they hatch because you'd be counting eggs.

Do gators trip PIR sensors? Hmmm.

Thanks, guys for all the eggxcellent jokes..

Let me recap -

  • Door and codes are in place. No RTC
  • Reason for LDR is, once working as expected, should never have to be changed.
  • Opening works as expected
  • Closing is the problem, closing too early

Need to delay closing by 30 minutes.

Question - How can this be done?

I thought of using Millis but don't know if this is the way to go.

Need a simple solution

OK guys over to you.......

Cheers
Tony

When the LDR code detects it is time to close the door, record millis() in a variable (type unsigned long).
When millis() - yourVariable >= 30601000ul you then close the door.

.

Sorry for the derailment.

Could you not simply look at what the LDR reads when you do want it to close and just change your parameters? I'd've thought that'd be the most obvious answer. Just in case you've just copied someone's code in whole and were unaware of the parameters.

Change the trigger. Analogously- it's like setting an alarm clock at 5:00p but wanting it to wait until 5:30p to ring. Just set the alarm at 5:30p.

Ok INTP , I have tried changing the LDR reading to the lowest I think I can go.
int darkthreshold = 2 hence my problem.

Larryd like your solution, now as I am not a programmer
where do I insert into code ? - Code above

Tony

Maybe this is close, you will have to test it out on your own:

// Chicken Coop Code 16/08/2017

// darkthreshold 2 (Really dark)

// Define pins & variables

const int EnMotorPin = 9;          // enable motor  - pin 9  PWM
const int CloseDoorPin = 8;  // direction close motor - pin 8
const int OpenDoorPin = 7;   // direction open motor  - pin 7

const int photocellPin = A0;                 // photocell connected to analog 0
int photocellVal;             // analog reading of the photocel
bool daylight = true; // daylight status
int darkthreshold = 2;
int daythreshold = 175;  // sets hysteresis limits to stop door jittering

unsigned long delayMillis;
bool closeFlag = false;

int systemState = 0;
int SPEED = 220;

// Reed switches top and bottom of coop door

int bottomSwitchPin = 2;
int topSwitchPin = 4;
bool topSwitchState; // true if door is up
bool bottomSwitchState; // true if door is down
void setup() {

  Serial.begin(9600);
  pinMode(bottomSwitchPin, INPUT);
  pinMode(topSwitchPin, INPUT);
  pinMode(EnMotorPin, OUTPUT);
  pinMode(CloseDoorPin, OUTPUT);
  pinMode(OpenDoorPin, OUTPUT);
}

void loop() {
  systemState = 0;
  photocellVal = analogRead(photocellPin); // read inputs
  if (photocellVal > daythreshold)
  {
    daylight = true;

    //enable darkness detection
    closeFlag = false;
  }
  
  //are we allowed to detect darkness and is it dark?
  if (closeFlag == false && photocellVal < darkthreshold)
  {
    daylight = false;
    
    //reset the timer
    delayMillis = millis();
    //prevent resetting the timer any more
    closeFlag = true;
  }
  
  topSwitchState = digitalRead(topSwitchPin);
  bottomSwitchState = digitalRead(bottomSwitchPin);
  //  read system status
  if (daylight == true && topSwitchState == true)
  {
    systemState = 0;   // motor stop
  }
  if (daylight == true && topSwitchState == false)
  {
    systemState = 1;  // drive door up
  }
  if (daylight == false && bottomSwitchState == true)
  {
    systemState = 0;    // motor stop
  }
  if (daylight == false && bottomSwitchState == false)
  {
    systemState = 2;  // drive door down
  }
  DispVals();
  switch (systemState) {
    case 0: // motor stop
      digitalWrite(CloseDoorPin, LOW);
      digitalWrite(OpenDoorPin, LOW);
      analogWrite(EnMotorPin, 0);
      break;
    case 1:  //drive door up
      digitalWrite(CloseDoorPin, LOW);
      digitalWrite(OpenDoorPin, HIGH);
      analogWrite(EnMotorPin, SPEED);
      break;
    case 2:  // drive door down
      //has 30 mimutes gone by yet?
      if(millis() - delayMillis < 30 * 60 * 1000ul)
      {
        //no not yet
        break;
      }
      //okay, proceed
      digitalWrite(CloseDoorPin, HIGH);
      digitalWrite(OpenDoorPin, LOW);
      analogWrite(EnMotorPin, SPEED);
      break;
    default:
      digitalWrite(CloseDoorPin, LOW);
      digitalWrite(OpenDoorPin, LOW);
      analogWrite(EnMotorPin, 0);
      break;
  }
}

void DispVals()
{
  Serial.print("topSW ");
  Serial.print(topSwitchState);
  Serial.print("\t");
  Serial.print("botSW ");
  Serial.print(bottomSwitchState);
  Serial.print("\t");
  Serial.print("PhotoVal ");
  Serial.print(photocellVal);
  Serial.print("\t");
  Serial.print("daylight ");
  Serial.print(daylight);
  Serial.print("\t");
  Serial.print("systemState ");
  Serial.print(systemState);
  Serial.print("\t");
  if (systemState == 0)
  {
    Serial.println("\t door stopped");
  }
  if (systemState == 1)
  {
    Serial.println("\t door driving up");
  }
  if (systemState == 2)
  {
    Serial.println("\t door driving down");
  }
}

Thanks, larryd will do.

Will get back with an update in a couple of days.

Cheers
Tony

If light/dark thresholds have to be set that low, then the LDR pull up/down resistor has the wrong value.
Or... the LDR is already stuffed. There have been reports that they don't last very long outside (months).

People have succesfully replaced the LDR with a solar cell from a small garden light.
Better results, and they should last longer.
Connect between pin and ground, no pull up/down resistor.
It might be wise to add a (1-10k) resistor between solar+ and analogue pin, and a 100n cap from pin to ground.

Experiment with a short sketch that only displays the analogue value on the serial monitor.
Leo..

void setup() {
  Serial.begin(9600);
}
void loop() {
  Serial.println(analogRead(A0));
  delay(250);
}

Day 1 - door did not close.

Can I answer someone to check the code.

Thanks
Tony

If you have a problem with your darkness value being too low (an analogRead() threshold of 2 is not the best imho, I'd want to bring it up to 10 or 20), you could replace the resistor wired with the LDR (I assume you wired this as voltage divider) to a much higher value. It'll of course also push higher the "day" value.

A second way of preventing jitter is to implement a delay before another change can be made to the door - e.g. can't open within 30 mins after closing and the other way around. That would give you more flexibility in the open/close darkness values.

Will you be controlling both doors?

Did you use the exact code in post #13 or did you change anything in it?

Do some testing, change the following line, then cover the sensor to see what happens.
if(millis() - delayMillis < 30 * 60 * 1000ul)
For testing, change to this for 30 second delay.
if(millis() - delayMillis < 30 * 1000ul)

darkthreshold = 2 <-----<<<< this is very very low, try ~10

You could add some code that, once darkness is triggered, only allow the door open if the sensor > ~60 for a period, but first check with 30 seconds.

.