Light and time dependent switch

I am building some kind of a switch which is turned on for one period of time when it's dark.

When outside is dark (transition from day to night) i want to turn LED (for example) on and it should be on for 7 hours. After 7 hours LED should be turned off and next activation should be at next transition from day to night (transition is a prerequisite for turning on, not just dark, so this should happen next evening).

I am wondering if i could do this with internal counting (millis) or should i use RTC module. I want to realise this as simple as possible and with the minimum number of components.

Any idea is appreciated.

LDR + resistor to differentiate between day and night (dark). LED + resistor. Arduino. Five parts plus the power supply. Does that constitute "the minimum number of components"?

Or are you after something sans Arduino?

Thank you for quick reply..

For light sensor i am using TEPT5700 from Vishay. I made circuit on breadboard but i am wondering if in code i can realise this function without RTC. If i can use internal counter (millis) and if, how to do that.

I tried with this function but without luck.. http://www.cmiyc.com/blog/2012/07/16/arduino-how-do-you-reset-millis/

I hope this question isn't more appropriate for "understanding the code" forum section :slight_smile:

Arduino itself it's not a problem (i will use stand-alone version in the end).

luxy:
For light sensor i am using TEPT5700 from Vishay. I made circuit on breadboard but i am wondering if in code i can realise this function without RTC. If i can use internal counter (millis) and if, how to do that.

unsigned long myMilliCounter, prevMillis;

void loop()
{
  unsigned long now = millis();
  unsigned long elapsedMillis = now-prevMillis;
  myMilliCounter += elapsedMillis;
  prevMillis = now;

  ...
}

"myMilliCounter" counts milliseconds, you can reset it to zero whenever you want to.

Great,

that's what i need.. Will try and report.

I was playing a while with millis counters but without luck. I have a lack of programming skills :slight_smile:

I know where is the problem but i don't know how to solve it. When program starts it works because timer start counting from zero. LED turn on for specified interval and than turns off, also if switch is still in HIGH state - that's ok. Next time, when i put switch from high to low and high again, this should happen again. LED does not turn on because timer is bigger than my interval. I need to reset timer while switch is in LOW state so LED can be turned on for specified interval again, but i don't know how.

Here's my code.

#define interval 5000  // 5 seconds
     
unsigned long counter;
  
byte led = 3;
byte switcher = 2;
byte switchState;
          
  void setup()  
{
  pinMode(led, OUTPUT);
  pinMode(switcher, INPUT);
}
   
      
  void loop()
{
  counter = millis();
    
  switchState = digitalRead(switcher);
  
  if ((switchState == HIGH) && (counter <= interval))
  {
    digitalWrite(led, HIGH);
    
      if (counter >= interval)
        {
          digitalWrite(led, LOW);
        }
  }
  
  else
  {
    digitalWrite(led, LOW);
  }
  
  delay(100);
}

Hi,

2nd example

u need a 2nd variable to update the time

also: never use delay()
delay means u block the uC from doing anything else/freeze it, for delays u actually use millis too

lax123:
Hi,
Arduino UNO Tutorial 3 - Timing

2nd example

u need a 2nd variable to update the time

also: never use delay()
delay means u block the uC from doing anything else/freeze it, for delays u actually use millis too

Hello,

thank you for that great tutorial! I solved the problem :slight_smile:

Btw, i saw that if i don't use delay in code (just 100 ms for example) that state from HIGH is not always set totaly to LOW, when it should be. If i use small delay in whole code is ok but i can see little LED flicker (they are almost unseen but if i look directly into LED i can see it). Like some kind of output leaking? Anyone know why?

New, working code

unsigned long currentTime;
unsigned long loopTime;
  
byte led = 3;
byte switcher = 2;
byte switchState;
          
  void setup()  
{  
  pinMode(led, OUTPUT);
  pinMode(switcher, INPUT);
  
  currentTime = millis();
  loopTime = currentTime; 
}
   
      
  void loop()
{
  currentTime = millis();
    
  switchState = digitalRead(switcher);
  
  if (switchState == HIGH)
  {
    digitalWrite(led, HIGH);          
  
    if (currentTime >= (loopTime + 5000))
    {
      digitalWrite(led, LOW);
    }
  }   
  
  else
  {
    digitalWrite(led, LOW);
    loopTime = currentTime;
  }
    
delay(100);

}

Hi,

is ur switcher actually a button or really that sensor?

Can you rephrase ur last text? I dont really understand it.

If u use no delay in the code the led is flickering?
If u use delay of 100 there is no led flickering?
And if u use a very small delay of like 1 the led is flickering too?

As I said, using delay() in code is like blocking the arduino from doing anything else. That could also mean the led is still turned on because of the delay when in fact it would be off. Might relate to that flickering or other weird behaviour, not sure.

Try to work with millis instead of delay, just type into google "millis instead of delay" and u will find plenty of info.

I dont know about your circuit but maybe u need something like a pullup or pulldown resistor for the sensor

