Motion controlled lights

Hello,

I'm looking to automate some light fittings in my home, however before I delve into the world of Arduino (never done anything like this before) I wanted to make sure it is capable of doing what I need it to do.

I want the board to control (with a relay) 3 separate lights with 3 separate motion sensors that are totally independent of each other. They will be required to turn on when motion is detected and turn off after 20 seconds of no motion. They will also be able to all be on at the same time although have separate 20 second countdown timers.

Can anyone tell me if the following code would work (Bear in mind I have not coded the light sensor yet as this will just wrap the motion sensor code, so to keep focus on the lights for now I have left it out, and I've only included two light and sensor pairs as it's etc...)

const int relay1 =  7;	// the number of the light on relay 1
const int relay2 =  8;	// the number of the light on relay 2
const int motion1 = 2;	// the number of the motion sensor for light 1
const int motion2 = 3;	// the number of the motion sensor for light 2

long timeLeft1 = 0;
long timeLeft2 = 0;
long timeSince1 = 0;
long timeSince2 = 0;
long timeOff = 20000;

void setup() {
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(motion1, INPUT);
  pinMode(motion2, INPUT);
}

void loop()
{

    unsigned long timeNow = millis();

	if(digitalRead(motion1) == HIGH){

		digitalWrite(relay1,HIGH); //turn lights on
                timeSince1 = millis();  //record time relay1 was set
                timeLeft1 = timeOff; //reset timer

	} else {

                if (timeLeft1 <= 0){

                         digitalWrite(relay1, LOW);
                         
                } else {

                          timeLeft1 = timeleft1 - (timeNow - timeSince1); //take current time from the time the light was turned on and set this as the time left until off
                }

        }

	if(digitalRead(motion2) == HIGH){

		digitalWrite(relay2,HIGH); //turn lights on
                timeSince2 = millis();  //record time relay2 was set
                timeLeft2 = timeOff; //reset timer

	} else {

                if (timeLeft2 <= 0){

                         digitalWrite(relay2, LOW);
                         
                } else {

                          timeLeft2 = timeleft2 - (timeNow - timeSince2); //take current time from the time the light was turned on and set this as the time left until off
                }

        }

}

You have an array of motion sensors, an array of relays, and an array of LDRs. Why doesn't your code have any arrays?

I can only presume it's because I'm new to this. Does this mean the code won't work until I use arrays?

Edit:

I've just looked up arrays and whilst I understand the concept I'm still unsure how it will be useful to me. I best had explain the set-up a little more.

Light positions 2, 3 and 4 are used during the day and are controlled separate from each other. Each has its own motion sensor.
When it is dark, the system reverts to a master motion sensor and includes another light fitting and turns them all on at the same time.

Here is the full code

const int relay1 =  7;	// the number of the light on relay 1
const int relay2 =  8;	// the number of the light on relay 2
const int relay3 =  9;	// the number of the light on relay 3
const int relay4 =  10;	// the number of the light on relay 4
const int motion1 = 2;	// the number of the motion sensor for light 1
const int motion2 = 3;	// the number of the motion sensor for light 2
const int motion3 = 4;	// the number of the motion sensor for light 3
const int motion4 = 5;	// the number of the motion sensor for light 4
const int light = 6;	// the number of the light sensor

long timeLeft1 = 0;
long timeLeft2 = 0;
long timeLeft3 = 0;
long timeLeft4 = 0;
long timeSince1 = 0;
long timeSince2 = 0;
long timeSince3 = 0;
long timeSince4 = 0;
long timeOff = 20000;
int lightThreshold = 250;

void setup() {
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);
  pinMode(motion1, INPUT);
  pinMode(motion2, INPUT);
  pinMode(motion3, INPUT);
  pinMode(motion4, INPUT);
  pinMode(light, INPUT);
}

void loop()
{

  unsigned long timeNow = millis();

    if(digitalRead(light) < lightThreshold) {
      
      	if(digitalRead(motion1) == HIGH){

		digitalWrite(relay1,HIGH); //turn lights on
		digitalWrite(relay2,HIGH); //turn lights on
		digitalWrite(relay3,HIGH); //turn lights on
		digitalWrite(relay4,HIGH); //turn lights on
                timeSince1 = millis();  //record time relays were set
                timeLeft1 = timeOff; //reset timer

	} else {

                if (timeLeft1 <= 0){

                         digitalWrite(relay1, LOW);
                         digitalWrite(relay2, LOW);
                         digitalWrite(relay3, LOW);
                         digitalWrite(relay4, LOW);
                         
                } else {

                          timeLeft1 = timeLeft1 - (timeNow - timeSince1); //take current time from the time the lights were turned on and set this as the time left until off
                }

        }
            
    } else {

	if(digitalRead(motion2) == HIGH){

		digitalWrite(relay2,HIGH); //turn lights on
                timeSince2 = millis();  //record time relay1 was set
                timeLeft2 = timeOff; //reset timer

	} else {

                if (timeLeft2 <= 0){

                         digitalWrite(relay2, LOW);
                         
                } else {

                          timeLeft2 = timeLeft2 - (timeNow - timeSince2); //take current time from the time the light was turned on and set this as the time left until off
                }

        }

	if(digitalRead(motion3) == HIGH){

		digitalWrite(relay3,HIGH); //turn lights on
                timeSince3 = millis();  //record time relay2 was set
                timeLeft3 = timeOff; //reset timer

	} else {

                if (timeLeft3 <= 0){

                         digitalWrite(relay3, LOW);
                         
                } else {

                          timeLeft3 = timeLeft3 - (timeNow - timeSince3); //take current time from the time the light was turned on and set this as the time left until off
                }

        }
        
        if(digitalRead(motion4) == HIGH){

		digitalWrite(relay4,HIGH); //turn lights on
                timeSince4 = millis();  //record time relay2 was set
                timeLeft4 = timeOff; //reset timer

	} else {

                if (timeLeft4 <= 0){

                         digitalWrite(relay4, LOW);
                         
                } else {

                          timeLeft4 = timeLeft4 - (timeNow - timeSince4); //take current time from the time the light was turned on and set this as the time left until off
 
                }

        }

    }

}

