pir sensor timer

Im having a problem setting up a timer with a pir sensor.

what im aiming to do is to set it up so if the sensor detects motion it comes on and sets a timer to turn off, moving forward if the timer is not up yet and it detects motion again the timer will reset so the light can stay on.

example:
motion detected - light turns on
45 second timer is started
at 15 seconds left motion is detected again
timer will reset to 45 - light stays on

is this something that needs to be done with threading or is there another way?

Here is simple_oneShot example: Change HOLD_MS to 45000.0 and you are good to go.

#include <mechButton.h>

#define  TRIGGER_PIN 2        // What pin the trigger will be on.
#define  OUT_PIN     13       // What pin we'll toggle high when the trigger goes low.
#define  HOLD_MS     500      // How long we'll hold the output high after being triggered.


mechButton  trigger(TRIGGER_PIN);   // Button debouncer.
timeObj     timer;                  // Our output hold timer.


// Your standard Arduino setup() function.
void setup() {
   
   pinMode(OUT_PIN,OUTPUT);               // Setup output pin.
   digitalWrite(OUT_PIN,LOW);             // Lets make sure its off.
   trigger.setCallback(triggerAction);    // Set up the function to call when the trigger is clicked.
   timer.setTime(HOLD_MS,false);          // Set the timer, but don't start it yet.
}


// When you click the button, this function will be called.
void triggerAction(void) {

   if (!trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
      digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      timer.start();                // And start the timer.
   }
}


// Your standard Arduino loop() function.
void loop() {
   
   idle();                       // Give the stuff running behind the scenes time to run.
   if (timer.ding()) {           // If the timer has expired..
      digitalWrite(OUT_PIN,LOW); // Shut down the output.
      timer.reset();             // Reset the timer for next time.
   }
}

Gran LC_basetools form the IDE library manger and see if it works. To change this from a button to a sensor. pUll out the button code, then write a function that reads the sensor and calls timer.start(); when it sees motion. Call this function every time through loop();

-jim lee

the timer works amazing i tested it with the sensor and an led however when i tired using the timer and connecting to the wifi to control some lights it would turn on the light but the timer would to progress and turn them off after it was done

bool state = false;

#define  TRIGGER_PIN 2        // What pin the trigger will be on.
#define  OUT_PIN     LED_BUILTIN       // What pin we'll toggle high when the trigger goes low.
#define  HOLD_MS     15000      // How long we'll hold the output high after being triggered.


mechButton  trigger(TRIGGER_PIN);   // Button debouncer.
timeObj     timer;                  // Our output hold timer.


// Your standard Arduino setup() function.
void setup() {// put your setup code here, to run once:
  
  Serial.begin(115200);
  WiFi.begin(ssid, password); 
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("Connected to the WiFi network");
  {
    pinMode(OUT_PIN,OUTPUT);               // Setup output pin.
  digitalWrite(OUT_PIN,LOW);             // Lets make sure its off.
  trigger.setCallback(triggerAction);    // Set up the function to call when the trigger is clicked.
  timer.setTime(HOLD_MS,false);          // Set the timer, but don't start it yet.
   
  }
  
  

}

// When you click the button, this function will be called.
void triggerAction(void) {

   if (!trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
      switchLight(1, true);
      digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      
      timer.start();                // And start the timer.
   }
}


// Your standard Arduino loop() function.
void loop() {
   
   idle();                       // Give the stuff running behind the scenes time to run.
   if (timer.ding()) {           // If the timer has expired..
      switchLight(1, false);
      digitalWrite(OUT_PIN,LOW); // Shut down the output.
      
      timer.reset();             // Reset the timer for next time.
   }
}
      
 


