Relay control - bistable switch instead of monostable.

  • Hello

    I'm using modified my-sensors sketch to control few relays. Arduino is connected via usb cable with Domoticz.

    Everything works fine but the sketch is designed for monostable switch (doorbell type)

    Point is I would like to use standard (bistable) switch instead of (monostable) doorbell switch.

    Could You please help me with modifying the sketch ?!?

    Thank You in advance.
    Below the code.

    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    // Enable and select radio type attached
    //#define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    // Set LOW transmit power level as default, if you have an amplified NRF-module and
    // power your radio separately with a good regulator you can turn up PA level. 
    //#define MY_RF24_PA_LEVEL RF24_PA_LOW
    // Enable serial gateway
    // Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
    #if F_CPU == 8000000L
    #define MY_BAUD_RATE 38400
    // Flash leds on rx/tx/err
    // Set blinking period
    // #define MY_DEFAULT_LED_BLINK_PERIOD 300
    // Inverses the behavior of leds
    // Enable inclusion mode
    // Enable Inclusion mode button on gateway
    // Inverses behavior of inclusion button (if using external pullup)
    // Set inclusion mode duration (in seconds)
    // Digital pin used for inclusion mode button
    // Uncomment to override default HW configurations
    //#define MY_DEFAULT_ERR_LED_PIN 4  // Error led pin
    //#define MY_DEFAULT_RX_LED_PIN  6  // Receive led pin
    //#define MY_DEFAULT_TX_LED_PIN  5  // the PCB, on board LED
    #include <SPI.h>
    #include <MySensors.h>  
    #include <Bounce2.h>
    // Enable repeater functionality for this node
    // #define MY_REPEATER_FEATURE
    #define RELAY_1  4  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
    #define RELAY_2  5
    #define RELAY_3  6
    #define RELAY_4  7
    #define NUMBER_OF_RELAYS 4 // Total number of attached relays
    #define RELAY_ON 0  // GPIO value to write to turn on attached relay
    #define RELAY_OFF 1 // GPIO value to write to turn off attached relay
    #define BUTTON_PIN A1
    #define BUTTON2_PIN A2
    #define BUTTON3_PIN A3
    #define BUTTON4_PIN A4
    void before() { 
      for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
        // Then set relay pins in output mode
        pinMode(pin, OUTPUT);   
        // Set relay to last known state (using eeprom storage) 
        digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
    Bounce debouncer = Bounce();
    Bounce debouncer2 = Bounce();
    Bounce debouncer3 = Bounce();
    Bounce debouncer4 = Bounce();
    void setup() { 
      // Setup locally attached sensors
       // Setup the button.
      // After setting up the button, setup debouncer.
    void presentation()  
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Relay", "1.0");
      for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
        // Register all sensors to gw (they will be created as child devices)
        present(sensor, S_LIGHT);
    MyMessage msg(1, V_LIGHT);
    MyMessage msg2(2, V_LIGHT);
    MyMessage msg3(3, V_LIGHT);
    MyMessage msg4(4, V_LIGHT);
    void loop() { 
      // Send locally attached sensor data here 
      if (debouncer.update()) {
        // Get the update value.
        int value =;
        // Send in the new value.
        if(value == LOW){
             saveState(1, !loadState(1));
             digitalWrite(RELAY_1, loadState(1)?RELAY_ON:RELAY_OFF);
      if (debouncer2.update()) {
          int value2 =;
        if(value2 == LOW){
             saveState(2, !loadState(2));
             digitalWrite(RELAY_2, loadState(2)?RELAY_ON:RELAY_OFF);
    if (debouncer3.update()) {
          int value3 =;
        if(value3 == LOW){
             saveState(3, !loadState(3));
             digitalWrite(RELAY_3, loadState(3)?RELAY_ON:RELAY_OFF);
    if (debouncer4.update()) {
          int value4 =;
        if(value4 == LOW){
             saveState(4, !loadState(4));
             digitalWrite(RELAY_4, loadState(4)?RELAY_ON:RELAY_OFF);
    void receive(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.type==V_LIGHT) {
         // Change relay state
         digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
         // Store state in eeprom
         saveState(message.sensor, message.getBool());
         // Write some debug info
         Serial.print("Incoming change for sensor:");
         Serial.print(", New status: ");

  • @Plantex By bistable switch, are you talking a standard on/off switch?

  • Yes, standard on/off switch

  • @Plantex For a bistable switch, my guess is that you would not want to just use the on/off state of the switch. I would think that you would want to look to see when the switch changes state, either from off to on, or from on to off. The reason for this is simple. If you have the switch set so that when contact is on, the relay is on, then you are stuck in that state. If a command comes in to the node to turn it off, it will be stuck on because the switch will continue to tell it that it is on. By checking the state change of the switch, you can just have it invert the state of the relay when that state change occurs.

    For the hardware, just connect the common and 1 pole of a switch to the same connections as the push button switches. When the switch is flipped, the value of BUTTONx_PIN will either be high or low.

    As far as the code for this, I would add 4 new variables to save the last state of each switch. Lets just name them last_state1 - last_state4.

    #define BUTTON4_PIN A4
    boolean last_state1 = LOW;
    boolean last_state2 = LOW;
    boolean last_state3 = LOW;
    boolean last_state4 = LOW;

    Next, we'll change the IF statement for each debouncer from this:

    if(valueX == LOW){

    to this

    if(valueX != last_stateX){

    And then after each IF check of the state, update the last_stateX:

        if(valueX != last_stateX){
             saveState(X !loadState(X));
             digitalWrite(RELAY_X, loadState(X)?RELAY_ON:RELAY_OFF);
      last_stateX = valueX;

    Obviously, in all the above code, replace X with the number of the relay that you are working on, so for relay 3, the last bit of code would look like this:

        if(value3 != last_state3){
             saveState(3, !loadState(3));
             digitalWrite(RELAY_3, loadState(3)?RELAY_ON:RELAY_OFF);
      last_state3 = value3;

    Using this method will cause the switch to act like other 3-way switches in that the standard up is on, down is off will not apply.

  • I am using below sketch; make sure that number of relays matches number of relayPins and buttonPins.

    //MultiRelayButton Sketch, MySensors 1.6, toggle switch
    #define MY_RADIO_NRF24
    //Set Static node id
    //#define MY_NODE_ID 250
    #include <MySensors.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)
      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(){
        // 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);
        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  
        debouncer[i] = Bounce();                        // initialize debouncer
    void presentation()  {
          sendSketchInfo("MultiRelayButton", "1.0");
          for (int i = 0; i < noRelays; i++)
          present(i, S_LIGHT);                               // present sensor to gateway
    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 );
    // 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)

  • This post is deleted!

  • @niccodemi Though I agree that that is a better cleaner approach to the original sketch, it doesn't answer the OPs question. Maybe convert it using the info that I posted to make it relevant to the OPs question.

  • Thank You. Works perfect and reporting to Domoticz/Imperi Home.

Log in to reply

Suggested Topics

  • 3
  • 1
  • 10
  • 2
  • 2
  • 24