Multiple Relays + Motion sketch, fully customizable, optional timer, manual override



  • Hi!

    I recently modified the relay example sketch so that it fits my needs; maybe some of you can make use of my little work too.

    Here's what you can do / what the features are:

    • Easily add as much Relays / FETs as you want (or as much as the arduino allows) by entering the according pin numbers in the RELAYS[ ]-Array
    • You can trigger each relay from your controller
    • You can add a motion sensor and specify which (MOTION_ACTIVATED_RELAYS[ ]) of your relays should be triggered through motion and for how long (ON_TIMES[ ])
    • The state of the motion sensor will be reported to your controller
    • When a relay is changed through motion, the change will also be reported to your controller
    • You can send a manual override from your controller, so that the motion will still be reported, but none of the relays will be triggered through motion
    /**
       The MySensors Arduino library handles the wireless radio link and protocol
       between your home built sensors/actuators and HA controller of choice.
       The sensors forms a self healing radio network with optional repeaters. Each
       repeater and gateway builds a routing tables in EEPROM which keeps track of the
       network topology allowing messages to be routed to nodes.
    
       Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       Copyright (C) 2013-2015 Sensnology AB
       Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
    
       Documentation: http://www.mysensors.org
       Support Forum: http://forum.mysensors.org
    
       This program is free software; you can redistribute it and/or
       modify it under the terms of the GNU General Public License
       version 2 as published by the Free Software Foundation.
    
     *******************************
    
       REVISION HISTORY
       Version 1.0 - Henrik Ekblad
       Version 1.1 - HenryWhite
    
       DESCRIPTION
       Example sketch showing how to control physical relays.
       This example will remember relay state after power failure.
       Optional attachment of motion sensor to control the relays is possible.
       Notes:
          -- The Child-IDs of the attached relays range from 1 up to (1-(NUMBER_OF_RELAYS))
          -- Make sure to adjust the potentiometer for triggertime on your motion sensor as leftmost as possible,
             because the countdown will not start until the motion sensor reports back a "0" (no movement)
    
    */
    
    //----------------------- Library Configuration ---------------------
    //#define MY_DEBUG                          // uncomment to enable debug prints to serial monitor
    //#define MY_REPEATER_FEATURE               // uncomment to enable repeater functionality for this node
    //#define MY_NODE_ID 20                     // uncomment to define static node ID
    
    // Enable and uncomment attached radio type
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    //#define MY_TRANSPORT_WAIT_READY_MS 1      // uncomment this to enter the loop() and setup()-function even when the node cannot be registered to gw
    
    //----------------------- Relay and Motion Sensor Configuration -----------------------
    #define MOTION                                                    // un-comment to enable motion sensing
    #define NUMBER_OF_RELAYS  2                                       // Total number of attached relays. Must be equal to total number of elements in array below!
    const int RELAYS[]                  =     {3,  5};                // digital pins of attached relays
    const int MOTION_ACTIVATED_RELAYS[] =     {1,  0};                // 1 to trigger the relay through motion, 0 to not trigger. Array length must correspond to RELAYS[] array.
    const long ON_TIMES[]               =     {300, 0};               // Specify for each element in MOTION_ACTIVATED_RELAYS, how long the specified relay should be active in seconds.
    #define RELAY_ON          1                                       // GPIO value to write to turn on attached relay
    #define RELAY_OFF         0                                       // GPIO value to write to turn off attached relay
    #define MOTION_PIN        2                                       // The digital input pin of the motion sensor
    #define MOTION_CHILD_ID   0                                       // Set the child id of the motion sensor
    bool ack = 1;                                                     // set this to 1 if you want destination node to send ack back to this node
    
    //----------------------- DO NOT CHANGE -----------------------------
    #include <MySensors.h>
    MyMessage motion_msg(MOTION_CHILD_ID, V_TRIPPED);   // Initialize motion message
    unsigned long trigger_millis[NUMBER_OF_RELAYS];     // Used for the timer
    bool lastTripped = 0;                               // Used to store last motion sensor value
    bool manual_override = 0;                           // if this gets set to 1 (e.g. by a switch or a command from the gateway), motion triggering of relays is deactivated
    MyMessage relay_msg;                                // Initialize relay message
    
    void before()
    {
      int i;
      for (int sensor = 1, i = 0; sensor <= NUMBER_OF_RELAYS; sensor++, i++) {
        // set relay pins to output mode
        pinMode(RELAYS[i], OUTPUT);
        // Restore relay to last known state (using eeprom storage)
        digitalWrite(RELAYS[i], loadState(sensor) ? RELAY_ON : RELAY_OFF);
      }
      // set motion pin to output mode, if MOTION is defined
    #ifdef MOTION
      pinMode(MOTION_PIN, INPUT);
    #endif
    }
    
    void setup()
    {
    #ifdef MOTION
      // give the motion sensor some time to settle
      Serial.println("Starting up. Please wait 8 seconds...");
      delay(8000);
    #endif
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Relay/Motion", "1.0");
    
      // Register all sensors to gw (they will be created as child devices)
      for (int sensor = 1; sensor <= NUMBER_OF_RELAYS; sensor++) {
        present(sensor, S_BINARY, "Relay", ack);
      }
    #ifdef MOTION
      present(MOTION_CHILD_ID, S_MOTION, "Motion Sensor", ack);
    #endif
    
    }
    
    void loop()
    {
    #ifdef MOTION
      if (!manual_override) {
        // Read digital motion value
        bool tripped = digitalRead(MOTION_PIN) == HIGH;
    
        if (lastTripped != tripped) {
          Serial.print("New Motion State: ");
          Serial.println(tripped);
          // Send tripped value to gw
          send(motion_msg.set(tripped ? "1" : "0"));
          lastTripped = tripped;
    
          // Change relay states, send new state to gw and store state in eeprom
          if (tripped == 1) {
            for (int i = 0; i < NUMBER_OF_RELAYS; i++) {
              if (MOTION_ACTIVATED_RELAYS[i] == 1) {
                digitalWrite(RELAYS[i], RELAY_ON);
                relay_msg_constructor(i + 1, V_STATUS);
                send(relay_msg.set(RELAY_ON));
                trigger_millis[i] = millis();
                Serial.print("Relay ");
                Serial.print(RELAYS[i]);
                Serial.println(" turned on");
                saveState(i, 1);
              }
            }
          }
        }
    
        for (int i = 0; i < NUMBER_OF_RELAYS; i++) {
          if (tripped == 1 and MOTION_ACTIVATED_RELAYS[i] == 1 and trigger_millis[i] != 0) {
            trigger_millis[i] = millis();
          }
          if ((trigger_millis[i] + ON_TIMES[i] * 1000 < millis()) and MOTION_ACTIVATED_RELAYS[i] == 1 and trigger_millis[i] != 0) {
            digitalWrite(RELAYS[i], RELAY_OFF);
            relay_msg_constructor(i + 1, V_STATUS);
            send(relay_msg.set(RELAY_OFF));
            Serial.print("Relay ");
            Serial.print(RELAYS[i]);
            Serial.println(" turned off");
            saveState(i, 0);
            trigger_millis[i] = 0;
          }
        }
      }
      else {
        bool tripped = digitalRead(MOTION_PIN) == HIGH;
        if (lastTripped != tripped) {
          Serial.print("New Motion State: ");
          Serial.println(tripped);
          // Send tripped value to gw
          send(motion_msg.set(tripped ? "1" : "0"));
          lastTripped = tripped;
        }
        for (int i = 0; i < NUMBER_OF_RELAYS; i++) {
          if (MOTION_ACTIVATED_RELAYS[i] == 1 and trigger_millis[i] != 0) {
            trigger_millis[i] = 0;                            // reset running timers
          }
        }
      }
    #endif
    }
    
    void receive(const MyMessage &message)
    {
      // Handle incoming relay commands
      if (message.type == V_STATUS) {
        // Change relay state
        if (RELAYS[message.sensor - 1]) {
          digitalWrite(RELAYS[message.sensor - 1], message.getBool() ? RELAY_ON : RELAY_OFF);
    
          // Store state in eeprom
          saveState(message.sensor - 1, message.getBool());
          // Write some debug info
          Serial.print("Incoming change for sensor:");
          Serial.print(message.sensor);
          Serial.print(", New status: ");
          Serial.println(message.getBool());
        }
      }
    
      // Handle incoming manual override/bypass of motion sensor
      if (message.type == V_ARMED and message.sensor == 0) {
        manual_override = message.getBool();
        Serial.print("Manual Override: ");
        Serial.println(manual_override);
      }
    }
    
    void relay_msg_constructor(int sensor, uint8_t type)
    {
      relay_msg.setSensor(sensor);
      relay_msg.setType(type);
    }
    

    Additional Notes:

    • The Child-IDs of the attached relays range from 1 up to (1-(NUMBER_OF_RELAYS))
    • The default Child-ID for the motion sensor is 0
    • Make sure to adjust the potentiometer for triggertime on your motion sensor as leftmost as possible, because the countdown-timer will not start until the motion sensor reports back a "0" (no movement)


  • awesome work...this sketch is brilliant....

    what happens if you retrigger motion before timer runs out?
    will it always handle a restart of the timer correctly?



  • @markjgabb said in Multiple Relays + Motion sketch, fully customizable, optional timer, manual override:

    awesome work...this sketch is brilliant....

    what happens if you retrigger motion before timer runs out?
    will it always handle a restart of the timer correctly?

    Yes, the timer will be reset.



  • confirmed, im now running this is my office, works perfectly every time

    i have it set to a motion sensor that covers most of the room...
    one relay controls the lights...the other controls my soldering iron perfect work


Log in to reply
 

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