433MHz Motion Sensor sketch



  • I would like to reuse 433MHz Motion sensors from old security alarm system. I connected 433MHz receiver to pin number 2 on arduino nano and combined Motion sensor and RF433 sketches. To my initial surprise sketch actually works; I would only need help with following items:

    -how would I enable sleep mode?

    -delay(1000) between sending tripped value of 1 and 0 doesn't work. That means that regardless of what value is delay node sends value 1 and 0 immediately one after another - that doesn't present the issue in itself but because of short period between messages, second message gets lost sometimes.

    -is it ok that function Void loop remains blank? How would I modify sketch to get function "void showoldcode" into "void loop" (if this makes sense at all)?

    /*
    433MHz Motion Sensor
     * Setup:
     * - connect a 433MHz receiver on digital pin 2.
     *
     * MySensor note: This example has not yet been adopted but can be used as an example
     * of receiving 433Mhz stuff. 
     * 
     * One idea could be to echo received 433 codes back to gateway to be able to pick up and
     * handle data over there.
     *
    */
    #define MY_DEBUG
    
    #define MY_RADIO_NRF24
    
    #include <RemoteReceiver.h>
    #include <InterruptChain.h>
    #include <SPI.h>
    #include <MySensor.h>
    
    unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    
    //#define INTERRUPT 2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define CHILD_ID_1 1   // Id of the sensor child
    #define CHILD_ID_2 2   // Id of the sensor child
    
    // Initialize motion message
    MyMessage msg1(CHILD_ID_1, V_TRIPPED);
    MyMessage msg2(CHILD_ID_2, V_TRIPPED);
    
    void setup() {
      Serial.begin(115200);
    
      // Interrupt -1 to indicate you will call the interrupt handler with InterruptChain
      RemoteReceiver::init(-1, 2, showOldCode);
    
      // On interrupt, call the interrupt handlers of remote and sensor receivers
      InterruptChain::addInterruptCallback(0, RemoteReceiver::interruptHandler);
      Serial.print("433 Motion Sensor");
    }
    
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("433 Motion Sensor", "1.0");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_1, S_MOTION);
      present(CHILD_ID_2, S_MOTION);
    }
    
    void loop() {
       // You can do other stuff here!
    // shows the received code sent from an old-style remote switch
    }
    
    void showOldCode(unsigned long receivedCode, unsigned int period) {
      // Print the received code.
      Serial.print("Code: ");
      Serial.print(receivedCode);
      Serial.print(", period: ");
      Serial.print(period);
      Serial.println("us.");
    
      // Read digital motion value
      //boolean tripped = receivedCode; 
      
      if(receivedCode == 510217) {
              send(msg1.set("1"));  // Send tripped value to gw 
              delay(1000);
              send(msg1.set("0"));
          }
    if(receivedCode == 354240) {
              send(msg2.set("1"));  // Send tripped value to gw 
              delay(1000);
              send(msg2.set("0"));
          }
    
        // Sleep until interrupt comes in on motion sensor. Send update every two minute. 
      //sleep(INTERRUPT,CHANGE, SLEEP_TIME);
    }
    

  • Contest Winner

    @niccodemi Did you try ?

    wait(1000);
    

    i.s.o.

    delay(1000);
    

    With wait() MySensor keeps processing messages on your node.



  • @BartE yes, I tried. If I change delay to wait the sketch compiles and I can upload it. After node receives 433 sensor input node sends out tripped value 1 and then stops responding (I have to reboot it). I guess the issue is because of using "wait(1000)" outside of void loop function?


  • Contest Winner

    @niccodemi I just had a better look @ your code. I think the issue is that your try to wait in an interrupt service routine (ISR) this is "killing" for most processors. showOldCod() is called from an interrupt.

    Better is to keep the time in and ISR as short as possible. So just remember you did received a trigger and and leave the routine.
    Something like this (not tested but should give an idea)

    /*
    433MHz Motion Sensor
     * Setup:
     * - connect a 433MHz receiver on digital pin 2.
     *
     * MySensor note: This example has not yet been adopted but can be used as an example
     * of receiving 433Mhz stuff. 
     * 
     * One idea could be to echo received 433 codes back to gateway to be able to pick up and
     * handle data over there.
     *
    */
    #define MY_DEBUG
    
    #define MY_RADIO_NRF24
    
    #include <RemoteReceiver.h>
    #include <InterruptChain.h>
    #include <SPI.h>
    #include <MySensor.h>
    
    unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    
    //#define INTERRUPT 2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define CHILD_ID_1 1   // Id of the sensor child
    #define CHILD_ID_2 2   // Id of the sensor child
    
    // Initialize motion message
    MyMessage msg1(CHILD_ID_1, V_TRIPPED);
    MyMessage msg2(CHILD_ID_2, V_TRIPPED);
    
    unsigned long newCodeReceived = 0;
    
    void setup() {
      Serial.begin(115200);
    
      // Interrupt -1 to indicate you will call the interrupt handler with InterruptChain
      RemoteReceiver::init(-1, 2, showOldCode);
    
      // On interrupt, call the interrupt handlers of remote and sensor receivers
      InterruptChain::addInterruptCallback(0, RemoteReceiver::interruptHandler);
      Serial.print("433 Motion Sensor");
    }
    
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("433 Motion Sensor", "1.0");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_1, S_MOTION);
      present(CHILD_ID_2, S_MOTION);
    }
    
    void loop() {
       // You can do other stuff here!
      // shows the received code sent from an old-style remote switch
           if(newCodeReceived == 510217) {
              send(msg1.set("1"));  // Send tripped value to gw 
              wait(1000);
              send(msg1.set("0"));
              newCodeReceived = 0;
          }
          if(newCodeReceived == 354240) {
              send(msg2.set("1"));  // Send tripped value to gw 
              wait(1000);
              send(msg2.set("0"));
              newCodeReceived = 0;
          }
    }
    
    void showOldCode(unsigned long receivedCode, unsigned int period) {
      // Print the received code.
      Serial.print("Code: ");
      Serial.print(receivedCode);
      Serial.print(", period: ");
      Serial.print(period);
      Serial.println("us.");
    
      // Read digital motion value
      //boolean tripped = receivedCode; 
       newCodeReceived = receivedCode;
    
        // Sleep until interrupt comes in on motion sensor. Send update every two minute. 
      //sleep(INTERRUPT,CHANGE, SLEEP_TIME);
    }
    

    BTW it is also not a good practice to wait with in the loop, it is better to save a time-stamp with millis(), keep looping and check if we were active for 1 second, something like this

    unsigned long timeTrigger1 = 0;
    unsigned long timeTrigger2 = 0;
    
    void loop() {
          // shows the received code sent from an old-style remote switch
          if(newCodeReceived == 510217) {
              if (timeTrigger1 == 0) {
                  send(msg1.set("1"));  // Send tripped value to gw 
              }
              newCodeReceived = 0;
              timeTrigger1 = millis();
          }
          if (timeTrigger1 > 0 && (millis() - timeTrigger1) > 1000) {
             // Not tripped for over 1 second tell the GW
             send(msg1.set("0"));
             timeTrigger1 = 0;
          }
          
          if(newCodeReceived == 354240) {
              if (timeTrigger2 == 0) {
                     send(msg2.set("1"));  // Send tripped value to gw 
              }
              newCodeReceived = 0;
              timeTrigger2 = millis();
          }
          if (timeTrigger2 > 0 && (millis() - timeTrigger2) > 1000) {
             // Not tripped for over 1 second tell the GW
             send(msg1.set("0"));
             timeTrigger2 = 0;
          }
          
          // Give some time to MySensor  to procces messages
          wait(10);
    }
    

    This solution has 2 side effects:

    1. It keeps being triggered if your motion sensor was tripped again with in the second
    2. it is now able to detect and handle 2 triggers at the same time (which is not the case in the original example)

  • Mod

    @BartE you mean "it is now able to detect", right?


  • Contest Winner

    @mfalkvidd yes you're right i will update my post



  • @BartE thank you. I modified sketch (the one with millis) and it works great. How would I enable sleep mode with interrupt?

    Eventually I plan to add more motion sensors and I think it would be better to use array. This is my first attempt and below is how far I got but obviously something is missing because I cannot compile it; I get error: "msg" cannot be used as function

    /*
    433MHz Motion Sensor
     * Setup:
     * - connect a 433MHz receiver on digital pin 2.
     *
     * MySensor note: This example has not yet been adopted but can be used as an example
     * of receiving 433Mhz stuff. 
     * 
     * One idea could be to echo received 433 codes back to gateway to be able to pick up and
     * handle data over there.
     *
    */
    #define MY_DEBUG
    
    #define MY_RADIO_NRF24
    
    #include <RemoteReceiver.h>
    #include <InterruptChain.h>
    #include <SPI.h>
    #include <MySensor.h>
    
    unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    
    //#define INTERRUPT 2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define noMotion 4
    const int RFCODE[] = {354240, 123654, 123789, 123954};  
    #define CHILD_ID 1   // Id of the sensor child
    
    // Initialize motion message
    MyMessage msg[noMotion];
    
    unsigned long newCodeReceived = 0;
    
    void setup() {
      Serial.begin(115200);
      // Interrupt -1 to indicate you will call the interrupt handler with InterruptChain
      RemoteReceiver::init(-1, 2, showOldCode);
      // On interrupt, call the interrupt handlers of remote and sensor receivers
      InterruptChain::addInterruptCallback(0, RemoteReceiver::interruptHandler);
      Serial.print("433 Motion Sensor");
      wait(30);
        // initialize Motion sensors 
      for (int i=1; i<=noMotion; i++){
        msg[i].sensor = i;          // initialize messages
        // Change to V_LIGHT if you use S_LIGHT in presentation below
        msg[i].type = V_TRIPPED;
    }
    }
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("433 Motion Sensor", "1.0a");
    
      // Register all sensors to gw (they will be created as child devices)
      for (int i=1; i<=noMotion; i++) {
      present(i, S_MOTION);
      wait(30);
    }
    }
    
    unsigned long timeTrigger1 = 0;
    //unsigned long timeTrigger2 = 0;
    
    void loop() {
          for (int i=1; i<=noMotion; i++) {
          // shows the received code sent from an old-style remote switch
          if(newCodeReceived == RFCODE[i]) {
              if (timeTrigger1 == 0) {
                  send(msg(i).set("1"));  // Send tripped value to gw 
              }
              newCodeReceived = 0;
              timeTrigger1 = millis();
          }
          if (timeTrigger1 > 0 && (millis() - timeTrigger1) > 1000) {
             // Not tripped for over 1 second tell the GW
             send(msg(i).set("0"));
             timeTrigger1 = 0;
          }      
          // Give some time to MySensor  to procces messages
          wait(10);
    }
    }
    
    void showOldCode(unsigned long receivedCode, unsigned int period) {
      // shows the received code sent from an old-style remote switch
      // Print the received code.
      Serial.print("Code: ");
      Serial.print(receivedCode);
      Serial.print(", period: ");
      Serial.print(period);
      Serial.println("us.");
    
      // Read digital motion value
       newCodeReceived = receivedCode;
       sendHeartbeat();
        // Sleep until interrupt comes in on motion sensor. Send update every two minute. 
      //sleep(INTERRUPT,CHANGE, SLEEP_TIME);
    }
    


  • I figured out array and the sketch works. As final thing I would like to enable sleep-time and Heartbeat message once node wakes up.

    /*
    433MHz Multi Motion Sensor
     * Setup:
     * - connect a 433MHz receiver on digital pin 2.
     * - type appropriate RF codes into array
    */
    #define MY_DEBUG
    
    #define MY_RADIO_NRF24
    
    #include <RemoteReceiver.h>
    #include <InterruptChain.h>
    #include <SPI.h>
    #include <MySensor.h>
    
    unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    
    //#define INTERRUPT 2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define noMotion 4                                                                                                     //number of sensors
    const unsigned long RFCODE[] = {354240, 354222, 354216, 354214};              //RF433 codes
    #define CHILD_ID 1   // Id of the sensor child
    
    // Initialize motion message
    MyMessage msg[noMotion];
    
    unsigned long newCodeReceived = 0;
    
    long previousMillis = 0;
    long interval = 120000;                                          //interval at which to send Heartbeat
    
    void setup() {
      Serial.begin(115200);
      // Interrupt -1 to indicate you will call the interrupt handler with InterruptChain
      RemoteReceiver::init(-1, 2, showOldCode);
      // On interrupt, call the interrupt handlers of remote and sensor receivers
      InterruptChain::addInterruptCallback(0, RemoteReceiver::interruptHandler);
      Serial.print("433 Motion Sensor");
      wait(30);
        // initialize Motion sensors 
      for (int i=0; i<noMotion; i++){
        msg[i].sensor = i;          // initialize messages
        // Change to V_LIGHT if you use S_LIGHT in presentation below
        msg[i].type = V_TRIPPED;
    }
    }
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("433 Motion Sensor", "1.0b");
      wait(50);
      // Register all sensors to gw (they will be created as child devices)
      for (int i=0; i<noMotion; i++) {
      present(i, S_MOTION);
      wait(50);
    }
    }
    
    unsigned long timeTrigger1 = 0;
    
    void loop() {
          for (int i=0; i<noMotion; i++) {
          // shows the received code sent from an old-style remote switch
          unsigned long value = RFCODE[i];
          if(newCodeReceived == value) {
              if (timeTrigger1 == 0) {
                  send(msg[i].set("1"));  // Send tripped value to gw 
              }
              newCodeReceived = 0;
              timeTrigger1 = millis();
          }
          if (timeTrigger1 > 0 && (millis() - timeTrigger1) > 1000) {
             // Not tripped for over 1 second tell the GW
             send(msg[i].set("0"));
             timeTrigger1 = 0;
          }      
          // Give some time to MySensor  to procces messages
          wait(10);
    }
    {
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis > interval) {
             sendHeartbeat();
             previousMillis = currentMillis;
             }
             }
    }
    
    void showOldCode(unsigned long receivedCode, unsigned int period) {
      // shows the received code sent from an old-style remote switch
      // Print the received code.
      Serial.print("Code: ");
      Serial.print(receivedCode);
      Serial.print(", period: ");
      Serial.print(period);
      Serial.println("us.");
    
      // Read digital motion value
       newCodeReceived = receivedCode;
        // Sleep until interrupt comes in on motion sensor. Send update every two minute. 
      //sleep(INTERRUPT,CHANGE, SLEEP_TIME);
    }
    

  • Contest Winner

    @niccodemi This looks good.

    One remark the timeTrigger variable should also become an array. When 2 sensors are triggered with your implementation only 1 sensor will be reseted the other will remain active.



  • @BartE thanks. Second sensor actually wouldn't even trigger while the first one was triggered (1 second).

    Would you know how to enable sleep-time in this sketch? I tried defining Interrupt on pin 2 but I get strange results (RF codes are randomly received and messages are rarely sent).

    /*
    433MHz Multi Motion Sensor
     * Setup:
     * - connect a 433MHz receiver on digital pin 2.
     * - type appropriate RF codes into array, define noMotion and timetrigger1
    */
    #define MY_DEBUG
    
    #define MY_RADIO_NRF24
    
    #include <RemoteReceiver.h>
    #include <InterruptChain.h>
    #include <SPI.h>
    #include <MySensor.h>
    
    //unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
    
    //#define INTERRUPT 2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define noMotion 4                                                           //number of sensors
    const unsigned long RFCODE[] = {354240, 354222, 354216, 354214};              //RF433 codes
    #define CHILD_ID 1   // Id of the sensor child
    
    // Initialize motion message
    MyMessage msg[noMotion];
    
    unsigned long newCodeReceived = 0;
    
    long previousMillis = 0;
    long interval = 120000;                                          //interval at which to send Heartbeat
    
    void setup() {
      Serial.begin(115200);
      // Interrupt -1 to indicate you will call the interrupt handler with InterruptChain
      RemoteReceiver::init(-1, 2, showOldCode);
      // On interrupt, call the interrupt handlers of remote and sensor receivers
      InterruptChain::addInterruptCallback(0, RemoteReceiver::interruptHandler);
      Serial.print("433 Motion Sensor");
      wait(30);
        // initialize Motion sensors 
      for (int i=0; i<noMotion; i++){
        msg[i].sensor = i;          // initialize messages
        // Change to V_LIGHT if you use S_LIGHT in presentation below
        msg[i].type = V_TRIPPED;
    }
    }
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("433 Motion Sensor", "1.0b");
      wait(50);
      // Register all sensors to gw (they will be created as child devices)
      for (int i=0; i<noMotion; i++) {
      present(i, S_MOTION);
      wait(50);
    }
    }
    
    unsigned long timeTrigger1[] = {0, 0, 0, 0};                // same as noMotion
    
    void loop() {
          for (int i=0; i<noMotion; i++) {
          // shows the received code sent from an old-style remote switch
          unsigned long value = RFCODE[i];
          if(newCodeReceived == value) {
              if (timeTrigger1[i] == 0) {
                  send(msg[i].set("1"));  // Send tripped value to gw 
              }
              newCodeReceived = 0;
              timeTrigger1[i] = millis();
          }
          if (timeTrigger1[i] > 0 && (millis() - timeTrigger1[i]) > 1000) {
             // Not tripped for over 1 second tell the GW
             send(msg[i].set("0"));
             timeTrigger1[i] = 0;
          }      
          // Give some time to MySensor  to procces messages
          wait(10);
    }
    {
    unsigned long currentMillis = millis();
    if(currentMillis - previousMillis > interval) {
             sendHeartbeat();
             previousMillis = currentMillis;
             }
             }
    }
    
    void showOldCode(unsigned long receivedCode, unsigned int period) {
      // shows the received code sent from an old-style remote switch
      // Print the received code.
      Serial.print("Code: ");
      Serial.print(receivedCode);
      Serial.print(", period: ");
      Serial.print(period);
      Serial.println("us.");
    
      // Read digital motion value
       newCodeReceived = receivedCode;
        // Sleep until interrupt comes in on motion sensor. Send update every two minute. 
      //sleep(INTERRUPT,CHANGE, SLEEP_TIME);
    }
    

  • Contest Winner

    @niccodemi sleep() will bring the processor actual to sleep e.g. several large parts of the process actually will stop working to save battery life.

    So data is not processed anymore causing the strange RF results. Using wait() is better is this case but will not save any battery lifetime.
    Golden rule on this MySensors forum is batteries are only useful for a sensor which only broadcast and NOT is meant to receive data. Your sketch uses both so better us a power adapter.



  • @BartE noted, I didn't actually plan to run this node off a battery but I thought it was a good practice to use sleep() (with interrupt) in nodes which are not expecting messages from gw.

    One more thing: if using array when presenting children

    present(i, S_MOTION);
    

    messages are sent to gw one after another and even with only 4 children at least one gets usually lost. Is there alternative to this?

    present(1, S_MOTION);
      wait(50);
      present(2, S_MOTION);
      wait(50);
      present(3, S_MOTION);
      wait(50);
      present(4, S_MOTION);
      wait(50);
    

  • Contest Winner

    @niccodemi this issue i reported more often in MySenors forum adding a delay (or better wait()) is the solution.

    It should not be a problem because this presentation function is only called once at start up


Log in to reply
 

Suggested Topics

  • 1
  • 3
  • 6
  • 10
  • 2
  • 2

55
Online

11.4k
Users

11.1k
Topics

112.7k
Posts