void switchLight(byte room, bool current_state){
  state = current_state;
  HTTPClient http; 
  String req_string;
  req_string = "http://";
  req_string += ip;
  req_string += "/api/";
  req_string += user_name;
  req_string += "/lights/";
  req_string += light_id;
  req_string += "/state";
  Serial.println(req_string);
  http.begin(req_string);
  http.addHeader("Content-Type", "text/plain");
  
  String put_string;
  put_string = "{\"on\":";
  put_string += (current_state)? "true" : "false";
  put_string += "}";
  
  int httpResponseCode = http.PUT(put_string);
  
  if(httpResponseCode > 0){
    String response = http.getString();   
    Serial.println(httpResponseCode);
    Serial.println(response);          
   } else {
    Serial.print("Error on sending PUT Request: ");
    Serial.println(httpResponseCode);
   }
   http.end();
}

This isn't your complete code. You're missing the #defines and the sensor stuff. Also, you never changed the #define for timeout to 45000.0 ms

Lets see the complete thing.

-jim lee

Maybe something like this just using millis() and an FSM:

(Note: Not compiled as you didn't provide a full sketch that compiled on its own. YMMV.)

bool state = false;

#define  TRIGGER_PIN    2        // What pin the trigger will be on.
#define  OUT_PIN        LED_BUILTIN       // What pin we'll toggle high when the trigger goes low.
#define  HOLD_MS        15000      // How long we'll hold the output high after being triggered.

#define ACTIVE_LEVEL    LOW         //based on comment above re "when the trigger goes low"

#define STATE_IDLE      0
#define STATE_ON        1

uint32_t
    timeNow,
    timePIR;    
uint8_t 
    statePIR;

// Your standard Arduino setup() function.
void setup() 
{
    // put your setup code here, to run once: 
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(1000);
        Serial.print(".");
    }
    
    Serial.println("Connected to the WiFi network");
    pinMode(OUT_PIN,OUTPUT);               // Setup output pin.
    digitalWrite(OUT_PIN,LOW);             // Lets make sure its off.
    pinMode( TRIGGER_PIN, INPUT );          //PIR input (assumes actively-driven PIR output)
    statePIR = STATE_IDLE;
        
}//setup

void loop( void )
{        
    timeNow = millis();

    switch( statePIR )
    {
        case    STATE_IDLE:
            //waiting for PIR to sense movement
            if( digitalRead( TRIGGER_PIN ) == ACTIVE_LEVEL )
            {
                //movement sensed
                //save time now for 45-sec interval
                timePIR = timeNow;
                //set output pin HIGH
                digitalWrite(OUT_PIN,HIGH);
                //send true msg
                switchLight( 1, true );
                //move to on state
                statePIR = STATE_ON;
                        
            }//if
        
        break;
        
        case    STATE_ON:
            //if PIR pin is high, reset timer
            if( digitalRead( TRIGGER_PIN ) == ACTIVE_LEVEL )
                timePIR = timeNow;            
            else if( (timeNow - timePIR) >= 45000ul )
            {
                //PIR stayed inactive for 45-sec
                //set output low
                digitalWrite(OUT_PIN,LOW);
                //send false message
                switchLight( 1, false );
                //and return to idle state
                statePIR = STATE_IDLE;
                
            }//else if
            
        break;
        
    }//switch       
    
}//loop
     
void switchLight(byte room, bool current_state)
{
    state = current_state;
    HTTPClient http;
    String req_string;
    req_string = "http://";
    req_string += ip;
    req_string += "/api/";
    req_string += user_name;
    req_string += "/lights/";
    req_string += light_id;
    req_string += "/state";
    Serial.println(req_string);
    http.begin(req_string);
    http.addHeader("Content-Type", "text/plain");
    
    String put_string;
    put_string = "{\"on\":";
    put_string += (current_state)? "true" : "false";
    put_string += "}";
    
    int httpResponseCode = http.PUT(put_string);
    
    if(httpResponseCode > 0)
    {
        String response = http.getString();   
        Serial.println(httpResponseCode);
        Serial.println(response);         
    } 
    else 
    {
        Serial.print("Error on sending PUT Request: ");
        Serial.println(httpResponseCode);
    }
    http.end();
    
}//switchLight

