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. Development
  3. Multiple Relays + Motion sketch, fully customizable, optional timer, manual override

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

Scheduled Pinned Locked Moved Development
24 Posts 11 Posters 8.0k Views 13 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.
  • O Ostoja

    @rejoe2, MANY thanks for answer! Relay don't work in Domoticz :white_frowning_face:

    // Enable and uncomment attached radio type
    #define MY_RADIO_NRF24
    //#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  1                                       // Total number of attached relays. Must be equal to total number of elements in array below!
    const int RELAYS[]                  =     {4};                    // 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        3                                       // The digital input pin of the motion sensor
    #define MOTION_CHILD_ID   10                                      // 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 = 1;                                         // 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
    
    
    #include <DallasTemperature.h>
    #include <OneWire.h>
    
    #define COMPARE_TEMP 1 // Send temperature only if changed? 1 = Yes 0 = No
    
    #define ONE_WIRE_BUS 2 // Pin where dallase sensor is connected 
    #define MAX_ATTACHED_DS18B20 16
    unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
    OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. 
    float lastTemperature[MAX_ATTACHED_DS18B20];
    int numSensors=0;
    bool receivedConfig = false;
    bool metric = true;
    // Initialize temperature message
    MyMessage msg(0,V_TEMP);
    
    void before()
    
      
    
    {
      // Startup up the OneWire library
      sensors.begin();
      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()
    {
      // requestTemperatures() will not block current thread
      sensors.setWaitForConversion(false);
    #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");
    
      // Fetch the number of attached temperature sensors  
      numSensors = sensors.getDeviceCount();
    
      // Present all sensors to controller
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {   
         present(i, S_TEMP);
      }
    
      // 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()
    {
    
      // Fetch temperatures from Dallas sensors
      sensors.requestTemperatures();
    
      // query conversion time and sleep until conversion completed
      int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution());
      // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
      sleep(conversionTime);
    
      // Read temperatures and send them to controller 
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
     
        // Fetch and round temperature to one decimal
        float temperature = static_cast<float>(static_cast<int>((getControllerConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;
     
        // Only send data if temperature has changed and no error
        #if COMPARE_TEMP == 1
        if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) {
        #else
        if (temperature != -127.00 && temperature != 85.00) {
        #endif
     
          // Send in the new temperature
          send(msg.setSensor(i).set(temperature,1));
          // Save new temperatures for next compare
          lastTemperature[i]=temperature;
        }
      }
      sleep(SLEEP_TIME);
    #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);
    }
    
    dirkcD Offline
    dirkcD Offline
    dirkc
    wrote on last edited by dirkc
    #21

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

    // Present all sensors to controller
      for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {   
         present(i, S_TEMP);
      }
    
      // 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);
      }
    

    With this two "for" loops you set present(n) multiple times. in the first for() you start with 0 until MAX_ATTACHED_DS18B20-1, in the second for() you start with 1 until NUMBER_OF_RELAYS-1, so this will assign the sensors with identical IDs as the relays.
    I have not checked the internal code of this method, but I would think that you should better user a different range in the second for() loop starting at least with MAX_ATTACHED_DS18B20+1.

    Controller: Home Assistant & FHEM - Gateway: ESP8266wifi - MySensors: 2.3.2 (nRF24)

    1 Reply Last reply
    0
    • rejoe2R Offline
      rejoe2R Offline
      rejoe2
      wrote on last edited by rejoe2
      #22

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

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

      // Present all sensors to controller
        for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {   
           present(i, S_TEMP);
        }
      
        // 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);
        }
      

      With this two "for" loops you set present(n) multiple times. in the first for() you start with 0 until MAX_ATTACHED_DS18B20-1, in the second for() you start with 1 until NUMBER_OF_RELAYS-1
      I have not checked the internal code of this method, but I would think that you should better user a different range in the second for() loop starting at least with MAX_ATTACHED_DS18B20+1.

      Additional remarks:
      For the relays better start with 1.
      Shift the Temp values to higer range (use e.g. a variable like FRIST_DS_SENSOR_ID).
      Check, if the receive()-part and the ID you get really fits together with the relay you want to switch.
      Don't try to read the temperature values every few parts of a second. Use a millis()-routine.

      Please search the forum, there have to be at least 2 threads with exactly the same problems in which I posted how to solve this. You are "trying to reinvent the wheel". :grin:

      Controller: FHEM; MySensors: 2.3.1, RS485,nRF24,RFM69, serial Gateways

      1 Reply Last reply
      0
      • O Ostoja

        I commented out the "sleep", but when I press the relay switch in Domoticz, it does not work:white_frowning_face:

        dirkcD Offline
        dirkcD Offline
        dirkc
        wrote on last edited by
        #23

        @ostoja look at this video with an explanation of this topic and how to handle the IDs
        https://forum.mysensors.org/post/26597

        Controller: Home Assistant & FHEM - Gateway: ESP8266wifi - MySensors: 2.3.2 (nRF24)

        1 Reply Last reply
        0
        • B Offline
          B Offline
          bereska
          wrote on last edited by
          #24

          @HenryWhite thank you for the excellent sketch. It works like a charm in my HA configuration!

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


          20

          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