pir trigger must start delay



  • 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.



  • Here the code to make it more clear

    @Dick said in pir trigger must start delay:

    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.

    // 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 = 60000;
    
    
    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(10);
      // 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 ( 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);
      }
    
       
     
      
      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);
    
    }
    
    

  • Mod

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


  • Hardware Contributor

    @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.



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



  • @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.


  • Hardware Contributor

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



  • @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?


  • Hardware Contributor

    @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.



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


  • Contest Winner

    @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;
    


  • @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);
    
    }
    
    `

  • Contest Winner

    @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;
            }
    }
    
    


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


  • Contest Winner

    @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.



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


Log in to reply
 

Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.