@jimlee i have it at 15 seconds just to test it so i dont have to wait the full 45. So after you sent this to me i tired it on the nano and set the input and output pin code to the setup and it worked perfectly so i figured i could add the code i needed to set it up for sending what i needed for the wifi. could it be not working because i have the code now uploaded to the esp8266 the small one with the 8 pins i have the sensor coming in at gpio2

@blackfin also thank you for replying to help me try and figure things out the only thing i didnt put in the code was my wifi and client info but i tired your code as well and same thing light will turn on but will not turn off could this be because the code is now uploaded to the esp and it cant handle and timer and wifi signal at the same time?

Well, lets see the code you uploaded. Post it here, do the code tags thing.

Did you check with just the sensor and nothing else if its active high or low? Or bouncing about high and low?

-jim lee

bool state = false;

#define  TRIGGER_PIN 2        // What pin the trigger will be on.
//#define  OUT_PIN  LED_BUILTIN  // What pin we'll toggle high when the trigger goes low.
#define  HOLD_MS  15000      // How long we'll hold the output high after being triggered.

mechButton  trigger(TRIGGER_PIN);   // Button debouncer.
timeObj     timer;                  // Our output hold timer.

// Your standard Arduino setup() function.
void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(1000);
        Serial.print(".");
    }
    
    Serial.println("Connected to the WiFi network");
//    pinMode(OUT_PIN,OUTPUT);               // Setup output pin.
//    digitalWrite(OUT_PIN,LOW);             // Lets make sure its off.
    trigger.setCallback(triggerAction);    // Set up the function to call when the trigger is clicked.
    timer.setTime(HOLD_MS,false);          // Set the timer, but don't start it yet.

        
}//setup
void triggerAction(void) {
  if (!trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
    switchLight(1, true);
//    digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
    timer.start();                // And start the timer.
   }
}

// Your standard Arduino loop() function.
void loop() {
   idle();                       // Give the stuff running behind the scenes time to run.
   if (timer.ding()) {           // If the timer has expired..
      switchLight(1, false);
//      digitalWrite(OUT_PIN,LOW); // Shut down the output.
      timer.reset();             // Reset the timer for next time.
   }
}

    
void switchLight(byte room, bool current_state)
{
    state = current_state;
    HTTPClient http;
    String req_string;
    req_string = "http://";
    req_string += ip;
    req_string += "/api/";
    req_string += user_name;
    req_string += "/lights/";
    req_string += light_id;
    req_string += "/state";
    Serial.println(req_string);
    http.begin(req_string);
    http.addHeader("Content-Type", "text/plain");
    
    String put_string;
    put_string = "{\"on\":";
    put_string += (current_state)? "true" : "false";
    put_string += "}";
    
    int httpResponseCode = http.PUT(put_string);
    
    if(httpResponseCode > 0)
    {
        String response = http.getString();  
        Serial.println(httpResponseCode);
        Serial.println(response);        
    }
    else
    {
        Serial.print("Error on sending PUT Request: ");
        Serial.println(httpResponseCode);
    }
    http.end();
    
}//switchLight

here is code everything besides personal info and yes i checked sensor and even tried a different one
i also tried with the output pin commented out maybe thinking it was getting stuck on dealing with the built in led still will not turn off the hue light

Where is #define of the libraries? Where is this sensor stuff? Are you not using the sensor and still using the button? Are you connecting the sensor up as if it were a button?

And maybe try this..

void triggerAction(void) {
   if (!trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
      switchLight(1, true);
      Serial.println("Trigger");
      //    digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      timer.start();                // And start the timer.
   }
}

Lest see if there's something odd in trigger that we are not seeing going on.

-jim lee

here is complete code

#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <mechButton.h>

// IP of Hue gateway
String ip = "xxxxxxxx";

// Hue gateway user name
String user_name = "xxxxxxxxxxxxxxxx";

// Light identificator
int light_id = 13;

// Wifi network SSID
const char* ssid = "xxxxx";

// Wifi network password
const char* password = "xxxxx";

bool state = false;