Today i made whole circuit with light sensor and FET for output. I also deleted delay from code and i am not getting flickers any more. The only thing i noticed is that when program is in one part of the code the led lights a little, although output state should be LOW. It's almost invisible but if i look directly into led i can see it. If i put circuit in other state, led is completely off (so this can't be FET leaking or something like that). Anyway, i think this should not be a problem but i am still wondering why this is happening.

I will show in which part of code this is happening.

if (light <= 160)
{
digitalWrite(fet, HIGH); <------------ IN THIS STATE LED IS TURNED ON FOR INTERVAL TIME

if (currentTime >= (loopTime + interval))
{
digitalWrite(fet, LOW); <------------ IN THIS STATE LED LIGHTS A LITTLE BUT SHOULD BE COMPLETELY OFF
}
}

else
{
digitalWrite(fet, LOW); <------------ IN THIS STATE LED IS COMPLETELY TURNED OFF
loopTime = currentTime;
}

well idk excatly but your code reads to me like this:

if light below 160(
TURN ON
(If intervall not exceeded TURN OFF))

so everytime that loop runs the light is turned on at first and then turned off after the intervall check, get what im thinking?

Exactly! That's what i need.

FET should be open (high state) only for a defined period of time and than should go in LOW state, no matter if light is still under 160. Everything works i am just wondering why led lights a little in that state and how could i solve it.

I just solved it.. I changed if state a little and now it's ok! :slight_smile:

 if ((light <= 160) && (currentTime <= (loopTime + interval)))
  {
    digitalWrite(fet, HIGH);          
  }
    else if ((light <= 160) && (currentTime >= (loopTime + interval)))
  {
    digitalWrite(fet, LOW);
  }       
    else
  {
    digitalWrite(fet, LOW);
    loopTime = currentTime;
  }

I almost finished my project. Everything works but i didn't try to run device for more than 50 days (to see whats happen on rollover). I want to be sure that in case of rollover the whole thing is not going to freeze.

I read a lot about millis rollover and if i understand it correctly.. I am wondering if in my case this should work. All i want to do is to reset my 3 variables to 0 on rollover.

Part of code..

  void setup()  
{ 
  unsigned long currentTime;
  unsigned long loopTime;  
  unsigned long onTime;    
  unsigned long offTime;      
  unsigned long interval; 
 
  currentTime = millis();
  onTime = offTime = loopTime = currentTime;
}

// LOOP

  currentTime = millis();

  // VALUES RESET
    if (currentTime >= 4294967295)
  {
    loopTime = 0;
    onTime = 0;
    offTime = 0;
  }
    
  
  // SWITCHING
    if (((light <= border) && (currentTime <= (loopTime + interval)) && (currentTime >= (onTime + 5000))))  // 5 sec delay
  {
    digitalWrite(fet, HIGH);
    offTime = currentTime;    
  }
    else if ((light <= border) && (currentTime >= (loopTime + interval)))
  {
    digitalWrite(fet, LOW);
    offTime = currentTime;
    onTime = currentTime;
  }    
    else if ((light > border) && (currentTime >= (offTime + 5000)))  // 5 sec delay
  {
    digitalWrite(fet, LOW);
    loopTime = currentTime;
    onTime = currentTime;
  }

luxy:
I read a lot about millis rollover and if i understand it correctly.. I am wondering if in my case this should work. All i want to do is to reset my 3 variables to 0 on rollover.

Resetting is never necessary if your code is correct.

luxy:
Part of code..

Others may be able to decipher what you are trying to do from the snippet. I will not. Post all of your code.

