Motion Sensor Light timer

Hello

currently trying to make a motion sensor light that i can turn on and off with sensor detection but also have auto turn off after lets say 15 minutes if left on.

I've got it so i can turn it off and on now using motion but not sure how to have it auto turn off after a set time since delay blocks me from turning it off with motion if i try using that.

I'm thinking I'll have to use the millis function? but not sure where to start and feel like I've hit a wall so any guidance would be appreciated.

here's the code i have so far to have the sensor turn it off and on.

int led = 8;
int pir = 2;
int val;
int state = 0;

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

void loop() {

val = digitalRead(pir);

if (val == HIGH)
{
if (state == 0)
{
state = 1;
digitalWrite(led, HIGH);
delay (4000);
}
else {
state = 0;
digitalWrite(led, LOW);
delay (4000);
}
}
}

Hi, Please read How to get the best out of this forum and you'll get more help from all.

When sensor detects the turn on state, you enable a timing flag and start the TIMER.
The operative word is when.

If you manually turn off the light, disable the flag.

When the flag is enabled the TIMER is checked to see if the interval has been reached, if so, turn off the light.

if(flag == enabled && millis() - startTime >= (15 * 60 *1000ul))
{
// turn off the light
flag = disabled;
}

how exactly do i go about implementing this into what i already have? I've tried for a while now but don't seem to be getting anywhere sorry.

i can't seem to be able to get my thick skull around millis no matter how hard i try.

Show us the sketch you tried.


In the Arduino IDE, use Ctrl T or CMD T to format your code then copy the complete sketch.

Use the </> icon from the ‘reply menu’ to attach the copied sketch.

this old version is all i have now unfortunately, but it'll show you what i think i was trying to do? still quite new to this so it's probably embarrassingly far from right.

int led = 8;
int pir = 2;
int val;
int state = 0;
unsigned long sleep_start;
unsigned long previousMillis = 0;


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

void loop() {
  unsigned long currentMillis = millis();
  val = digitalRead(pir);
  if (sleep_start > 0 && millis() > sleep_start + 15 * 60 * 1000)

  if (val == HIGH)
  {
    if (state == 0)
    {
      state = 1;
      digitalWrite(led, HIGH);
      sleep_start = millis();
      delay (4000);
    }
    else {
      state = 0;
     sleep_start = 0;
      digitalWrite(led, LOW);
      delay (4000);
    }
  }
}

Is this what you had in mind ?

// Version  YY/MM/DD  Description
// 1.00     21/07/03  Functional code
// 1.01     21/07/03  Added comments

//*********************************************************************
#define movementDetection             HIGH

#define LEDon                         HIGH
#define LEDoff                        LOW

#define enabled                       true
#define disabled                      false

//*********************************************************************
const byte heartbeatLED             = 13;
const byte  led                     = 8;
const byte  pir                     = 2;

bool autoOffFlag                    = disabled;

byte lastPIRstate                   = !movementDetection;
byte val;
byte state = 0;

//Timing stuff
const unsigned long timeoutDuration   = 5000;             //5 seconds for testing
//const unsigned long timeoutDuration = 15 * 60 * 1000ul; //15 minutes

unsigned long heartbeatMillis;
unsigned long switchMillis;
unsigned long autoMillis;

//*********************************************************************
void setup()
{
  pinMode(heartbeatLED, OUTPUT);

  //turn the light OFF
  digitalWrite(led, LEDoff);
  pinMode(led, OUTPUT);

  pinMode(pir, INPUT);

} //END of setup()

