Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. General Discussion
  3. pir trigger must start delay

pir trigger must start delay

Scheduled Pinned Locked Moved General Discussion
16 Posts 4 Posters 3.1k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • gohanG Offline
    gohanG Offline
    gohan
    Mod
    wrote on last edited by
    #3

    During sleep you can only wake it up by using the interrupts of pins 2 and 3. Is it a battery powered node?

    1 Reply Last reply
    0
    • DickD Dick

      Is there anyone who can me help with the next step in getting this sensor to work. It is a combi of 3 relays, motion sensor and 2 temps. All works now but if the Motion is triggered it starts the SLEEP_TIME. but in this period I cannot use the buttons to activate the relays. How can I only stop the motion trigger (for a period of time) without affecting the test of the sensors.

      m26872M Offline
      m26872M Offline
      m26872
      Hardware Contributor
      wrote on last edited by m26872
      #4

      @Dick You should use a non-blocking code. Replace your if ( motionsDebouncer.update()) {...} with an updateMotion(SLEEP_TIME); which could be something like

      void updateMotion(unsigned long blockedMotionTime)
      {
        static unsigned long lastUpdateTime;
        if (millis() - lastUpdateTime >= blockedMotionTime)
        {
      	  if ( motionsDebouncer.update()) {
      		int value = motionsDebouncer.read();
      		Serial.println( "PIR " + (String)value );
      		gw.send( msgMOTION.set( value ), true );
      		lastUpdateTime += blockedMotionTime;
      	  }
        }  
      }
      

      Never use sleep if you want to listen for incoming messages. wait is not good either since you expect button press. Buttons could use an interruptpin if needed, but it looks like your not on battery.

      DickD 2 Replies Last reply
      1
      • m26872M m26872

        @Dick You should use a non-blocking code. Replace your if ( motionsDebouncer.update()) {...} with an updateMotion(SLEEP_TIME); which could be something like

        void updateMotion(unsigned long blockedMotionTime)
        {
          static unsigned long lastUpdateTime;
          if (millis() - lastUpdateTime >= blockedMotionTime)
          {
        	  if ( motionsDebouncer.update()) {
        		int value = motionsDebouncer.read();
        		Serial.println( "PIR " + (String)value );
        		gw.send( msgMOTION.set( value ), true );
        		lastUpdateTime += blockedMotionTime;
        	  }
          }  
        }
        

        Never use sleep if you want to listen for incoming messages. wait is not good either since you expect button press. Buttons could use an interruptpin if needed, but it looks like your not on battery.

        DickD Offline
        DickD Offline
        Dick
        wrote on last edited by
        #5

        @m26872
        thanks for the short lesson. I change the code it test it.

        1 Reply Last reply
        1
        • m26872M m26872

          @Dick You should use a non-blocking code. Replace your if ( motionsDebouncer.update()) {...} with an updateMotion(SLEEP_TIME); which could be something like

          void updateMotion(unsigned long blockedMotionTime)
          {
            static unsigned long lastUpdateTime;
            if (millis() - lastUpdateTime >= blockedMotionTime)
            {
          	  if ( motionsDebouncer.update()) {
          		int value = motionsDebouncer.read();
          		Serial.println( "PIR " + (String)value );
          		gw.send( msgMOTION.set( value ), true );
          		lastUpdateTime += blockedMotionTime;
          	  }
            }  
          }
          

          Never use sleep if you want to listen for incoming messages. wait is not good either since you expect button press. Buttons could use an interruptpin if needed, but it looks like your not on battery.

          DickD Offline
          DickD Offline
          Dick
          wrote on last edited by
          #6

          @m26872 I implemented the function but it does not work. I also read more about the NON BLOCKING code. is new for me. At the moment the pir pin give no reaction. nothing happend with the new function. The relays and temp sensors are working fine. Any idea to get it work so I can see a working example so I can use it in my other sensors.

          m26872M 1 Reply Last reply
          0
          • DickD Dick

            @m26872 I implemented the function but it does not work. I also read more about the NON BLOCKING code. is new for me. At the moment the pir pin give no reaction. nothing happend with the new function. The relays and temp sensors are working fine. Any idea to get it work so I can see a working example so I can use it in my other sensors.

            m26872M Offline
            m26872M Offline
            m26872
            Hardware Contributor
            wrote on last edited by
            #7

            @Dick I'm no code expert, but I would make the two lastUpdateTime-variables as global ones and initialize them with 0.

            DickD 1 Reply Last reply
            0
            • m26872M m26872

              @Dick I'm no code expert, but I would make the two lastUpdateTime-variables as global ones and initialize them with 0.

              DickD Offline
              DickD Offline
              Dick
              wrote on last edited by
              #8

              @m26872 it is all new for me this solution. How can I make them global?? that means outside the function? is that the only thing I have to do?

              m26872M 1 Reply Last reply
              0
              • DickD Dick

                @m26872 it is all new for me this solution. How can I make them global?? that means outside the function? is that the only thing I have to do?

                m26872M Offline
                m26872M Offline
                m26872
                Hardware Contributor
                wrote on last edited by
                #9

                @Dick Since they are 'static' I think you only need to initialize them with 0 , maybe not even that. I simply dont know. Your problem could be something else too. Sorry.

                DickD 1 Reply Last reply
                0
                • m26872M m26872

                  @Dick Since they are 'static' I think you only need to initialize them with 0 , maybe not even that. I simply dont know. Your problem could be something else too. Sorry.

                  DickD Offline
                  DickD Offline
                  Dick
                  wrote on last edited by
                  #10

                  @m26872 No Problem. I continue reading. If someone else knows what to do please reply.

                  1 Reply Last reply
                  0
                  • BartEB Offline
                    BartEB Offline
                    BartE
                    Contest Winner
                    wrote on last edited by BartE
                    #11

                    @Dick said in pir trigger must start delay:

                    Replace this piece of code

                      if ( motionsDebouncer.update()) {
                         int value = motionsDebouncer.read();
                         Serial.println( "PIR " + (String)value );
                         gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                         
                     // Sleep until interrupt comes in on motion sensor. Send update.
                       gw.sleep(DIGITAL_MOTION_SENSOR, CHANGE, SLEEP_TIME);
                       }
                    

                    with something like this

                    if (blockMotionTimer == 0) {
                    {
                        if (motionsDebouncer.update()) {
                            int value = motionsDebouncer.read();
                            Serial.println( "PIR " + (String)value );
                            gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                            blockMotionTimer = (millis() + SLEEP_TIME);
                       } else {
                            motionsDebouncer.update(); // dummy update to prevent false trigger after timer expires 
                            if (blockMotionTimer < millis()) {
                                blockMotionTimer = 0;
                            }
                       }
                    }
                    

                    Add this line at the top of your sketch (just below SLEEP_TIME)

                    unsigned long blockMotionTimer = 0;
                    
                    DickD 1 Reply Last reply
                    0
                    • BartEB BartE

                      @Dick said in pir trigger must start delay:

                      Replace this piece of code

                        if ( motionsDebouncer.update()) {
                           int value = motionsDebouncer.read();
                           Serial.println( "PIR " + (String)value );
                           gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                           
                       // Sleep until interrupt comes in on motion sensor. Send update.
                         gw.sleep(DIGITAL_MOTION_SENSOR, CHANGE, SLEEP_TIME);
                         }
                      

                      with something like this

                      if (blockMotionTimer == 0) {
                      {
                          if (motionsDebouncer.update()) {
                              int value = motionsDebouncer.read();
                              Serial.println( "PIR " + (String)value );
                              gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                              blockMotionTimer = (millis() + SLEEP_TIME);
                         } else {
                              motionsDebouncer.update(); // dummy update to prevent false trigger after timer expires 
                              if (blockMotionTimer < millis()) {
                                  blockMotionTimer = 0;
                              }
                         }
                      }
                      

                      Add this line at the top of your sketch (just below SLEEP_TIME)

                      unsigned long blockMotionTimer = 0;
                      
                      DickD Offline
                      DickD Offline
                      Dick
                      wrote on last edited by
                      #12

                      @BartE Hi Bart thanks for the solution but hopefully you can help me with the last hurdle:
                      I added your solution, after starting the node I can activate the PIR once (it state change from 1 to 0) and stays in 0 and will not change anymore.
                      Here the code as it is now

                      // 2x binary switch + dallas temp example 
                      // Connect button or door/window reed switch between 
                      // digitial I/O pin 4,5 (BUTTON_PIN_4/BUTTON_PIN_5 below) and GND.
                      // Connect dallas temp sensor to digital pin 3
                      
                      #include <MySensor.h>
                      #include <SPI.h>
                      #include <Bounce2.h>
                      #include <DallasTemperature.h>
                      #include <OneWire.h>
                      #define DIGITAL_MOTION_SENSOR 2
                      #define CHILD_ID_MOTION 6
                      #define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected 
                      #define MAX_ATTACHED_DS18B20 16
                      #define RELAY_ON 0                      // switch around for realy HIGH/LOW state
                      #define RELAY_OFF 1
                      
                      Bounce motionsDebouncer = Bounce();
                      
                      int lastMOTION;
                      unsigned long SLEEP_TIME = 3600;
                      unsigned long blockMotionTimer = 0;
                      
                      
                      OneWire oneWire(ONE_WIRE_BUS);
                      DallasTemperature sensors(&oneWire);
                      MySensor gw;
                      
                      #define noRelays 3
                      const int relayPin[] = {A3, A4, A5}; //  switch around pins to your desire
                      const int buttonPin[] = {6, 7, 8}; //  switch around pins to your desire
                      
                      class Relay             // relay class, store all relevant data (equivalent to struct)
                      {
                      public: 
                        int buttonPin;                    // physical pin number of button
                        int relayPin;                     // physical pin number of relay
                        byte oldValue;                    // last Values for key (debounce)
                        boolean relayState;               // relay status (also stored in EEPROM)
                      };
                      
                      Relay Relays[noRelays];
                      Bounce debouncerRELAY[noRelays];
                      MyMessage msgRELAY[noRelays];
                      
                      
                      float lastTemperature[MAX_ATTACHED_DS18B20];
                      int numSensors=0;
                      boolean receivedConfig = false;
                      boolean metric = true; 
                      MyMessage msg(0,V_TEMP);
                      MyMessage msgMOTION(CHILD_ID_MOTION, V_TRIPPED);
                      
                      void setup()  
                      {  
                        sensors.begin();
                        //gw.begin();
                        gw.begin(incomingMessage, AUTO, true);
                        gw.sendSketchInfo("Motion/Temp/relay", "1.0");
                        numSensors = sensors.getDeviceCount();
                        for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) 
                        {   
                          gw.present(i, S_TEMP);
                        }
                      
                      
                       
                      pinMode(DIGITAL_MOTION_SENSOR, INPUT_PULLUP);      // sets the motion sensor digital pin as input
                        motionsDebouncer.attach(DIGITAL_MOTION_SENSOR);
                        motionsDebouncer.interval(400);
                        // Register all sensors to gw (they will be created as child devices)
                        gw.present(CHILD_ID_MOTION, S_MOTION, "Motion needs presentation", true);
                      
                         for (int i = 0; i < noRelays; i++)
                        {
                          Relays[i].buttonPin = buttonPin[i];              // assign physical pins
                          Relays[i].relayPin = relayPin[i];
                          msgRELAY[i].sensor = i;                                   // initialize messages
                          msgRELAY[i].type = V_LIGHT;
                          debouncerRELAY[i] = Bounce();                        // initialize debouncer
                          debouncerRELAY[i].attach(buttonPin[i]);
                          debouncerRELAY[i].interval(5);
                          pinMode(Relays[i].buttonPin, INPUT_PULLUP);
                          pinMode(Relays[i].relayPin, OUTPUT);
                          Relays[i].relayState = gw.loadState(i);                               // retrieve last values from EEPROM
                          digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF); // and set relays accordingly
                          gw.send(msgRELAY[i].set(Relays[i].relayState ? true : false));                 // make controller aware of last status
                          gw.present(i, S_LIGHT);                               // present sensor to gateway
                          delay(250);
                      
                        }
                          
                      }
                      void loop() 
                      {
                      gw.process(); 
                      
                      for (byte i = 0; i < noRelays; i++)
                        {
                          debouncerRELAY[i].update();
                          byte value = debouncerRELAY[i].read();
                          if (value != Relays[i].oldValue && value == 0)
                          {
                            Relays[i].relayState = !Relays[i].relayState;
                            digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF);
                            gw.send(msgRELAY[i].set(Relays[i].relayState ? true : false));
                            gw.saveState( i, Relays[i].relayState );
                          }                 // save sensor state in EEPROM (location == sensor number)
                      
                          Relays[i].oldValue = value;
                        }
                        
                        if (blockMotionTimer == 0) {
                      {
                          if (motionsDebouncer.update()) {
                              int value = motionsDebouncer.read();
                              Serial.println( "PIR " + (String)value );
                              gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                              blockMotionTimer = (millis() + SLEEP_TIME);
                         } else {
                              motionsDebouncer.update(); // dummy update to prevent false trigger after timer expires 
                              if (blockMotionTimer < millis()) {
                                  blockMotionTimer = 0;
                              }
                         }
                      }
                        }
                      
                         
                       
                        
                        updateTemperature(30);// update time in seconds
                        
                      }
                      
                      void updateTemperature(int frequency)
                      {
                        static unsigned long lastUpdateTime;
                        if (millis() - lastUpdateTime >= frequency * 1000UL)
                        {
                          sensors.requestTemperatures(); 
                          for (int i=0; i<numSensors && i< MAX_ATTACHED_DS18B20; i++) 
                          {
                            float temperature = static_cast<float>(static_cast<int>((gw.getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;
                            if (lastTemperature[i] != temperature && temperature != -127.00) 
                            {
                              gw.send(msg.setSensor(i).set(temperature,1));
                              lastTemperature[i]=temperature;
                            }
                          }
                          lastUpdateTime += frequency * 1000UL;
                        }
                      }
                      
                      void incomingMessage(const MyMessage &message)
                      {
                      
                        if (message.type == V_LIGHT)
                        {
                          if (message.sensor < noRelays)            // check if message is valid for relays..... previous line  [[[ if (message.sensor <=noRelays){ ]]]
                          {
                            Relays[message.sensor].relayState = message.getBool();
                            digitalWrite(Relays[message.sensor].relayPin, Relays[message.sensor].relayState ? RELAY_ON : RELAY_OFF); // and set relays accordingly
                            gw.saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
                          }
                        }
                      //gw.wait(50);
                      
                      }
                      
                      `
                      1 Reply Last reply
                      0
                      • BartEB Offline
                        BartEB Offline
                        BartE
                        Contest Winner
                        wrote on last edited by BartE
                        #13

                        @Dick mm look like a } on the wrong line. The } on line 126 should move up between line 119 and 120
                        (and there are 2 additional brackets)

                        The result should look like this

                        
                        if (blockMotionTimer == 0) {
                            if (motionsDebouncer.update()) {
                                int value = motionsDebouncer.read();
                                Serial.println( "PIR " + (String)value );
                                gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                                blockMotionTimer = (millis() + SLEEP_TIME);
                           }
                        } else {
                                motionsDebouncer.update(); // dummy update to prevent false trigger after timer expires 
                                if (blockMotionTimer < millis()) {
                                    blockMotionTimer = 0;
                                }
                        }
                        
                        
                        DickD 1 Reply Last reply
                        0
                        • BartEB BartE

                          @Dick mm look like a } on the wrong line. The } on line 126 should move up between line 119 and 120
                          (and there are 2 additional brackets)

                          The result should look like this

                          
                          if (blockMotionTimer == 0) {
                              if (motionsDebouncer.update()) {
                                  int value = motionsDebouncer.read();
                                  Serial.println( "PIR " + (String)value );
                                  gw.send( msgMOTION.set( value ), true ); // Also it might need inverted value
                                  blockMotionTimer = (millis() + SLEEP_TIME);
                             }
                          } else {
                                  motionsDebouncer.update(); // dummy update to prevent false trigger after timer expires 
                                  if (blockMotionTimer < millis()) {
                                      blockMotionTimer = 0;
                                  }
                          }
                          
                          
                          DickD Offline
                          DickD Offline
                          Dick
                          wrote on last edited by
                          #14

                          @BartE It works fine. Now I try to understand how it works, have found already some documentation about this item. again thanks!

                          BartEB 1 Reply Last reply
                          0
                          • DickD Dick

                            @BartE It works fine. Now I try to understand how it works, have found already some documentation about this item. again thanks!

                            BartEB Offline
                            BartEB Offline
                            BartE
                            Contest Winner
                            wrote on last edited by
                            #15

                            @Dick nice to hear

                            How it works:

                            As long as 'blockMotionTimer' is zero the motion debouncer is being monitored for any change.
                            When a PIR-change is detected the blockMotionTimer gets the value of the Arduino's internal milliseconds timer + the delay in milliseconds one want to wait.
                            This happes on this line: "blockMotionTimer = (millis() + SLEEP_TIME);"
                            See more about the millis() here

                            The blockMotionTimer is set back to zero the when mills() reaches the value set for time-out done with this check "if (blockMotionTimer < millis()) {" , and because the blockMotionTimer is non-zero the PIR value will not be checked during this period.

                            Expert note: since the milliseconds counter is returned in an unsigned long it will carry over one moment in time. Since Arduino stores it's ulong in 32 bits this means a carry over each 2^32 thus 4294967296 milliseconds. This is approx. every 50 days (49,71 days) So in theory this mechanism could result in a wrong (very short) delay, when timer is started precisely with the SLEEP_TIME period just before these 49,71 days. The result of millis() + SLEEP_TIME will then carry over and is immediate smaller than millis() on the next check. So be aware that this check if (blockMotionTimer > (millis() - SLEEP_TIME)) can result in a death-lock when blockMotionTimer = millis(); was set on the wrong moment in time.

                            DickD 1 Reply Last reply
                            0
                            • BartEB BartE

                              @Dick nice to hear

                              How it works:

                              As long as 'blockMotionTimer' is zero the motion debouncer is being monitored for any change.
                              When a PIR-change is detected the blockMotionTimer gets the value of the Arduino's internal milliseconds timer + the delay in milliseconds one want to wait.
                              This happes on this line: "blockMotionTimer = (millis() + SLEEP_TIME);"
                              See more about the millis() here

                              The blockMotionTimer is set back to zero the when mills() reaches the value set for time-out done with this check "if (blockMotionTimer < millis()) {" , and because the blockMotionTimer is non-zero the PIR value will not be checked during this period.

                              Expert note: since the milliseconds counter is returned in an unsigned long it will carry over one moment in time. Since Arduino stores it's ulong in 32 bits this means a carry over each 2^32 thus 4294967296 milliseconds. This is approx. every 50 days (49,71 days) So in theory this mechanism could result in a wrong (very short) delay, when timer is started precisely with the SLEEP_TIME period just before these 49,71 days. The result of millis() + SLEEP_TIME will then carry over and is immediate smaller than millis() on the next check. So be aware that this check if (blockMotionTimer > (millis() - SLEEP_TIME)) can result in a death-lock when blockMotionTimer = millis(); was set on the wrong moment in time.

                              DickD Offline
                              DickD Offline
                              Dick
                              wrote on last edited by
                              #16

                              @BartE What an extended answere. Here I can do something with. Good learning stuff.

                              1 Reply Last reply
                              0
                              Reply
                              • Reply as topic
                              Log in to reply
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes


                              22

                              Online

                              11.7k

                              Users

                              11.2k

                              Topics

                              113.1k

                              Posts


                              Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                              • Login

                              • Don't have an account? Register

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • MySensors
                              • OpenHardware.io
                              • Categories
                              • Recent
                              • Tags
                              • Popular