I think that rollover should not affect in my case but i wanna be sure.. If my code is correct.

  unsigned long currentTime;  
  unsigned long loopTime;     
  unsigned long onTime;     
  unsigned long offTime;  
  unsigned long interval;     
  
  unsigned long svetlost;     
  unsigned long samples[100]; 
  byte i; 
    
  byte fet = 9;        
  unsigned long trim;
  
  byte dip1 = A2;
  byte dip2 = A3; 
  byte dip3 = A4;
  byte dip4 = A5;
  
  byte dip1state;
  byte dip2state;
  byte dip3state;
  byte dip4state;
  
         
  // SETUP        
  void setup()  
{ 

  pinMode(fet, OUTPUT);
  
  pinMode(dip1, INPUT);    
  pinMode(dip2, INPUT);    
  pinMode(dip3, INPUT);
  pinMode(dip4, INPUT);
  
  currentTime = millis();
  onTime = offTime = loopTime = currentTime;
 
}
 
   
  // LOOP    
  void loop()
{
   

  for(i=0; i<=99; i++)
  {
    samples[i] = analogRead(A0);
    svetlost = svetlost + samples[i];   
  }

    svetlost = svetlost / 100.0;

  
  unsigned long pot = analogRead(A1);
  trim = ((pot * 30) / 1023);  // Delta 30
  
  
  unsigned int meja = (200 + trim); 
  

  dip1state = digitalRead(dip1);
  dip2state = digitalRead(dip2);
  dip3state = digitalRead(dip3);
  dip4state = digitalRead(dip4);
  

    if ((dip1state == LOW) && (dip2state == LOW) && (dip3state == LOW) && (dip4state == LOW))
  {
    interval = 20000;  // 20 sekund
  }
    else if ((dip1state == LOW) && (dip2state == LOW) && (dip3state == LOW) && (dip4state == HIGH))
  {
    interval = 1800000;  // 30 minut 
  }
    else if ((dip1state == LOW) && (dip2state == LOW) && (dip3state == HIGH) && (dip4state == LOW))
  {
    interval = 3600000;  // 1h
  }
    else if ((dip1state == LOW) && (dip2state == LOW) && (dip3state == HIGH) && (dip4state == HIGH))
  {
    interval = 5400000;  // 1,5h
  }
    else if ((dip1state == LOW) && (dip2state == HIGH) && (dip3state == LOW) && (dip4state == LOW))
  {
    interval = 7200000;  // 2h
  }
    else if ((dip1state == LOW) && (dip2state == HIGH) && (dip3state == LOW) && (dip4state == HIGH))
  {
    interval = 9000000;  // 2,5h
  }
    else if ((dip1state == LOW) && (dip2state == HIGH) && (dip3state == HIGH) && (dip4state == LOW))
  {
    interval = 10800000;  // 3h
  }
    else if ((dip1state == LOW) && (dip2state == HIGH) && (dip3state == HIGH) && (dip4state == HIGH))
  {
    interval = 12600000;  // 3,5h
  }
    else if ((dip1state == HIGH) && (dip2state == LOW) && (dip3state == LOW) && (dip4state == LOW))
  {
    interval = 14400000;  // 4h
  }
    else if ((dip1state == HIGH) && (dip2state == LOW) && (dip3state == LOW) && (dip4state == HIGH))
  {
    interval = 16200000;  // 4,5h
  }
    else if ((dip1state == HIGH) && (dip2state == LOW) && (dip3state == HIGH) && (dip4state == LOW))
  {
    interval = 18000000;  // 5h
  }
    else if ((dip1state == HIGH) && (dip2state == LOW) && (dip3state == HIGH) && (dip4state == HIGH))
  {
    interval = 19800000;  // 5,5h
  }
    else if ((dip1state == HIGH) && (dip2state == HIGH) && (dip3state == LOW) && (dip4state == LOW))
  {
    interval = 21600000;  // 6h
  }
    else if ((dip1state == HIGH) && (dip2state == HIGH) && (dip3state == LOW) && (dip4state == HIGH))
  {
    interval = 23400000;  // 6,5h
  }
    else if ((dip1state == HIGH) && (dip2state == HIGH) && (dip3state == HIGH) && (dip4state == LOW))
  {
    interval = 25200000;  // 7h
  }
    else
  {
    interval = 99999999;  // Unlimited
  }

    
  currentTime = millis();  
  
  
    if (((svetlost <= meja) && (currentTime <= (loopTime + interval)) && (currentTime >= (onTime + 5000))))  // 5 min = 300000 ms
  {
    digitalWrite(fet, HIGH);
    offTime = currentTime;    
  }
    else if ((svetlost <= meja) && (currentTime >= (loopTime + interval)))
  {
    digitalWrite(fet, LOW);
    offTime = currentTime;
    onTime = currentTime;
  }    
    else if ((svetlost > meja) && (currentTime >= (offTime + 5000)))  // 5 min = 300000 ms
  {
    digitalWrite(fet, LOW);
    loopTime = currentTime;
    onTime = currentTime;
  }
  
}

luxy:
I think that rollover should not affect in my case but i wanna be sure.. If my code is correct.

The code will not work correctly through a rollover. The correct pattern is to subtract the current millis value from a previous millis to get a delta. If the expression has a subtraction there is high probability you did it correctly.

Change this...

    if (((svetlost <= meja) && (currentTime <= (loopTime + interval)) && (currentTime >= (onTime + 5000))))  // 5 min = 300000 ms
  {

...to this...

    if (((svetlost <= meja) && (currentTime - loopTime <= interval) && (currentTime - onTime >= 5000)))  // 5 min = 300000 ms
  {

Change this...

  }
    else if ((svetlost <= meja) && (currentTime >= (loopTime + interval)))
  {

...to this...

  }
    else if ((svetlost <= meja) && (currentTime - loopTime >= interval))
  {

Change this...

  }    
    else if ((svetlost > meja) && (currentTime >= (offTime + 5000)))  // 5 min = 300000 ms
  {

...to this...

  }    
    else if ((svetlost > meja) && (currentTime - offTime >= 5000))  // 5 min = 300000 ms
  {

As far as I can tell, the changes do not introduce any bugs but you should thoroughly test.

Thank you, thank you, thank you!!

I changed those lines and everything works the same (just without rollover problem after 45 days i hope :slight_smile:
I think now i really understand how to handle with millis without getting any rollover problems. For me, that kind of learning is the most effective.

Really, thanks a lot again!

You are welcome.

You can test the rollover by using unsigned short instead of unsigned long. The rollover will occur after about one minute.