//*********************************************************************
void loop()
{
  //***********************
  //time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 500)
  {
    //restart the TIMER
    heartbeatMillis = millis();

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //***********************
  //time to check the switches ?
  if (millis() - switchMillis >= 50)
  {
    //restart the TIMER
    switchMillis = millis();

    checkSwitches();
  }

  //***********************
  //if enabled, has the auto timout duration be reached ?
  if (autoOffFlag == enabled && millis() - autoMillis >= timeoutDuration)
  {
    //disable the TIMER
    autoOffFlag = disabled;

    //turn the light OFF
    digitalWrite(led, LEDoff);
  }

} //END of loop()


//*********************************************************************
void checkSwitches()
{
  //*****************************************    PIR
  //
  byte state = digitalRead(pir);

  //***********************
  //has the PIR changed state ?
  if (lastPIRstate != state)
  {
    //update to the new state
    lastPIRstate = state;

    //************
    //has the PIR detected movement ?
    if (state == movementDetection)
    {
      //enable the TIMER
      autoOffFlag = enabled;

      //start the TIMER
      autoMillis = millis();

      //turn ON the light
      digitalWrite(led, LEDon);
    }

    //PIR sensor must have timed out
    else
    {
      //disable the TIMER
      autoOffFlag = disabled;

      //turn OFF the light
      digitalWrite(led, LEDoff);
    }

  } //END of  if (lastPIRstate != state)


} //END of  checkSwitches()

//*********************************************************************
1 Like

not entirely sure to be honest, tried to change the times on that code to stay on but couldn't keep it on for more then a few seconds, i think the sensor stays active for 3-4 seconds after activation so not sure if that could have something to do with it?

If the sensor detects movement are you saying it sends a HIGH (+5v) to the Arduino input ?

This HIGH lasts for at least 3-4 seconds by an internal timer in the sensor ?

i believe so, that's why at first i was just using delay as a way to wait for the sensor to finish before i started checking for movement again but ran into the problem of figuring out an auto time off as well. sorry I'm a bit of a newbie at this, it's my first Arduino project

It is very important that the following be confirmed:

  • the PIR sends a HIGH (+5v) to the Arduino input when the PIR detects movement (use a DVM to confirm) OR does the sensor just close a dry relay contact ?
  • if movement is detected every 1 second will the PIR signal to the Arduino ever time out ?
  • if there was constant movement for 2 minutes then all movement stops completely, when would you like the LED to turn OFF ?

Do you have a link to the PIR ?

PIR sends a HIGH to the arduino when it detects movement.
looks like signal doesn't time out and I'm looking to start the auto off timer from when it first detects movement and turns on but also have the option of turning off by motion

This is confusing "looks like signal doesn't time out", please explain ?

Also, explain this "but also have the option of turning off by motion"

Do you have a LINK to the PIR ?


Where does the PIR gets its power from ?

Is this how you have things wired ?

PIR is HC-SR501 PIR Motion Sensor Module | Elektor
if movement is constantly detected it will send a HIGH signal for a long as it's there.
I'm looking to have the motion detection as just a switch to turn it on and off so i can swipe my foot and switch it on and off, but if it's on it has a timer for 15 min to auto turn off.

have the pir power, GND and signal connected directly to the Arduino and the light connected separately to another pin

just a real basic thing similar to this

Please confirm:

  • So the Arduino is powering the PIR from its 5V pin ?
  • You have set the PIR to output a momentary signal to the Arduino, lets assume you have set this to a 1 second pulse when the PIR detects your foot movement ?
  • you move your foot the LED light will turn ON, you move your foot again the light will go OFF ?
  • if you move your foot to turn on the LED light and then not move your foot again, you want the LED light to go OFF after 15 minutes ?

yep powered from the 5v pin.
i think the HIGH pulse it sends is a couple seconds long but yeah essentially.
and yep those are the things I'm looking to do with it.

Try this:

// Version  YY/MM/DD  Description
// 1.00     21/07/03  Functional code
// 1.01     21/07/03  Added comments
// 1.02     21/07/03  Changed so PIR gives ON/OFF control

//*********************************************************************
#define movementDetection  HIGH

#define LEDon              HIGH
#define LEDoff             LOW

#define enabled            true
#define disabled           false

//*********************************************************************
const byte heartbeatLED  = 13;
const byte  led          = 8;
const byte  pir          = 2;

bool autoOffFlag         = disabled;

byte lastPIRstate        = !movementDetection;
byte val;
byte state               = 0;
byte LEDstate            = LEDoff;


//Timing stuff
const unsigned long timeoutDuration   = 10000;            //10 seconds for testing
//const unsigned long timeoutDuration = 15 * 60 * 1000ul; //15 minutes

unsigned long heartbeatMillis;
unsigned long switchMillis;
unsigned long autoMillis;

//*********************************************************************
void setup()
{
  pinMode(heartbeatLED, OUTPUT);

  //turn the light OFF
  digitalWrite(led, LEDoff);
  pinMode(led, OUTPUT);

  pinMode(pir, INPUT);

} //END of setup()

//*********************************************************************
void loop()
{
  //***********************
  //time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 500)
  {
    //restart the TIMER
    heartbeatMillis = millis();

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //***********************
  //time to check the switches ?
  if (millis() - switchMillis >= 50)
  {
    //restart the TIMER
    switchMillis = millis();

    checkSwitches();
  }

  //***********************
  //if enabled, has the TIMER reached the timeout interval ?
  if (autoOffFlag == enabled && millis() - autoMillis >= timeoutDuration)
  {
    //disable the TIMER
    autoOffFlag = disabled;

    //toggle the LED light
    LEDstate = LEDoff;

    //turn the light OFF
    digitalWrite(led, LEDoff);
  }

} //END of loop()


//*********************************************************************
void checkSwitches()
{
  //*****************************************    PIR
  //
  byte state = digitalRead(pir);

  //***********************
  //has the PIR changed state ?
  if (lastPIRstate != state)
  {
    //update to the new state
    lastPIRstate = state;

    //************
    //has the PIR detected movement ?
    if (state == movementDetection)
    {
      //toggle the LED light
      LEDstate = !LEDstate;

      digitalWrite(led, LEDstate);

      if (LEDstate == LEDon)
      {
        //enable the TIMER
        autoOffFlag = enabled;

        //start the TIMER
        autoMillis = millis();
      }

      else
      {
        //disable the TIMER
        autoOffFlag = disabled;
      }

    }

  } //END of  if (lastPIRstate != state)


} //END of  checkSwitches()

//*********************************************************************

when running that the light turns on when motion is detected but only for 10 sec then turns off

Do you see in the code (line 29) where you can change the time to 15 minutes ?

//Timing stuff
const unsigned long timeoutDuration = 10000; //10 seconds for testing
//const unsigned long timeoutDuration = 15 * 60 * 1000ul; //15 minutes

Change to:
//Timing stuff
//const unsigned long timeoutDuration = 10000; //10 seconds for testing
const unsigned long timeoutDuration = 15 * 60 * 1000ul; //15 minutes