Multi Button Relay switch



  • Hi

    Is is possible to attached 4 relays to a node and also control each with a button?


  • Admin

    @Terence-Faul

    Should be possible. But make sure to feed the relays separately.



  • hek

    Do you have an example sketch, I am a newby and would not have any idea how to alter the sketch to include buttons and move the relay pins


  • Admin

    No sorry, I don't have any example that matches your needs exactly.

    Best way to learn (I hope that is what you ultimately want?) is to use at the two relay examples provided and try to modify them.

    If you have any specific question about the code don't hesitate to ask.


  • Contest Winner

    @Terence-Faul said:

    Do you have an example sketch, I am a newby and would not have any idea how to alter the sketch to include buttons and move the relay pins

    try this (untested but compiles)

    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    //
    MySensor gw;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()  
    {  
      Serial.begin(115200);
      gw.begin(incomingMessage, AUTO, false);
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        msg[i].sensor = i;
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(buttonPin[i], INPUT_PULLUP);
        digitalWrite(relayPin[i], LOW);
        pinMode(relayPin[i], OUTPUT);
        gw.present(relayPin[i], S_LIGHT);
        delay(250);
      }
      //retreive from EEPROM last states
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        relayState[i] = gw.loadState(i);
        digitalWrite(relayPin[i], relayState[i]? HIGH : LOW);
        gw.send(msg[i].set(relayState[i]? true : false), true);
        delay(250);
      }
    }
    //
    void loop() 
    {
      gw.process();
      for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != oldValue[i] && value == 0)
        {
          relayState[i] = !relayState[i];
          digitalWrite(relayPin[i], relayState[i]);
          gw.send(msg[i].set(relayState[i]? true : false), true);
        }
        oldValue[i] = value;
      }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck()) 
      {
        Serial.println(F("This is an ack from gateway"));
      }
      for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        if (message.sensor == i)
        {
          if (message.type == V_LIGHT)
          {
            relayState[i] = message.getBool();
            digitalWrite(relayPin[i], relayState[i]); 
            gw.saveState(relayPin[i], relayState[i]);
          }
        }
      }
    }
    


  • there is no problem to put 4 relays.
    you just feed a separate power!!!



  •   // Example sketch fΓΆr a "light switch" where you can control light or something 
      // else from both vera and a local physical button (connected between digital
      // pin 3 and GND).
      // This node also works as a repeader for other nodes
      
      #include <MySensor.h>
      #include <SPI.h>
      #include <Bounce2.h>
      
      #define RELAY_PIN  4  // Arduino Digital I/O pin number for relay 
      #define BUTTON_PIN  3  // Arduino Digital I/O pin number for button 
      #define CHILD_ID 1   // Id of the sensor child
      #define RELAY_ON 1
      #define RELAY_OFF 0
      
      Bounce debouncer = Bounce(); 
      int oldValue=0;
      bool state;
      MySensor gw;
      MyMessage msg(CHILD_ID,V_LIGHT);
      
      void setup()  
      {  
        gw.begin(incomingMessage, AUTO, true);
      
        // Send the sketch version information to the gateway and Controller
        gw.sendSketchInfo("Relay & Button", "1.0");
      
       // Setup the button
        pinMode(BUTTON_PIN,INPUT);
        // Activate internal pull-up
        digitalWrite(BUTTON_PIN,HIGH);
        
        // After setting up the button, setup debouncer
        debouncer.attach(BUTTON_PIN);
        debouncer.interval(5);
      
        // Register all sensors to gw (they will be created as child devices)
        gw.present(CHILD_ID, S_LIGHT);
      
        // Make sure relays are off when starting up
        digitalWrite(RELAY_PIN, RELAY_OFF);
        // Then set relay pins in output mode
        pinMode(RELAY_PIN, OUTPUT);   
            
        // Set relay to last known state (using eeprom storage) 
        state = gw.loadState(CHILD_ID);
        digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
      }
      
      
      /*
      *  Example on how to asynchronously check for new messages from gw
      */
      void loop() 
      {
        gw.process();
        debouncer.update();
        // Get the update value
        int value = debouncer.read();
        if (value != oldValue && value==0) {
            gw.send(msg.set(state?false:true), true); // Send new state and request ack back
        }
        oldValue = value;
      } 
       
      void incomingMessage(const MyMessage &message) {
        // We only expect one type of message from controller. But we better check anyway.
        if (message.isAck()) {
           Serial.println("This is an ack from gateway");
        }
      
        if (message.type == V_LIGHT) {
           // Change relay state
           state = message.getBool();
           digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
           // Store state in eeprom
           gw.saveState(CHILD_ID, state);
          
           // Write some debug info
           Serial.print("Incoming change for sensor:");
           Serial.print(message.sensor);
           Serial.print(", New status: ");
           Serial.println(message.getBool());
         } 
      }
    
    

  • Contest Winner

    @Terence-Faul said:

    gw.sendSketchInfo("Relay & Button", "1.0");

    yeah, a mistake or two πŸ˜‰

    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    //
    MySensor gw;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()  
    {  
      Serial.begin(115200);
      gw.begin(incomingMessage, AUTO, false);
      //
      // or you can try:
      // gw.begin(incomingMessage, <Your_Node_ID>, false); // where Your_Node_ID is a number from 1 to 254
      //
      delay(250);
      gw.sendSketchInfo("MultiRelayButton", "0.9b");// <<<<<<<<<<<<<<<<<<< I forgot this, here
      //
      delay(250);
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        msg[i].sensor = i;
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(buttonPin[i], INPUT_PULLUP);
        digitalWrite(relayPin[i], LOW);
        pinMode(relayPin[i], OUTPUT);
        gw.present(i, S_LIGHT); // <<<<<<<<<<<<<<<<<<<<<<< I fixed this too...
        delay(250);
      }
      //retreive from EEPROM last states
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        relayState[i] = gw.loadState(i);
        digitalWrite(relayPin[i], relayState[i]? HIGH : LOW);
        gw.send(msg[i].set(relayState[i]? true : false), true);
        delay(250);
      }
    }
    //
    void loop() 
    {
      gw.process();
      for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != oldValue[i] && value == 0)
        {
          relayState[i] = !relayState[i];
          digitalWrite(relayPin[i], relayState[i]);
          gw.send(msg[i].set(relayState[i]? true : false), true);
        }
        oldValue[i] = value;
      }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck()) 
      {
        Serial.println(F("This is an ack from gateway"));
      }
      for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        if (message.sensor == i)
        {
          if (message.type == V_LIGHT)
          {
            relayState[i] = message.getBool();
            digitalWrite(relayPin[i], relayState[i]); 
            gw.saveState(relayPin[i], relayState[i]);
          }
        }
      }
    }
    

    try and see if it fixes your issues πŸ™‚


  • Contest Winner

    @Terence-Faul

    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    //
    #define RELAY_ON 1
    #define RELAY_OFF 0
      
    MySensor gw;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()  
    {  
      Serial.begin(115200);
      gw.begin(incomingMessage, AUTO, false);
      //
      // or you can try:
      // gw.begin(incomingMessage, <Your_Node_ID>, false); // where Your_Node_ID is a number from 1 to 254
      //
      delay(250);
      gw.sendSketchInfo("MultiRelayButton", "0.9b");
      //
      delay(250);
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        msg[i].sensor = i;
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(buttonPin[i], INPUT_PULLUP);
        digitalWrite(relayPin[i], LOW);
        pinMode(relayPin[i], OUTPUT);
        gw.present(i, S_LIGHT); 
        delay(250);
      }
      //retreive from EEPROM last states
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        relayState[i] = gw.loadState(i);
        digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF);
        //gw.send(msg[i].set(relayState[i]? RELAY_ON : RELAY_OFF), true);
        delay(250);
      }
    }
    //
    void loop() 
    {
      gw.process();
      for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != oldValue[i] && value == 0)
        {
          relayState[i] = !relayState[i];
          //digitalWrite(relayPin[i], relayState[i]);
          gw.send(msg[i].set(relayState[i]? false : true), true);
        }
        oldValue[i] = value;
      }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck()) 
      {
        Serial.println(F("This is an ack from gateway"));
      }
      for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        if (message.sensor == i)
        {
          if (message.type == V_LIGHT)
          {
            relayState[i] = message.getBool();
            digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF); 
            gw.saveState(relayPin[i], relayState[i]);
          }
        }
      }
    }
    


  • @BulldogLowell

    This new one had the relays correct, but the buttons did not work. I compared the old with the new and below now works.

    Thanks again a million for all the help

    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    
    #define RELAY_ON 0
    #define RELAY_OFF 1
    
    //
    MySensor gw;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()  
    {  
      Serial.begin(115200);
      gw.begin(incomingMessage, AUTO, false);
      //
      // or you can try:
      // gw.begin(incomingMessage, <Your_Node_ID>, false); // where Your_Node_ID is a number from 1 to 254
      //
      delay(250);
      gw.sendSketchInfo("MultiRelayButton", "0.9b");// <<<<<<<<<<<<<<<<<<< I forgot this, here
      //
      delay(250);
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        msg[i].sensor = i;
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(buttonPin[i], INPUT_PULLUP);
        digitalWrite(relayPin[i], LOW);
        pinMode(relayPin[i], OUTPUT);
        gw.present(i, S_LIGHT); // <<<<<<<<<<<<<<<<<<<<<<< I fixed this too...
        delay(250);
      }
      //retreive from EEPROM last states
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        relayState[i] = gw.loadState(i);
        digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF);
        gw.send(msg[i].set(relayState[i]? true : false), true);
        delay(250);
      }
    }
    //
    void loop() 
    {
      gw.process();
      for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != oldValue[i] && value == 0)
        {
          relayState[i] = !relayState[i];
          digitalWrite(relayPin[i], relayState[i]);
          gw.send(msg[i].set(relayState[i]? true : false), true);
        }
        oldValue[i] = value;
      }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck()) 
      {
        Serial.println(F("This is an ack from gateway"));
      }
      for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        if (message.sensor == i)
        {
          if (message.type == V_LIGHT)
          {
            relayState[i] = message.getBool();
            digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF); 
            gw.saveState(relayPin[i], relayState[i]);
          }
        }
      }
    }
    


  • @Terence-Faul
    Only one other thing.

    I notice that when the sensor starts up, each of the relays turn on and then off.

    This ia all good and well, however i assume in practice this would mean what ever is connected to them will turn on and off as well in the initialisation phase.

    Also I assume that retrieve from EEPROM means that if the sensor loses power while a relay is on, when it powers up this relay will return to the on state?

    Can you point me to to code that controls this, if these are lights and the power goes out a better option may be to have the relays all start in the off position so that the lights do not come on in the middle of the night

    Is this correct?



  • Bulldog

    So this is as far as I got.

    Managed to get the relays to start in the off position by Changing LOW for the defined RELAY_OFF.

    Commented out the EEPROM Section and now when the sensor reboots is starts with all relays in off position.

    I do not know how to change the EEPROM section I am sur I need to maybe include the RELAY_OFF somewhere in that line.

    #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;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()  
    {  
      Serial.begin(115200);
      gw.begin(incomingMessage, AUTO, false);
      //
      // or you can try:
      // gw.begin(incomingMessage, <Your_Node_ID>, false); // where Your_Node_ID is a number from 1 to 254
      //
      delay(250);
      gw.sendSketchInfo("MultiRelayButton", "0.9b");// <<<<<<<<<<<<<<<<<<< I forgot this, here
      //
      delay(250);
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        msg[i].sensor = i;
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(buttonPin[i], INPUT_PULLUP);
        digitalWrite(relayPin[i], RELAY_OFF); //Start State of Relays
        pinMode(relayPin[i], OUTPUT);
        gw.present(i, S_LIGHT); // <<<<<<<<<<<<<<<<<<<<<<< I fixed this too...
        delay(250);
      }
      //retreive from EEPROM last states
    //  for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)//>>>>>>> I'm sure that this is causing all relays to turn on and off at startup
    //  {
    //    relayState[i] = gw.loadState(i);
    //    digitalWrite(relayPin[i], relayState[i]? RELAY_ON:RELAY_OFF);
    //    gw.send(msg[i].set(relayState[i]? true : false), true);
    //    delay(250);
    //  }
    //  
    }
    //
    void loop() 
    {
      gw.process();
      for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != oldValue[i] && value == 0)
        {
          relayState[i] = !relayState[i];
          digitalWrite(relayPin[i], relayState[i]);
          gw.send(msg[i].set(relayState[i]? true : false), true);
        }
        oldValue[i] = value;
      }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck()) 
      {
        Serial.println(F("This is an ack from gateway"));
      }
      for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        if (message.sensor == i)
        {
          if (message.type == V_LIGHT)
          {
            relayState[i] = message.getBool();
            digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF); 
            gw.saveState(relayPin[i], relayState[i]);
          }
        }
      }
    }
    

  • Contest Winner

    @Terence-Faul said:

    gw.saveState(relayPin[i], relayState[i]);

    if you are not relying on settings saved to EEPROM to recover its state after a power cycle, you can also comment our or remove this line:

    gw.saveState(relayPin[i], relayState[i]);
    

    it saves the state of the relay each time it gets changed.

    glad to see you are learning and have it working just the way you like.



  • Thanks a stack, it is slow.

    If I did want to restore the relay state how would I change the code?

    At the moment if I leave that code in when the arduino boots it cycles each relay on and then off, instead of just restoring the previous state



  • go for SSR instead of hk mechical relay it will stop working after 10,000 clicked ... cheap brand



  • I got the same question as @Terence-Faul, How to change the code to have the Relay to restore its previous state. I tried a couple of things but can't seem to get it to work. Thanks @BulldogLowell for the script !


  • Contest Winner

    @jeylites ,

    so, try to look over the example just above the one that worked for @Terence-Faul

    It included saving states to EEPROM and retrieving them in setup( ).



  • How do you seperate relay power?

    What is your solution to drop 220v AC to 5v DC?



  • @C.r.a.z.y. You could get a USB power adapter... see Ebay link below. On my current setup, I'm using a 2.1A+1A Dual USB 2-Ports. I use the the 1A port for the Arduino and the 2.1A port for the relays. On the relay board, you have VCC, IN1 & GND. IN1 gets connected to the Arduino, VCC to the second power supply or power port. The GND is shared between both power ports. Hope that helps!

    http://www.ebay.com/sch/i.html?_from=R40&_trksid=p2141725.m570.l1313.TR12.TRC2.A0.H0.XUSB+Wall+Charger+.TRS0&_nkw=USB+Wall+Charger+&ghostText=&_sacat=0



  • @BulldogLowell

    I have gone through the script like 8 times with no luck at all. Are you suggesting the mistake in in the EEPROM retrieval section ?

    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    
    #define RELAY_ON 1 //switch around for realy HIGH/LOW state
    #define RELAY_OFF 0
    
    //
    MySensor gw;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()
    {
    Serial.begin(115200);
    gw.begin(incomingMessage, AUTO, true);
    //
    // or you can try:
    // gw.begin(incomingMessage, <Your_Node_ID>, false); // where Your_Node_ID is a number from 1 to 254
    //
    delay(250);
    gw.sendSketchInfo("MultiRelayButton", "0.9b");
    
    delay(250);
    for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
    {
    msg[i].sensor = i;
    msg[i].type = V_LIGHT;
    debouncer[i] = Bounce();
    debouncer[i].attach(buttonPin[i]);
    debouncer[i].interval(5);
    pinMode(buttonPin[i], INPUT_PULLUP);
    digitalWrite(relayPin[i], RELAY_OFF); //Start State of Relays
    pinMode(relayPin[i], OUTPUT);
    gw.present(i, S_LIGHT);
    delay(250);
    }
    //retreive from EEPROM last states
    for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)//>>>>>>> I'm sure that this is causing all relays to turn on and off at startup
    {
    relayState[i] = gw.loadState(i);
    digitalWrite(relayPin[i], relayState[i]? RELAY_ON:RELAY_OFF);
    //gw.send(msg[i].set(relayState[i]? true : false), true);
    delay(250);
    }
    
    }
    
    void loop()
    {
    gw.process();
    for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
    {
    debouncer[i].update();
    byte value = debouncer[i].read();
    if (value != oldValue[i] && value == 0)
    {
    relayState[i] = !relayState[i];
    digitalWrite(relayPin[i], relayState[i]);
    gw.send(msg[i].set(relayState[i]? true : false), true);
    }
    oldValue[i] = value;
    }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
    if (message.isAck())
    {
    Serial.println(F("This is an ack from gateway"));
    }
    for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
    {
    if (message.sensor == i)
    {
    if (message.type == V_LIGHT)
    {
    relayState[i] = message.getBool();
    digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF);
    gw.saveState(relayPin[i], relayState[i]);
    }
    }
    }
    }```
    
    
    
    
    
    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    
    #define RELAY_ON 1  //switch around for realy HIGH/LOW state
    #define RELAY_OFF 0
    
    //
    MySensor gw;
    const int relayPin[] = {7, 8, A0, A1};
    const int buttonPin[sizeof(relayPin) / sizeof(relayPin[0])] = {3, 4, 5, 6};
    byte oldValue[sizeof(relayPin) / sizeof(relayPin[0])];
    boolean relayState[sizeof(relayPin) / sizeof(relayPin[0])];
    
    Bounce debouncer[sizeof(relayPin) / sizeof(relayPin[0])];
    
    MyMessage msg[sizeof(relayPin) / sizeof(relayPin[0])];//(sensor,type);
    
    void setup()  
    {  
      Serial.begin(115200);
      gw.begin(incomingMessage, AUTO, true);
      //
      // or you can try:
      // gw.begin(incomingMessage, <Your_Node_ID>, false); // where Your_Node_ID is a number from 1 to 254
      //
      delay(250);
      gw.sendSketchInfo("MultiRelayButton", "0.9b");
      
      delay(250);
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        msg[i].sensor = i;
        msg[i].type = V_LIGHT;
        debouncer[i] = Bounce();
        debouncer[i].attach(buttonPin[i]);
        debouncer[i].interval(5);
        pinMode(buttonPin[i], INPUT_PULLUP);
        digitalWrite(relayPin[i], RELAY_OFF); //Start State of Relays
        pinMode(relayPin[i], OUTPUT);
        gw.present(i, S_LIGHT);
        delay(250);
      }
      //retreive from EEPROM last states
      for (int i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)//>>>>>>> I'm sure that this is causing all relays to turn on and off at startup
      {
        relayState[i] = gw.loadState(i);
        digitalWrite(relayPin[i], relayState[i]? RELAY_ON:RELAY_OFF);
        //gw.send(msg[i].set(relayState[i]? true : false), true);
        delay(250);
      }
      
    }
    
    void loop() 
    {
      gw.process();
      for (byte i = 0; i < sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        debouncer[i].update();
        byte value = debouncer[i].read();
        if (value != oldValue[i] && value == 0)
        {
          relayState[i] = !relayState[i];
          digitalWrite(relayPin[i], relayState[i]);
          gw.send(msg[i].set(relayState[i]? true : false), true);
        }
        oldValue[i] = value;
      }
    }
    //
    void incomingMessage(const MyMessage &message)
    {
      if (message.isAck()) 
      {
        Serial.println(F("This is an ack from gateway"));
      }
      for (byte i = 0; i< sizeof(relayPin) / sizeof(relayPin[0]); i++)
      {
        if (message.sensor == i)
        {
          if (message.type == V_LIGHT)
          {
            relayState[i] = message.getBool();
            digitalWrite(relayPin[i], relayState[i]? RELAY_ON : RELAY_OFF); 
            gw.saveState(relayPin[i], relayState[i]);
          }
        }
      }
    }

  • Hero Member

    @jeylites You are initializing the relays with the "Start State of Relays" and afterwards with the state from EEPROM. That could cause the on/off switching at startup.



  • To Elaborate on what AWI said

    @jeylites said:

    digitalWrite(relayPin[i], RELAY_OFF); //Start State of Relays
    ...
    digitalWrite(relayPin[i], relayState[i]? RELAY_ON:RELAY_OFF);

    You have both of those lines in your Setup() The first one is setting the relay to off the second one is checking the EEPROM value

    Remove the first one and the problems should be fixed (assuming the EEPROM data is correct.



  • @Chaotic , @AWI

    //digitalWrite(relayPin[i], RELAY_OFF); //Start State of Relays
    I did as you say and removed the above line but still no luck. The relay turns on/off on every start up. And it doesn't hold the last state. I compared My Sensor's script with Bulldogs's and found lots of similarities but can't seem to find the fault.


  • Hero Member

    @jeylites I took a deeper look at your sketch and think I found the cause. You are writing and reading from different EEPROM locations. The "standard" way is to use the "Sensor number" as location reference. Whereas the sketch also used "relayPin[i]" to store values. I took the liberty of adapting your sketch as I found it hard to read. Also added storing the value in EEPROM after pushing a button.
    I have not build the circuit so were not able to test it in real life πŸ™‚ Have fun and let me know if it worked for you.

    https://codebender.cc/sketch:92964



  • @AWI Thank you so much. This is awesome! I bet so many people is going to benefit from this script.

    I had some time off today and ran the script. It didn't work the fist time, but I made some minor changes to "Relay_ON & Relay_OFF and also activated " Start State of Relays" and it worked. I'm guessing it didn't the first time because my relays are Active Low.

    Also, while toying around with it, I realize that it doesn't send back the status of the relay & actuator to the Controller (Homeseer). On Homeseer, suppose you have it at β€œON” there is a maker that indicates its state and vice versa. I noticed that worked on Binary Switch & Motion Sensor but not on Relay & Relay Button Actuator sketch. Don't know if it's a script or Homeseer issue though.

    Again, thanks, everyone who helped pointing out the problem. I'm new to My Sensor and I'm glad to be here and making progress.

    #define RELAY_ON 0 //switch around for relay HIGH/LOW state
    #define RELAY_OFF 1

    pinMode(Relays[i].relayPin, OUTPUT);



  • @AWI I just realize another thing. The is a long delay for the sensor to sends its presentation during inclusion mode. Is there something to do with the number of sensors in one node or sketch? Essentially, I would have to reset the sensor several times to get it discovered.
    It's pretty quick on a single or double sensor node.


  • Hero Member

    @jeylites I don't have experience with Homeseer as controller.and don't fully understand your questions, so just give it a shot..

    The multi relay sketch is firing a large amount of messages to the gateway/ controller during presentation. If you have transmission problems and/or a slow controller it could get into trouble. I suggest you monitor on the serial port of the sensor if there are "fail" messages. (need to turn on DEBUG = default) If there are it could be a power problem or...

    The real fun (and headache) is in the debugging πŸ™‚ The serial monitor can give you lost of clues

    Depending on how long is "long". there are also 250 ms delays between the individual presentations of the relays. ..'
    have fun πŸ˜‰



  • @AWI

    I think you're right on the controller. I've been getting some glitch running HS3 on Mac. I don't know if its a plugin or software issue, but I will like to get to the bottom of it. In addition, a buddy of mine is loaning his Vera edge so I might run some test on that too.

    Meanwhile, will take your advice on serial monitor and will let you know the outcome. Cheers!



  • Thanks for sharing.
    I have a problem with this scripts. My relay auto start then off every gateway check node. How can i fix it?
    Thanks



  • @quocanhcgd

    You will need to activate this line pinMode(Relays[i].relayPin, OUTPUT);

    It should work right after.



  • I activated this line but no result. may be openhab work wrong? What the controller you use?
    @jeylites said:

    @quocanhcgd

    You will need to activate this line pinMode(Relays[i].relayPin, OUTPUT);

    It should work right after.



  • @quocanhcgd Homeseer



  • @quocanhcgd

    I have tested the sketch on vera Ui7 & Homeseer but I don't know why it takes a very long time for the sketch to send individual presentations of the relay to the controller. Sometimes it doesn't send it at all. I have changed power supply as @AWI suggested and the relays are not connected to the Arduino at this time. Still nothing. Anyone here knows what the fail messages are. Below is the serial messages I got....

    repeater started, id 2
    send: 2-2-0-0 s=255,c=0,t=18,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=255,c=3,t=6,pt=1,l=1,st=fail:0
    send: 2-2-0-0 s=255,c=3,t=11,pt=0,l=16,st=ok:MultiRelayButton
    send: 2-2-0-0 s=255,c=3,t=12,pt=0,l=4,st=ok:0.9b
    send: 2-2-0-0 s=0,c=1,t=2,pt=2,l=2,st=fail:1
    send: 2-2-0-0 s=0,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=1,c=1,t=2,pt=2,l=2,st=fail:1
    send: 2-2-0-0 s=1,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=2,c=1,t=2,pt=2,l=2,st=fail:1
    send: 2-2-0-0 s=2,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=3,c=1,t=2,pt=2,l=2,st=fail:0
    send: 2-2-255-255 s=255,c=3,t=7,pt=0,l=0,st=fail:
    send: 2-2-0-0 s=3,c=0,t=3,pt=0,l=5,st=fail:1.4.1


  • Hero Member

    @jeylites I would suggest you take a closer look at the hardware. Almost all messages are failing and in most cases radio reception is the cause. Have you used capacitors on the radio's?



  • @AWI
    No. Now that you mention it. I'm going to work on that. What does "st=fail:1.4.1" mean?



  • That there is an issue in the radio communication, and most probably the reason why it's taking so long, as all the failed transmissions will be retransmitted.
    Like mentioned above (and on the webpage) you should install the capacitors on the radio.

    Check the decoupling capacitor part of this page how to do this :
    http://www.mysensors.org/build/connect_radio



  • Still get the same error message despite putting a 4.7uf cap across GND and VCC (3.3v) on the radio for both sensor and gateway. But I don't get any fail messages using a different My Sensor sketch. What is error message: "st=fail:1.4.1" suggesting?

    repeater started, id 1
    send: 1-1-0-0 s=255,c=0,t=18,pt=0,l=5,st=ok:1.4.1
    send: 1-1-0-0 s=255,c=3,t=6,pt=1,l=1,st=ok:0
    read: 0-0-1 s=255,c=3,t=6,pt=0,l=1:M
    send: 1-1-0-0 s=255,c=3,t=11,pt=0,l=16,st=ok:MultiRelayButton
    send: 1-1-0-0 s=255,c=3,t=12,pt=0,l=4,st=ok:0.9b
    send: 1-1-0-0 s=0,c=1,t=2,pt=2,l=2,st=ok:0
    send: 1-1-0-0 s=0,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 1-1-0-0 s=1,c=1,t=2,pt=2,l=2,st=ok:0
    send: 1-1-0-0 s=1,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 1-1-0-0 s=2,c=1,t=2,pt=2,l=2,st=ok:0
    send: 1-1-0-0 s=2,c=0,t=3,pt=0,l=5,st=ok:1.4.1
    send: 1-1-0-0 s=3,c=1,t=2,pt=2,l=2,st=ok:1
    send: 1-1-0-0 s=3,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    read: 0-0-1 s=2,c=1,t=2,pt=2,l=2:0
    This is an ack from gateway


  • Hero Member

    @jeylites What I read from the log is that there seems to be a little problem with sending a bunch of messages after another. (intermittent failures) probably because the radio power supply is not keeping up. Possible solutions: hardware: increase the capacitor size (eg. 47 uF) ; software: avoid sending messages after another and put a delay in between (like the 250ms delay used in your original setup() code).

    Fail:1..4.1 means that something went wrong in communication with MySensors version 1.4.1. The good news is that the number of fail messages is decreasing with respect to the earlier log πŸ‘


  • Hero Member

    @jeylites you can also try adding some delay between each gw.send or gw.present. In my case it did the difference.



  • @AWI said:

    sending messages after another

    I have put a 47uf, 100V capacitor in parallel with GND and 3.3V on the radio side and needless to say, it did help in reducing the number of fails. I have yet to receive my 5V to 3.3 radio adapter from China so I'm currently running of a two 1.5Vdc battery wired in series to the NRF radio.

    In addition, I've also put a 250ms delay between sending messages after another. With every precaution in place, I'm still getting these same messages. I'm only having this problem with this particular sketch.

    repeater started, id 2
    send: 2-2-0-0 s=255,c=0,t=18,pt=0,l=5,st=ok:1.4.1
    send: 2-2-0-0 s=255,c=3,t=6,pt=1,l=1,st=ok:0
    read: 0-0-2 s=255,c=3,t=6,pt=0,l=1:M
    send: 2-2-0-0 s=255,c=3,t=11,pt=0,l=16,st=ok:MultiRelayButton
    send: 2-2-0-0 s=255,c=3,t=12,pt=0,l=4,st=ok:0.9b
    send: 2-2-0-0 s=0,c=1,t=2,pt=2,l=2,st=ok:0
    send: 2-2-0-0 s=0,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=1,c=1,t=2,pt=2,l=2,st=ok:0
    send: 2-2-0-0 s=1,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=2,c=1,t=2,pt=2,l=2,st=ok:1
    send: 2-2-0-0 s=2,c=0,t=3,pt=0,l=5,st=fail:1.4.1
    send: 2-2-0-0 s=3,c=1,t=2,pt=2,l=2,st=ok:1
    send: 2-2-0-0 s=3,c=0,t=3,pt=0,l=5,st=fail:1.4.1


  • Hero Member

    Maybe it worth a try, to remove the ACK requests? Remove the last 'true' from every gw.send line:

      gw.send(msg[i].set(Relays[i].relayState? true : false) ) ;
    

    Some fake radios don't play well with ACK messages. At least it worked for me.



  • @rvendrame

    Ever since I removed ACK & true, I have not been having any fails at all.

    Everything works and I have posted the final sketch in Array Relay Button Actuator as linked below... Hope it comes in handy. Thanks again MYS community!

    http://forum.mysensors.org/topic/1299/array-relay-button-actuator/12



  • This post is deleted!

Log in to reply
 

Suggested Topics

  • 87
  • 5
  • 8
  • 7
  • 3
  • 7

9
Online

11.4k
Users

11.1k
Topics

112.7k
Posts