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. Array Relay Button Actuator

Array Relay Button Actuator

Scheduled Pinned Locked Moved General Discussion
45 Posts 16 Posters 24.8k Views 16 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.
  • Cliff KarlssonC Cliff Karlsson

    How would I update this to work with 1.6?

    N Offline
    N Offline
    niccodemi
    wrote on last edited by
    #27

    @Cliff-Karlsson I recently started using 1.6 version, below is converted sketch. It works with momentary (pushbuttons) switches only.

    Does anyone have sketch for toggle switches?

    #define MY_RADIO_NRF24
    
    #define MY_REPEATER_FEATURE
    
    #include <MySensor.h>
    
    #include <SPI.h>
    #include <Bounce2.h>
    #define RELAY_ON 0                      // switch around for relay HIGH/LOW state
    #define RELAY_OFF 1
    //
    
    #define noRelays 2                     //2-4
    const int relayPin[] = {14,15};          //  switch around pins to your desire
    const int buttonPin[] = {3,4};      //  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 debouncer[noRelays];
    MyMessage msg[noRelays];
    
    void setup(){
        sendHeartbeat();
        wait(250);
        // Initialize Relays with corresponding buttons
        for (int i = 0; i < noRelays; i++){
        Relays[i].buttonPin = buttonPin[i];              // assign physical pins
        Relays[i].relayPin = relayPin[i];
        msg[i].sensor = i;                                   // initialize messages
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();                        // initialize debouncer
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(Relays[i].buttonPin, INPUT_PULLUP);
        //digitalWrite(Relays[i].relayPin, RELAY_OFF);
        wait(250);
        pinMode(Relays[i].relayPin, OUTPUT);
        Relays[i].relayState = loadState(i);                               // retrieve last values from EEPROM
        digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF);   // and set relays accordingly
        send(msg[i].set(Relays[i].relayState? true : false));                  // make controller aware of last status  
        wait(250);
        }
    }
    void presentation()  {
          sendSketchInfo("MultiRelayButton", "0.9f");
          wait(250);
          for (int i = 0; i < noRelays; i++)
          present(i, S_LIGHT);                               // present sensor to gateway
    }
    void loop()
        {
        for (byte i = 0; i < noRelays; i++){
        debouncer[i].update();
        byte value = debouncer[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);
        send(msg[i].set(Relays[i].relayState? true : false));
        saveState( i, Relays[i].relayState );}                 // save sensor state in EEPROM (location == sensor number)
        
            Relays[i].oldValue = value;      
        }
    }
    // process incoming message 
    void receive(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
       saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
       }
      }
    }
    
    1 Reply Last reply
    0
    • jeylitesJ Offline
      jeylitesJ Offline
      jeylites
      wrote on last edited by jeylites
      #28

      The following sketch has got what you're looking for. Hope that helps.

      Relay With Actuator Switch Toggle

      #include <MySensor.h>
      #include <SPI.h>
      #include <Bounce2.h>
      #define RELAY_ON 0                      // switch around for realy HIGH/LOW state
      #define RELAY_OFF 1
      
      MySensor gw;
      
      #define RADIO_ID 11                    // Radio ID, whatever channel you assigned to
      #define noRelays 6
      const int relayPin[] = {A0, A1, A2, A3, A4, A5};
      const int buttonPin[] = {3, 4, 5, 6, 7, 8};
      
      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 debouncer[noRelays];
      MyMessage msg[noRelays];
      
      void setup(){
      	gw.begin(incomingMessage, RADIO_ID, true);
      	delay(250);
      	gw.sendSketchInfo("MultiRelayButton", "0.9b");
      	delay(250);
      
      	// Initialize Relays with corresponding buttons
      	for (int i = 0; i < noRelays; i++){
      	Relays[i].buttonPin = buttonPin[i];				             // assign physical pins
      	Relays[i].relayPin = relayPin[i];
      	msg[i].sensor = i;						             // initialize messages
      	msg[i].type = V_LIGHT;
      	debouncer[i] = Bounce();						     // initialize debouncer
      	debouncer[i].attach(buttonPin[i]);
      	debouncer[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(msg[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++){
      	debouncer[i].update();
      	byte value = debouncer[i].read();
      //	if (value != Relays[i].oldValue && value == 0){
              if (value != Relays[i].oldValue){
      	Relays[i].relayState = !Relays[i].relayState;
      	digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
      	gw.send(msg[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;
              
      	}
      }
      
      // process incoming message 
      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)
      		}
      	}
      }
      
      1 Reply Last reply
      1
      • N Offline
        N Offline
        niccodemi
        wrote on last edited by
        #29

        @jeylites Thanks, toggle switch works but there is issue when node boots / restarts. On 1st restart relays stay OFF, on 2nd come ON, on 3rd again OFF and so on. It seems that whatever happens during Setup is reversed in Loop. Hopefully someone can point out what should be changed in modified sketch.

        #define MY_RADIO_NRF24
        
        #define MY_REPEATER_FEATURE
        
        #include <MySensor.h>
        #include <SPI.h>
        #include <Bounce2.h>
        #define RELAY_ON 0                      // switch around for realy HIGH/LOW state
        #define RELAY_OFF 1
        //
        
        #define noRelays 2                     //2-4
        const int relayPin[] = {14,15};          //  switch around pins to your desire
        const int buttonPin[] = {3,4};      //  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 debouncer[noRelays];
        MyMessage msg[noRelays];
        
        void setup(){
            sendHeartbeat();
            wait(250);
            // Initialize Relays with corresponding buttons
            for (int i = 0; i < noRelays; i++){
            Relays[i].buttonPin = buttonPin[i];              // assign physical pins
            Relays[i].relayPin = relayPin[i];
            msg[i].sensor = i;                                   // initialize messages
            msg[i].type = V_LIGHT;
            debouncer[i] = Bounce();                        // initialize debouncer
            debouncer[i].attach(buttonPin[i]);
            debouncer[i].interval(5);
            pinMode(Relays[i].buttonPin, INPUT_PULLUP);
            //digitalWrite(Relays[i].relayPin, RELAY_OFF);
            wait(250);
            pinMode(Relays[i].relayPin, OUTPUT);
            Relays[i].relayState = loadState(i);                               // retrieve last values from EEPROM
            digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF);   // and set relays accordingly
            send(msg[i].set(Relays[i].relayState? true : false));                  // make controller aware of last status  
            wait(250);
            }
        }
        void presentation()  {
              sendSketchInfo("MultiRelayButton", "0.9g");
              wait(250);
              for (int i = 0; i < noRelays; i++)
              present(i, S_LIGHT);                               // present sensor to gateway
        }
        void loop()
            {
            for (byte i = 0; i < noRelays; i++){
            debouncer[i].update();
            byte value = debouncer[i].read();
            if (value != Relays[i].oldValue){
            Relays[i].relayState = !Relays[i].relayState;
            digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
            send(msg[i].set(Relays[i].relayState? true : false));
            saveState( i, Relays[i].relayState );}                 // save sensor state in EEPROM (location == sensor number)
            
                Relays[i].oldValue = value;      
            }
        }
        // process incoming message 
        void receive(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
           saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
           }
          }
        }
        

        these are screenshots from restarts

        reboot1

        reboot2

        martinhjelmareM 1 Reply Last reply
        0
        • N niccodemi

          @jeylites Thanks, toggle switch works but there is issue when node boots / restarts. On 1st restart relays stay OFF, on 2nd come ON, on 3rd again OFF and so on. It seems that whatever happens during Setup is reversed in Loop. Hopefully someone can point out what should be changed in modified sketch.

          #define MY_RADIO_NRF24
          
          #define MY_REPEATER_FEATURE
          
          #include <MySensor.h>
          #include <SPI.h>
          #include <Bounce2.h>
          #define RELAY_ON 0                      // switch around for realy HIGH/LOW state
          #define RELAY_OFF 1
          //
          
          #define noRelays 2                     //2-4
          const int relayPin[] = {14,15};          //  switch around pins to your desire
          const int buttonPin[] = {3,4};      //  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 debouncer[noRelays];
          MyMessage msg[noRelays];
          
          void setup(){
              sendHeartbeat();
              wait(250);
              // Initialize Relays with corresponding buttons
              for (int i = 0; i < noRelays; i++){
              Relays[i].buttonPin = buttonPin[i];              // assign physical pins
              Relays[i].relayPin = relayPin[i];
              msg[i].sensor = i;                                   // initialize messages
              msg[i].type = V_LIGHT;
              debouncer[i] = Bounce();                        // initialize debouncer
              debouncer[i].attach(buttonPin[i]);
              debouncer[i].interval(5);
              pinMode(Relays[i].buttonPin, INPUT_PULLUP);
              //digitalWrite(Relays[i].relayPin, RELAY_OFF);
              wait(250);
              pinMode(Relays[i].relayPin, OUTPUT);
              Relays[i].relayState = loadState(i);                               // retrieve last values from EEPROM
              digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF);   // and set relays accordingly
              send(msg[i].set(Relays[i].relayState? true : false));                  // make controller aware of last status  
              wait(250);
              }
          }
          void presentation()  {
                sendSketchInfo("MultiRelayButton", "0.9g");
                wait(250);
                for (int i = 0; i < noRelays; i++)
                present(i, S_LIGHT);                               // present sensor to gateway
          }
          void loop()
              {
              for (byte i = 0; i < noRelays; i++){
              debouncer[i].update();
              byte value = debouncer[i].read();
              if (value != Relays[i].oldValue){
              Relays[i].relayState = !Relays[i].relayState;
              digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
              send(msg[i].set(Relays[i].relayState? true : false));
              saveState( i, Relays[i].relayState );}                 // save sensor state in EEPROM (location == sensor number)
              
                  Relays[i].oldValue = value;      
              }
          }
          // process incoming message 
          void receive(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
             saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
             }
            }
          }
          

          these are screenshots from restarts

          reboot1

          reboot2

          martinhjelmareM Offline
          martinhjelmareM Offline
          martinhjelmare
          Plugin Developer
          wrote on last edited by martinhjelmare
          #30

          @niccodemi

          Hi!

          I think the problem is you're not initializing oldValue to anything. It will then always be different than value in the loop, and state will change.

          You should set oldValue to the same "state" as the loaded relayState in setup. Even better, only use relayState, and make it an int. You can do the same boolean evaluations anyway. 1 is true and 0 is false.

          Edit:
          Sorry, I forgot that this is a pushbutton, right? Then you should just make sure that oldValue and value are the same after setup is complete, ie HIGH.

          1 Reply Last reply
          1
          • N Offline
            N Offline
            niccodemi
            wrote on last edited by
            #31

            @martinhjelmare

            thanks, I understand what you mean but I don't know how to write it in sketch.

            I tried inserting

            Relays[i].oldValue = Relays[i].relayState;
            

            at the end of Void Setup section but then sketch wouldn't compile. I get "name lookup of 'i' changed 'for' ISO for scoping [-fpermissive]" error. I get same error if I substitute Relays[i].relayState with loadstate.

            martinhjelmareM 1 Reply Last reply
            0
            • N niccodemi

              @martinhjelmare

              thanks, I understand what you mean but I don't know how to write it in sketch.

              I tried inserting

              Relays[i].oldValue = Relays[i].relayState;
              

              at the end of Void Setup section but then sketch wouldn't compile. I get "name lookup of 'i' changed 'for' ISO for scoping [-fpermissive]" error. I get same error if I substitute Relays[i].relayState with loadstate.

              martinhjelmareM Offline
              martinhjelmareM Offline
              martinhjelmare
              Plugin Developer
              wrote on last edited by
              #32

              @niccodemi

              Put this on a line after pinMode() in setup function.

              Relays[i].oldValue = digitalRead(Relays[i].buttonPin);
              
              1 Reply Last reply
              0
              • N Offline
                N Offline
                niccodemi
                wrote on last edited by
                #33

                @martinhjelmare

                Ok, there is an improvement. Relays now turn to same state as they were before reboot most of the time but not always. Sometimes they inverse - the one which was OFF turns ON and vice-versa. Sometimes (1 in 3) they switch ON and OFF (only for split second) in the loop function. See below screenshots:

                reboot3

                reboot4

                This sketch is used with toggle button, same as on this photo.

                martinhjelmareM BartEB 2 Replies Last reply
                0
                • N niccodemi

                  @martinhjelmare

                  Ok, there is an improvement. Relays now turn to same state as they were before reboot most of the time but not always. Sometimes they inverse - the one which was OFF turns ON and vice-versa. Sometimes (1 in 3) they switch ON and OFF (only for split second) in the loop function. See below screenshots:

                  reboot3

                  reboot4

                  This sketch is used with toggle button, same as on this photo.

                  martinhjelmareM Offline
                  martinhjelmareM Offline
                  martinhjelmare
                  Plugin Developer
                  wrote on last edited by
                  #34

                  @niccodemi

                  Could be the toggle is still bouncing at read time. Try increasing the debouncer interval. For example, double it until no more issues. Then decrease it in halves of what the last increase was until you see the issue again. This way you can try to find the smallest debounce time needed.

                  1 Reply Last reply
                  0
                  • N niccodemi

                    @martinhjelmare

                    Ok, there is an improvement. Relays now turn to same state as they were before reboot most of the time but not always. Sometimes they inverse - the one which was OFF turns ON and vice-versa. Sometimes (1 in 3) they switch ON and OFF (only for split second) in the loop function. See below screenshots:

                    reboot3

                    reboot4

                    This sketch is used with toggle button, same as on this photo.

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

                    @niccodemi You can forget using the oldValue, because the debounce takes track of it's last status. When update() is called and a debounced pin-change is detect this function will return true otherwise it will send false.
                    Having a short delay each loop will stabilize the debouncers so your loop() can look like this:

                    void loop()
                    {
                        for (byte i = 0; i < noRelays; i++) {
                            if (debouncer[i].update()) {
                                Relays[i].relayState = !Relays[i].relayState;
                                digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
                                send(msg[i].set(Relays[i].relayState? true : false));
                                // save sensor state in EEPROM (location == sensor number)
                                saveState( i, Relays[i].relayState );
                            }                 
                        }
                        wait(10);
                    }
                    
                    martinhjelmareM 1 Reply Last reply
                    1
                    • BartEB BartE

                      @niccodemi You can forget using the oldValue, because the debounce takes track of it's last status. When update() is called and a debounced pin-change is detect this function will return true otherwise it will send false.
                      Having a short delay each loop will stabilize the debouncers so your loop() can look like this:

                      void loop()
                      {
                          for (byte i = 0; i < noRelays; i++) {
                              if (debouncer[i].update()) {
                                  Relays[i].relayState = !Relays[i].relayState;
                                  digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
                                  send(msg[i].set(Relays[i].relayState? true : false));
                                  // save sensor state in EEPROM (location == sensor number)
                                  saveState( i, Relays[i].relayState );
                              }                 
                          }
                          wait(10);
                      }
                      
                      martinhjelmareM Offline
                      martinhjelmareM Offline
                      martinhjelmare
                      Plugin Developer
                      wrote on last edited by martinhjelmare
                      #36

                      @BartE

                      Why do you think it's better to add the wait than to increase debounce interval? Didn't know update returns a boolean, cool.

                      BartEB 1 Reply Last reply
                      0
                      • martinhjelmareM martinhjelmare

                        @BartE

                        Why do you think it's better to add the wait than to increase debounce interval? Didn't know update returns a boolean, cool.

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

                        @martinhjelmare there is no reason to have that many button checks per millisecond, if you "wait" each while loop the MySensors core has more time to process messages i.s.o. of reading I/O pins especially when your node acts as a repeater. (During a wait the process function is called)
                        A person will not notices a button to take 50 i.s.o 10 milliseconds to respond.

                        martinhjelmareM 1 Reply Last reply
                        1
                        • BartEB BartE

                          @martinhjelmare there is no reason to have that many button checks per millisecond, if you "wait" each while loop the MySensors core has more time to process messages i.s.o. of reading I/O pins especially when your node acts as a repeater. (During a wait the process function is called)
                          A person will not notices a button to take 50 i.s.o 10 milliseconds to respond.

                          martinhjelmareM Offline
                          martinhjelmareM Offline
                          martinhjelmare
                          Plugin Developer
                          wrote on last edited by
                          #38

                          @BartE

                          Yes, very good point.

                          1 Reply Last reply
                          0
                          • N Offline
                            N Offline
                            niccodemi
                            wrote on last edited by
                            #39

                            @martinhjelmare @BartE thank you both for trying to solve this issue but the problem is still there. On reboot relay (usually just 1 never both) gets set randomly in loop function (setup function always restores correct state). I also tried increasing debouncer up to 500 without success. And I am also sure this is not hardware related because if I load sketch which is meant for momentary switch relays work as expected (tested with 10 consecutive reboots). Just to be on the same page this is latest sketch:

                            //MultiRelayButton Sketch, MySensors 1.6
                            
                            #define MY_RADIO_NRF24
                            
                            #define MY_REPEATER_FEATURE
                            
                            #include <MySensor.h>
                            #include <SPI.h>
                            #include <Bounce2.h>
                            #define RELAY_ON 0                      // switch around for realy HIGH/LOW state
                            #define RELAY_OFF 1
                            //
                            
                            #define noRelays 2                     //2-4
                            const int relayPin[] = {14,15};          //  switch around pins to your desire
                            const int buttonPin[] = {3,4};      //  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 debouncer[noRelays];
                            MyMessage msg[noRelays];
                            
                            void setup(){
                                sendHeartbeat();
                                wait(250);
                                // Initialize Relays with corresponding buttons
                                for (int i = 0; i < noRelays; i++){
                                Relays[i].buttonPin = buttonPin[i];              // assign physical pins
                                Relays[i].relayPin = relayPin[i];
                                msg[i].sensor = i;                                   // initialize messages
                                msg[i].type = V_LIGHT;
                                debouncer[i] = Bounce();                        // initialize debouncer
                                debouncer[i].attach(buttonPin[i]);
                                debouncer[i].interval(100);
                                pinMode(Relays[i].buttonPin, INPUT_PULLUP);
                                wait(250);
                                pinMode(Relays[i].relayPin, OUTPUT);
                                //Relays[i].oldValue = digitalRead(Relays[i].buttonPin);
                                Relays[i].relayState = loadState(i);                               // retrieve last values from EEPROM
                                digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF);   // and set relays accordingly
                                send(msg[i].set(Relays[i].relayState? true : false));                  // make controller aware of last status  
                                wait(250);
                                }
                            }
                            void presentation()  {
                                  sendSketchInfo("MultiRelayButton", "0.9k");
                                  wait(250);
                                  for (int i = 0; i < noRelays; i++)
                                  present(i, S_LIGHT);                               // present sensor to gateway
                                  wait(250);
                            }
                            void loop()
                            {
                                for (byte i = 0; i < noRelays; i++) {
                                    if (debouncer[i].update()) {
                                        Relays[i].relayState = !Relays[i].relayState;
                                        digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
                                        send(msg[i].set(Relays[i].relayState? true : false));
                                        // save sensor state in EEPROM (location == sensor number)
                                        saveState( i, Relays[i].relayState );
                                    }                 
                                }
                                wait(50);
                            }
                            // process incoming message 
                            void receive(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
                               saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
                               }
                              }
                              wait(50);
                            }
                            
                            martinhjelmareM 1 Reply Last reply
                            0
                            • N niccodemi

                              @martinhjelmare @BartE thank you both for trying to solve this issue but the problem is still there. On reboot relay (usually just 1 never both) gets set randomly in loop function (setup function always restores correct state). I also tried increasing debouncer up to 500 without success. And I am also sure this is not hardware related because if I load sketch which is meant for momentary switch relays work as expected (tested with 10 consecutive reboots). Just to be on the same page this is latest sketch:

                              //MultiRelayButton Sketch, MySensors 1.6
                              
                              #define MY_RADIO_NRF24
                              
                              #define MY_REPEATER_FEATURE
                              
                              #include <MySensor.h>
                              #include <SPI.h>
                              #include <Bounce2.h>
                              #define RELAY_ON 0                      // switch around for realy HIGH/LOW state
                              #define RELAY_OFF 1
                              //
                              
                              #define noRelays 2                     //2-4
                              const int relayPin[] = {14,15};          //  switch around pins to your desire
                              const int buttonPin[] = {3,4};      //  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 debouncer[noRelays];
                              MyMessage msg[noRelays];
                              
                              void setup(){
                                  sendHeartbeat();
                                  wait(250);
                                  // Initialize Relays with corresponding buttons
                                  for (int i = 0; i < noRelays; i++){
                                  Relays[i].buttonPin = buttonPin[i];              // assign physical pins
                                  Relays[i].relayPin = relayPin[i];
                                  msg[i].sensor = i;                                   // initialize messages
                                  msg[i].type = V_LIGHT;
                                  debouncer[i] = Bounce();                        // initialize debouncer
                                  debouncer[i].attach(buttonPin[i]);
                                  debouncer[i].interval(100);
                                  pinMode(Relays[i].buttonPin, INPUT_PULLUP);
                                  wait(250);
                                  pinMode(Relays[i].relayPin, OUTPUT);
                                  //Relays[i].oldValue = digitalRead(Relays[i].buttonPin);
                                  Relays[i].relayState = loadState(i);                               // retrieve last values from EEPROM
                                  digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF);   // and set relays accordingly
                                  send(msg[i].set(Relays[i].relayState? true : false));                  // make controller aware of last status  
                                  wait(250);
                                  }
                              }
                              void presentation()  {
                                    sendSketchInfo("MultiRelayButton", "0.9k");
                                    wait(250);
                                    for (int i = 0; i < noRelays; i++)
                                    present(i, S_LIGHT);                               // present sensor to gateway
                                    wait(250);
                              }
                              void loop()
                              {
                                  for (byte i = 0; i < noRelays; i++) {
                                      if (debouncer[i].update()) {
                                          Relays[i].relayState = !Relays[i].relayState;
                                          digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
                                          send(msg[i].set(Relays[i].relayState? true : false));
                                          // save sensor state in EEPROM (location == sensor number)
                                          saveState( i, Relays[i].relayState );
                                      }                 
                                  }
                                  wait(50);
                              }
                              // process incoming message 
                              void receive(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
                                 saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
                                 }
                                }
                                wait(50);
                              }
                              
                              martinhjelmareM Offline
                              martinhjelmareM Offline
                              martinhjelmare
                              Plugin Developer
                              wrote on last edited by martinhjelmare
                              #40

                              @niccodemi

                              I think you should setup the button first, pinMode etc, and then setup the debouncer and attach it to the button.

                              https://github.com/thomasfredericks/Bounce2/wiki

                              If you attach the debouncer while the pin is floating, the debouncer will probably have a hard time figuring out correct new state.

                              1 Reply Last reply
                              0
                              • N Offline
                                N Offline
                                niccodemi
                                wrote on last edited by
                                #41

                                @martinhjelmare

                                That was it. After I amended sketch according to your advise all the random state changes disappeared. I rebooted node over 20 times in various button / relay states and it always started with relays in correct position. For anyone else interested below is amended sketch.

                                //MultiRelayButton Sketch, MySensors 1.6, toggle switch
                                
                                #define MY_RADIO_NRF24
                                
                                #define MY_REPEATER_FEATURE
                                
                                #include <MySensor.h>
                                #include <SPI.h>
                                #include <Bounce2.h>
                                #define RELAY_ON 0                      // switch around for ACTIVE LOW / ACTIVE HIGH relay
                                #define RELAY_OFF 1
                                //
                                
                                #define noRelays 2                     //2-4
                                const int relayPin[] = {14,15};          //  switch around pins to your desire
                                const int buttonPin[] = {3,4};      //  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
                                  boolean relayState;               // relay status (also stored in EEPROM)
                                };
                                
                                Relay Relays[noRelays]; 
                                Bounce debouncer[noRelays];
                                MyMessage msg[noRelays];
                                
                                void setup(){
                                    sendHeartbeat();
                                    wait(100);
                                    // Initialize Relays with corresponding buttons
                                    for (int i = 0; i < noRelays; i++){
                                    Relays[i].buttonPin = buttonPin[i];              // assign physical pins
                                    Relays[i].relayPin = relayPin[i];
                                    msg[i].sensor = i;                                   // initialize messages
                                    msg[i].type = V_LIGHT;   
                                    pinMode(Relays[i].buttonPin, INPUT_PULLUP);
                                    wait(100);
                                    pinMode(Relays[i].relayPin, OUTPUT);
                                    Relays[i].relayState = loadState(i);                               // retrieve last values from EEPROM
                                    digitalWrite(Relays[i].relayPin, Relays[i].relayState? RELAY_ON:RELAY_OFF);   // and set relays accordingly
                                    send(msg[i].set(Relays[i].relayState? true : false));                  // make controller aware of last status  
                                    wait(50);
                                    debouncer[i] = Bounce();                        // initialize debouncer
                                    debouncer[i].attach(buttonPin[i]);
                                    debouncer[i].interval(20);
                                    wait(50);
                                    }
                                }
                                void presentation()  {
                                      sendSketchInfo("MultiRelayButton", "0.9t");
                                      wait(100);
                                      for (int i = 0; i < noRelays; i++)
                                      present(i, S_LIGHT);                               // present sensor to gateway
                                      wait(100);
                                }
                                void loop()
                                {
                                    for (byte i = 0; i < noRelays; i++) {
                                        if (debouncer[i].update()) {
                                            Relays[i].relayState = !Relays[i].relayState;
                                            digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
                                            send(msg[i].set(Relays[i].relayState? true : false));
                                            // save sensor state in EEPROM (location == sensor number)
                                            saveState( i, Relays[i].relayState );
                                        }                 
                                    }
                                    wait(20);
                                }
                                // process incoming message 
                                void receive(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
                                   saveState( message.sensor, Relays[message.sensor].relayState ); // save sensor state in EEPROM (location == sensor number)
                                   }
                                  }
                                  wait(20);
                                }
                                
                                1 Reply Last reply
                                0
                                • M Offline
                                  M Offline
                                  moskovskiy82
                                  wrote on last edited by
                                  #42

                                  What is the simplest method to add two extra butons to this sketch not tied to the relay?
                                  I have a four button device. Two will work with relays and two extra utilised in openhab rules

                                  1 Reply Last reply
                                  0
                                  • korttomaK Offline
                                    korttomaK Offline
                                    korttoma
                                    Hero Member
                                    wrote on last edited by
                                    #43

                                    Just in case someone else finds this thread and decides to use the sketch and runs in to the same issue I did.

                                    I was using push buttons and the sketch above, when I pushed the button the relay turned on but as soon as I let go of the button the relay turned back off. I changed the sketch like this:

                                    void loop()
                                    {
                                      for (byte i = 0; i < noRelays; i++) {
                                        if (debouncer[i].update()) {
                                          
                                          int value = debouncer[i].read();
                                          
                                          if ( value == LOW) {
                                            Relays[i].relayState = !Relays[i].relayState;
                                            digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF);
                                            send(msg[i].set(Relays[i].relayState ? true : false));
                                            // save sensor state in EEPROM (location == sensor number)
                                            saveState( i, Relays[i].relayState );
                                          }
                                        }
                                      }
                                      //wait(20);
                                    }
                                    

                                    Now the relay changes state as soon as I push the button and keeps the state until I push the button again.

                                    Because my inputs for the push buttons are ground when pushed I used

                                    if ( value == LOW) 
                                    

                                    This way the relay would turn on immediately when I push the button and not wait until I let go of the button.

                                    • Tomas
                                    Стоян ГеоргиевС 1 Reply Last reply
                                    0
                                    • korttomaK korttoma

                                      Just in case someone else finds this thread and decides to use the sketch and runs in to the same issue I did.

                                      I was using push buttons and the sketch above, when I pushed the button the relay turned on but as soon as I let go of the button the relay turned back off. I changed the sketch like this:

                                      void loop()
                                      {
                                        for (byte i = 0; i < noRelays; i++) {
                                          if (debouncer[i].update()) {
                                            
                                            int value = debouncer[i].read();
                                            
                                            if ( value == LOW) {
                                              Relays[i].relayState = !Relays[i].relayState;
                                              digitalWrite(Relays[i].relayPin, Relays[i].relayState ? RELAY_ON : RELAY_OFF);
                                              send(msg[i].set(Relays[i].relayState ? true : false));
                                              // save sensor state in EEPROM (location == sensor number)
                                              saveState( i, Relays[i].relayState );
                                            }
                                          }
                                        }
                                        //wait(20);
                                      }
                                      

                                      Now the relay changes state as soon as I push the button and keeps the state until I push the button again.

                                      Because my inputs for the push buttons are ground when pushed I used

                                      if ( value == LOW) 
                                      

                                      This way the relay would turn on immediately when I push the button and not wait until I let go of the button.

                                      Стоян ГеоргиевС Offline
                                      Стоян ГеоргиевС Offline
                                      Стоян Георгиев
                                      wrote on last edited by
                                      #44

                                      @korttoma I used this sketch but my vera founds only 1 device and i have no idea why.

                                      korttomaK 1 Reply Last reply
                                      0
                                      • Стоян ГеоргиевС Стоян Георгиев

                                        @korttoma I used this sketch but my vera founds only 1 device and i have no idea why.

                                        korttomaK Offline
                                        korttomaK Offline
                                        korttoma
                                        Hero Member
                                        wrote on last edited by
                                        #45

                                        @Стоян-Георгиев please post the complete sketch along with info about MySensors library version you are using.

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


                                        15

                                        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