#define  TRIGGER_PIN 2        // What pin the trigger will be on.
//#define  OUT_PIN  LED_BUILTIN  // What pin we'll toggle high when the trigger goes low.
#define  HOLD_MS  15000      // How long we'll hold the output high after being triggered.

mechButton  trigger(TRIGGER_PIN);   // Button debouncer.
timeObj     timer;                  // Our output hold timer.

// Your standard Arduino setup() function.
void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(1000);
        Serial.print(".");
    }
    
    Serial.println("Connected to the WiFi network");
//    pinMode(OUT_PIN,OUTPUT);               // Setup output pin.
//    digitalWrite(OUT_PIN,LOW);             // Lets make sure its off.
    trigger.setCallback(triggerAction);    // Set up the function to call when the trigger is clicked.
    timer.setTime(HOLD_MS,false);          // Set the timer, but don't start it yet.

        
}//setup
void triggerAction(void) {
   if (!trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
      switchLight(1, true);
      Serial.println("Trigger");
      //    digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      timer.start();                // And start the timer.
   }
}
// Your standard Arduino loop() function.
void loop() {
   idle();                       // Give the stuff running behind the scenes time to run.
   if (timer.ding()) {           // If the timer has expired..
      switchLight(1, false);
//      digitalWrite(OUT_PIN,LOW); // Shut down the output.
      timer.reset();             // Reset the timer for next time.
   }
}

    
void switchLight(byte room, bool current_state)
{
    state = current_state;
    HTTPClient http;
    String req_string;
    req_string = "http://";
    req_string += ip;
    req_string += "/api/";
    req_string += user_name;
    req_string += "/lights/";
    req_string += light_id;
    req_string += "/state";
    Serial.println(req_string);
    http.begin(req_string);
    http.addHeader("Content-Type", "text/plain");
    
    String put_string;
    put_string = "{\"on\":";
    put_string += (current_state)? "true" : "false";
    put_string += "}";
    
    int httpResponseCode = http.PUT(put_string);
    
    if(httpResponseCode > 0)
    {
        String response = http.getString();  
        Serial.println(httpResponseCode);
        Serial.println(response);        
    }
    else
    {
        Serial.print("Error on sending PUT Request: ");
        Serial.println(httpResponseCode);
    }
    http.end();
    
}//switchLight

this is what it keeps looping through the light still turns on but i dont see it print the trigger

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 3584, room 16 
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
Connecting to WiFi..Connected to the WiFi network
http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Exception (9):
epc1=0x40207b7c epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000282 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffcc0 end: 3fffffc0 offset: 0190
3ffffe50:  402046e0 3ffee524 3ffe8706 402049c1  
3ffffe60:  00000001 00000000 3ffffe90 40201478  
3ffffe70:  00000001 000000c8 3ffffe90 40202220  
3ffffe80:  00000001 000000c8 3ffee524 4020125f  
3ffffe90:  00000000 00000000 3ffef6a4 3ffef68c  
3ffffea0:  000d000f 00ffdad0 3f010050 00001388  
3ffffeb0:  3ffefc94 003d003f 00000001 70747468  
3ffffec0:  00000000 84ffdad0 3ffeff2c 0000002f  
3ffffed0:  00000000 3ffef594 0011001f 00000030  
3ffffee0:  00000000 3fffdad0 80fee5ac 00000000  
3ffffef0:  00000000 000000c8 ffffffff 3ffe8400  
3fffff00:  00000000 3fff000a 3ffee500 00000030  
3fffff10:  80206e21 00000000 3ffef624 74786500  
3fffff20:  616c702f 80006e69 3ffefacc 000b000f  
3fffff30:  0a006575 3ffef5bc 0051005f 072044b1  
3fffff40:  00000001 3ffee44c 3ffee440 402012ca  
3fffff50:  3fffdad0 3ffee44c 3ffee440 4020449d  
3fffff60:  3fffdad0 00000000 3ffee440 402044d0  
3fffff70:  00000000 3ffee48c 3ffee440 40207d79  
3fffff80:  00000000 00000000 3ffee4fc 40204198  
3fffff90:  3fffdad0 00000000 3ffee56c 4020128e  
3fffffa0:  feefeffe 00000000 3ffee56c 40205e70  
3fffffb0:  feefeffe feefeffe 3ffe84f0 40100bd1  
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 3584, room 16 
tail 0
chksum 0xb0
csum 0xb0
v2843a5ac
~ld
Connecting to WiFi...Connected to the WiFi network

