Light and Time dependant switch

Hi Guys,

I'm trying to get a code working that will do the following;

  1. Check to see if its dark using a light sensor
  2. if its light, keep the LED off
  3. if its dark, turn on the LED
  4. If LED is on, keep LED on for 3 hours and then off for 9 hours
  5. then back to checking if its dark.

So its for a light I want to come on automatically when it gets dark, then stay on for 3 hours and then stay off until the next day. I want it to ignore any light increases, i.e. when I turn other lights on, if this makes sense. This is what I have so far but its not up to the task.

The code works but not the 3 on 9 off timing

// These variables store the on and off pattern
// and the current state of the LED

int led =  2;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
long OnTime = 10800000;           // milliseconds of on-time
long OffTime = 32400000;          // milliseconds of off-time

#include <RBD_LightSensor.h>
 
RBD::LightSensor light_sensor(A0);
 
void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
}
 
void loop() {

  int LS = (light_sensor.getPercentValue());
  Serial.println(LS);
  
//check to see if its dark enought to turn the LED on  

  if (LS >= 40){
    digitalWrite(led, LOW);
  }
  
  else {
    digitalWrite(led, HIGH); 
  }

  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();
 
  if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
  {
    ledState = LOW;  // Turn it off
    previousMillis = currentMillis;  // Remember the time
    digitalWrite(led, ledState);  // Update the actual LED
  }
  else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
  {
    ledState = HIGH;  // turn it on
    previousMillis = currentMillis;   // Remember the time
    digitalWrite(led, ledState);	  // Update the actual LED
  }
}

Because this logic...

f (LS >= 40){
    digitalWrite(led, LOW);
  }
  
  else {
    digitalWrite(led, HIGH); 
  }

...is still executing every time around the loop. So it is interfering with the code that is doing the timing and still turning the light on and off regardless..

Something more like (untested)....

//Check for start condition, set initial state...
if (running == false && LS < 40) {
  running = true;
  ledState = HIGH;
  previousMillis = currentMillis;  // Remember the time
}

//if timers active, wait for required times to expire, trigger state changes...
if (running) {
  if(ledState == HIGH && currentMillis - previousMillis >= OnTime)
  {
    ledState = LOW;  // Turn it off
    previousMillis = currentMillis;  // Remember the time
  }
  else if (ledState == LOW && currentMillis - previousMillis >= OffTime)
  {
    // REALLY? ARE YOU SURE YOU WANT TO END THE SEQUENCE WITH LED ON?
    ledState = HIGH;  // turn it on
    // Not necessary. We’re not timing anything anymore, no need to remember time we stopped.
    previousMillis = currentMillis;   // Remember the time
    running = false; //back to waiting for low light start condition
  }
}

digitalWrite(led, ledState);  // Update the actual LED

Am I on the right track here?

// These variables store the on and off pattern 
// and the current state of the LED

int led =  2;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
long OnTime = 10800000;           // milliseconds of on-time
long OffTime = 32400000;          // milliseconds of off-time

unsigned long startMillis;
unsigned long currentMillis;


#include <RBD_LightSensor.h>
 
RBD::LightSensor light_sensor(A0);
 
void setup() {
  Serial.begin(9600);
  startMillis = millis();  //initial start time
  pinMode(led, OUTPUT);
}
 
void loop() {

  int LS = (light_sensor.getPercentValue());
  Serial.println(LS);
  unsigned long currentMillis = millis();

//check to see if its dark enought to turn the LED on  
//Check for start condition, set initial state...
if (led == LOW && LS <= 40) {
    digitalWrite(led, LOW);
  }
  else if (led == LOW && LS > 40) {
    digitalWrite(led, HIGH);
  }
//if timers active, wait for required times to expire, trigger state changes...
  else if (led == HIGH && LS > 40 && currentMillis - previousMillis >= OnTime) {
    
    digitalWrite(led, LOW);  // Turn it off
    previousMillis = currentMillis;  // Remember the time
  }
  else if (led == LOW && LS <= 40 && currentMillis - previousMillis >= OffTime)
  {
    digitalWrite(led, LOW);  // Turn it off
  }
}

Still having trouble with it starting and the 9 hours off.

The more I think about it, I think Delay would work best, I dont need to do anything while the light is On and Off.

So I couldn't get the millis one working but I did get it working with Delay. I guess for such a simple code it will suffice.

int led =  2;

#include <RBD_LightSensor.h>
 
RBD::LightSensor light_sensor(A0);

void setup() {
    pinMode(led, OUTPUT);
}

void loop() {
  
  int LS = (light_sensor.getPercentValue());
  
  if (LS >= 40){
    digitalWrite(led, LOW);
  }
 
  else {
    digitalWrite(led, HIGH);
    delay(10800000);
    digitalWrite(led, LOW);
    delay(32400000);
  }
}

I can't see any drawbacks to using this.