Does this mean the code won't work until I use arrays?

No, but it means you will have three times as much code as you need (or four, or five if you add more sensors and relays). Evey time you duplicate code, you increase the chances of not changing every needed in the copy, screwing up something that was working.

Thank you for your explanation. I have updated my second post to explain more (I suppose I should have explained better first time).

After this updated code, do you still think arrays will work?

const int light = 6;	// the number of the light sensor
...
int lightThreshold = 250;
...
  pinMode(light, INPUT);
...
    if(digitalRead(light) < lightThreshold) {

So you've defined light to be digital pin 6, and are reading it with a digitalRead. digitalRead returns either HIGH or LOW which numerically are 1 and 0. Both 1 and 0 are below 250, so that if statement will always be true. Typically, light sensors are hooked up to analogPins and read with an analogRead. How come you haven't done that?

Arrch:

const int light = 6;	// the number of the light sensor

...
int lightThreshold = 250;
...
 pinMode(light, INPUT);
...
   if(digitalRead(light) < lightThreshold) {




So you've defined light to be digital pin 6, and are reading it with a digitalRead. digitalRead returns either HIGH or LOW which numerically are 1 and 0. Both 1 and 0 are below 250, so that if statement will always be true. Typically, light sensors are hooked up to analogPins and read with an analogRead. How come you haven't done that?

Along with what this guy said, you need to do an analogRead() on either an Analog pin, or one of the PWM Digital pins (these are, as PaulS corrected, not Analog pins, but I'm pretty sure you can use them similar to the Analog pins for basic tasks such as this). Once you have that value, you will probably need to use constrain() or map() depending on what you want.

or one of the PWM Digital pins (these are also Analog pins).

No, they are not.

Ah, silly mistake. I've changed it to the following, presuming that I understand correctly that 14 is analogue 1

const int light = 14;	// the number of the light sensor
...
int lightThreshold = 250;
...
  pinMode(light, INPUT);
...
    if(analogRead(light) < lightThreshold) {

Presuming that I understand that 14 is analogue 1

14 is the value of the digital pin that shares space with analog pin 0, on some Arduinos. Why not just use 0? The analogRead() function will have to subtract 14 from the value you specify, if you specify a pin number that is out of range, so save it the trouble and use correct pin numbers.

PaulS:

Presuming that I understand that 14 is analogue 1

14 is the value of the digital pin that shares space with analog pin 0, on some Arduinos. Why not just use 0? The analogRead() function will have to subtract 14 from the value you specify, if you specify a pin number that is out of range, so save it the trouble and use correct pin numbers.

Brilliant, thank you very much, I got a bit confused over A0, 0 and 14.

	if(digitalRead(motion1) == HIGH){

		digitalWrite(relay1,HIGH); //turn lights on
                timeSince1 = millis();  //record time relay1 was set
                timeLeft1 = timeOff; //reset timer

	} else {

                if (timeLeft1 <= 0){

                         digitalWrite(relay1, LOW);
                         
                } else {

                          timeLeft1 = timeleft1 - (timeNow - timeSince1); //take current time from the time the light was turned on and set this as the time left until off
                }

        }

If this even works, it's a very bizarre way of doing it. If the motion sensor pin is HIGH, turn the relay on and set the appropriate time:

if (digitalRead(sensor) == HIGH)
{
  digitalWrite(relay, HIGH);
  timeSinceLastHigh = millis();
}

If it isn't, check the time elapsed since it was last HIGH, and turn it off it it has reached its threshold:

else
{
  if (millis() - timeSinceLastHigh > timeToStayOn)
  {
    digitalWrite(relay, LOW);
  }
}

Get it working for one. Once that works, and your variables are in arrays, surround the code in a for loop:

for (int i=0; i<numSensors; i++)
{
  // code to check for motion and activate lights
}

and modify the variables from

relay
sensor
timeSinceLastHigh

to

relay[i]
sensor[i]
timeSinceLastHigh[i]

So you don't have to duplicate it a bunch of times, and it will be scalable if you wish to add more.

The array is optional. I wouldn't worry about it until after you have it working, and then if you want to make it more elegant, feel free.

However, I really like how Arrch did the time stamp. Although timeSince1 and timeSinceLastHigh are probably a not quite accurately named. Maybe timeOfLastHigh or timeStampOfLastHigh would be more intuitive.

TanHadron:
The array is optional. I wouldn't worry about it until after you have it working, and then if you want to make it more elegant, feel free.

However, I really like how Arrch did the time stamp. Although timeSince1 and timeSinceLastHigh are probably a not quite accurately named. Maybe timeOfLastHigh or timeStampOfLastHigh would be more intuitive.

I too like the time change suggested. I did begin to create the array but quickly got stuck with motion sensor 1 only being active when it was dark and controlling all of the lights.

Thank you for the StampOfLastHigh suggestion, I've been playing with a new name for it all day.