nick_d12:
@blackfin also thank you for replying to help me try and figure things out the only thing i didnt put in the code was my wifi and client info but i tired your code as well and same thing light will turn on but will not turn off could this be because the code is now uploaded to the esp and it cant handle and timer and wifi signal at the same time?

Are you certain the output of the PIR sensor is not showing "active" all the time?

jimLee and I used completely different approaches and you're seeing the same behavior which is suggestive of a hardware cause (not necessarily fault...)

Put a meter or scope on that PIR signal and see what it's doing. Are you sure the pin goes "low" when the PIR detects something?

ill double check with a meter to test it but i dont think so because it worked with the led. On the led test i turned the timer on the sensor itself down to like 3 seconds so it would only grab the input voltage as active to know an output needed to be sent. The original code I was using was with timer thats on the sensor and it was shutting off the hue light. Still, let me double check to we can rule it out if so

it goes to 3.3 for a second or two then down to 0.55

nick_d12:
it goes to 3.3 for a second or two then down to 0.55

In my code, I used your comment "// What pin we'll toggle high when the trigger goes low." to determine the active level of PIR.

Change this line:

#define ACTIVE_LEVEL    LOW         //based on comment above re "when the trigger goes low"

to

#define ACTIVE_LEVEL    HIGH         //

and try it again.

still no luck

You want the trigger to happen when the pin goes high?

void triggerAction(void) {
   if (!trigger.trueFalse()) {      // <<-- [REMOVE THE ! from this line] Causes it to trigger high instead of low.
      switchLight(1, true);
      Serial.println("Trigger");
      //    digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      timer.start();                // And start the timer.
   }
}

-jim lee

Can you run this:

#define  TRIGGER_PIN    2        // What pin the trigger will be on.

void setup()
{
    Serial.begin( 115200 );
    pinMode( TRIGGER_PIN, INPUT );          //PIR input (assumes actively-driven PIR output)    
    
}//setup

void loop( void )
{
    Serial.println( digitalRead( TRIGGER_PIN ) == HIGH ? "1":"0" );
    delay(50);
    
}//loop

Open your serial monitor and set it to 115200-baud.

If the PIR input is high you'll see '1's and if it's low you'll see '0's.

You need to see what the MCU thinks the level on the pin when the PIR sensor is idle and when something moves in front of it.

@jimlee no luck on that either

@Blackfin as expected i get 0's when its in an idle state and 1s if i move my hand infront of it and after a couple seconds back to 0

also i would like to thank you both you guys have been going hard with me trying to figure this out it means a lot

So i was messing around with print statements to keep better track of whats going on

if its like this it will print trigger

void triggerAction(void) {
   if (trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
      Serial.println("Trigger");
      //    digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      
      switchLight(1, true);
      timer.start();

if its like this it will not print trigger

void triggerAction(void) {
   if (trigger.trueFalse()) {      // If the trigger returns false, button has been clicked.
      switchLight(1, true);
      Serial.println("Trigger");
      //    digitalWrite(OUT_PIN,HIGH);   // So we fire the output pin.
      
      
      timer.start();

is it possible that the switchLight function is some how messing up the main loop or interrupting it some how?

nick_d12:
is it possible that the switchLight function is some how messing up the main loop or interrupting it some how?

Was going to make that suggestion next.

In my code (if you like), comment out the calls to

//switchLight( 1, true );

and

//switchLight( 1, false );

Maybe your code is hanging up in switchLight and never getting back to check the PIR sensor and LED.