Multirelay for Home Assistant



  • Hi
    Is anybody who has or who can write sketch for multirelay with buttons controlled by Arduino Mega 2560 some pcs relay board as example:
    https://www.aliexpress.com/item/16-Channel-5V-Relay-Shield-Module-with-optocoupler-LM2576-Power-supply-For-Arduino/32700261256.html?spm=2114.search0604.3.1.6ee871cdJslziS&s=p&ws_ab_test=searchweb0_0,searchweb201602_1_10065_10068_10843_10059_10884_10887_312_10696_100031_10084_10083_10103_10618_10304_10307_10820_10301_10821_528,searchweb201603_45,ppcSwitch_4&algo_expid=9778a327-b65b-44d1-8d96-1b16e3c4bf04-0&algo_pvid=9778a327-b65b-44d1-8d96-1b16e3c4bf04&priceBeautifyAB=0

    In sketch good if will be option to define which relay should read state from eeprom, which alsways is ON or OFF after restart lost power.I have this sketch... it is very good but he always read states from eeprom. Maybe we can modify this. Please help me...

    // Enable debug prints to serial monitor
    //#define USE_EXPANDER
    #define MY_DEBUG
     
    #define MY_GATEWAY_SERIAL
    #define MY_INCLUSION_MODE_FEATURE
    #define MY_INCLUSION_BUTTON_FEATURE
    #define MY_INCLUSION_MODE_DURATION 60
    #define MY_INCLUSION_MODE_BUTTON_PIN  3
     
    #include <MySensors.h>
    #include <Bounce2.h>
    #ifdef USE_EXPANDER
      #include <Wire.h>    // Required for I2C communication
      #include "PCF8574.h" // Required for PCF8574
      PCF8574 expander0;
      // Expander constants
      #define E00 0x0100
      #define E01 0x0101
      #define E02 0x0102
      #define E03 0x0103
      #define E04 0x0104
      #define E05 0x0105
      #define E06 0x0106
      #define E07 0x0107
    #endif
     
    // No Button Constant
    #define NOB -1
    #define MULTI_RELAY_VERSION 7
    #define RELAY_STATE_STORAGE 1
    
    #define RELAY_ON 1
    #define RELAY_OFF 0
     
    enum ButtonType {
      MONO_STABLE = 0,
      BI_STABLE = 1,
      DING_DONG = 3 // HIGH state immediatly after push, LOW state after release
    };
     
    typedef struct {
      int relay;
      int button;
      uint8_t relayTrigger;
      ButtonType buttonType;
    } RelayButton;
     
    // CONFIGURE ONLY THIS ARRAY!
    // Row params: relay pin, button pin, relay trigger [HIGH|LOW], button type [MONO_STABLE|BI_STABLE]
    RelayButton myRelayButtons[] = {
        {4, A0, HIGH, MONO_STABLE},
        {5, A1, HIGH, MONO_STABLE},
        {6, A2, HIGH, MONO_STABLE},
        {7, A3, HIGH, MONO_STABLE},
        {8, A4, HIGH, MONO_STABLE},
        {9, A5, HIGH, MONO_STABLE},
        {10, A6, HIGH, MONO_STABLE},
        {11, A7, HIGH, MONO_STABLE},
    };
     
    const int numberOfRelayButtons = sizeof(myRelayButtons) / sizeof(RelayButton);
     
    typedef struct {
      int firstButton;
      int nextButton;
    } RelayMultiButtons;
     
    RelayMultiButtons relayMultiButtons[numberOfRelayButtons];
     
    // MySensors - Sending Data
    // To send data you have to create a MyMessage container to hold the information.
    MyMessage msgs[numberOfRelayButtons];
     
    Bounce myButtonDebouncer[numberOfRelayButtons];
     
     
    // MySensors - This will execute before MySensors starts up
    void before() {
      Serial.begin(115200);
     
      #ifdef USE_EXPANDER
        /* Start I2C bus and PCF8574 instance */
        expander0.begin(0x20);
      #endif
     
      // initialize multiple buttons list structure
      for (int i = 0; i < numberOfRelayButtons; i++) {
        relayMultiButtons[i].firstButton = -1;
        relayMultiButtons[i].nextButton = -1;
      }
      // find multiple buttons for the same relay (uni-directional list)
      for (int i = 0; i < numberOfRelayButtons-1; i++) {
        if (relayMultiButtons[i].firstButton == -1) {
          int prevRelayButton = i;
          for (int j = i+1; j < numberOfRelayButtons; j++) {
            if (myRelayButtons[i].relay == myRelayButtons[j].relay) {
              relayMultiButtons[prevRelayButton].firstButton = i;
              relayMultiButtons[prevRelayButton].nextButton = j;
              relayMultiButtons[j].firstButton = i;
              prevRelayButton = j;
            }
          }
        }
      }
     
      // if version has changed, reset state of all relays
      int versionChangeResetState = 0;
      if (MULTI_RELAY_VERSION != loadState(0) )
      for (int i = 0; i < numberOfRelayButtons; i++) {
        // if this relay has multiple buttons, load only first
        if (relayMultiButtons[i].firstButton == -1 || relayMultiButtons[i].firstButton == i) {
          // Then set relay pins in output mode
          #ifdef USE_EXPANDER
            if ( myRelayButtons[i].relay >= 0x0100 ) {
              // EXPANDER
              expander0.pinMode(myRelayButtons[i].relay & 0xf, OUTPUT);
            } else {
          #endif
              pinMode(myRelayButtons[i].relay, OUTPUT);
          #ifdef USE_EXPANDER
            }
          #endif
         
          uint8_t isTurnedOn = 0;
         
          if (versionChangeResetState) {
            saveRelayState(i, 0);
          } else {
            // Set relay to last known state (using eeprom storage)
            isTurnedOn = loadRelayState(i); // 1 - true, 0 - false
          }
          uint8_t state = isTurnedOn ? myRelayButtons[i].relayTrigger : ! myRelayButtons[i].relayTrigger;
          digitalWrite(myRelayButtons[i].relay, state);
        }
      }
    }
     
    // executed AFTER mysensors has been initialised
    void setup() {
      // Setup locally attached sensors
      delay(5000);
      // Setup Relays
      for(int i = 0; i < numberOfRelayButtons; i++) {
        // if this relay has multiple buttons, send only first
        if (relayMultiButtons[i].firstButton == -1 || relayMultiButtons[i].firstButton == i) {
          msgs[i] = MyMessage(i, V_LIGHT);
          send(msgs[i].set(loadRelayState(i))); // send current state
        }
      }
      // Setup buttons
      for(int i = 0; i < numberOfRelayButtons; i++) {
        if (myRelayButtons[i].button >= 0) {
          // No Expander support for buttons (de-bouncing)
          pinMode(myRelayButtons[i].button, INPUT_PULLUP); // HIGH state when button is not pushed
          // After setting up the button, setup debouncer.
          myButtonDebouncer[i] = Bounce();
          myButtonDebouncer[i].attach(myRelayButtons[i].button);
          myButtonDebouncer[i].interval(50);
        }
      }
      //presentation();
    }
     
    void loop() {
      for(int i = 0; i < numberOfRelayButtons; i++) {
        if (myRelayButtons[i].button >= 0 && myButtonDebouncer[i].update()) {
          int buttonState = myButtonDebouncer[i].read();
          #ifdef MY_DEBUG
            Serial.print("Button ");
            Serial.print(i);
            Serial.print(" changed to: ");
            Serial.println(buttonState);
          #endif
         
          int nextButton = (relayMultiButtons[i].firstButton == -1) ? i : relayMultiButtons[i].firstButton;
         
          if (myRelayButtons[i].buttonType == DING_DONG) {
            if (buttonState == LOW) { // button pressed
              digitalWrite(myRelayButtons[nextButton].relay, myRelayButtons[nextButton].relayTrigger);
              send(msgs[nextButton].set(1));
            } else { // button released
              digitalWrite(myRelayButtons[nextButton].relay, ! myRelayButtons[nextButton].relayTrigger);
              send(msgs[nextButton].set(0));
            }
          } else if (myRelayButtons[i].buttonType == BI_STABLE || buttonState == HIGH) {
            // If button type is BI_STABLE, any change will toggle relay state
            // For MONO_STABLE, button must be pushed and released (HIGH)
            uint8_t isTurnedOn = ! loadRelayState(nextButton); // 1 - true, 0 - false
            uint8_t newState = isTurnedOn ? myRelayButtons[nextButton].relayTrigger : ! myRelayButtons[nextButton].relayTrigger;
            digitalWrite(myRelayButtons[nextButton].relay, newState);
            send(msgs[nextButton].set(isTurnedOn));
           
            // update state in eeprom for all buttons
            do {
              saveRelayState(nextButton, isTurnedOn);
              nextButton = relayMultiButtons[nextButton].nextButton;
            } while (nextButton != -1);
          }
        }
      }
    }
     
     
     
    // MySensors - Presentation
    // Your sensor must first present itself to the controller.
    // The presentation is a hint to allow controller prepare for the sensor data that eventually will come.
    // void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool ack);
    //   childSensorId - The unique child id you want to choose for the sensor connected to this Arduino. Range 0-254.
    //   sensorType - The sensor type you want to create.
    //   description An optional textual description of the attached sensor.
    //   ack - Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Multi Relay", "1.1");
       
        // Register every relay as separate sensor
      for (int i = 0; i < numberOfRelayButtons; i++) {
        // if this relay has multiple buttons, register only first
        if (relayMultiButtons[i].firstButton == -1 || relayMultiButtons[i].firstButton == i) {
          // Register all sensors to gw (they will be created as child devices)
          present(i, S_BINARY);
        }
      }
    }
     
     
    // MySensors - Handling incoming messages
    // Nodes that expects incoming data, such as an actuator or repeating nodes,
    // must implement the receive() - function to handle the incoming messages.
    // Do not sleep a node where you expect incoming data or you will lose messages.
    void receive(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.type == V_STATUS) {
        uint8_t isTurnedOn = message.getBool(); // 1 - true, 0 - false
        uint8_t newState = isTurnedOn ? myRelayButtons[message.sensor].relayTrigger : ! myRelayButtons[message.sensor].relayTrigger;
        // Change relay state
        digitalWrite(myRelayButtons[message.sensor].relay, newState);
        // Store state in eeprom if changed
        if (loadRelayState(message.sensor) != isTurnedOn) {
          saveRelayState(message.sensor, isTurnedOn);
        }
        send(msgs[message.sensor].set(isTurnedOn)); // support for OPTIMISTIC=FALSE (Home Asistant)
      }
    }
     
    uint8_t loadRelayState(int relayNum) {
      return(loadState(RELAY_STATE_STORAGE + relayNum));
    }
     
    void saveRelayState(int relayNum, uint8_t state) {
      saveState(RELAY_STATE_STORAGE + relayNum, state);
    }
    

    please help.


 

294
Online

7.8k
Users

8.7k
Topics

93.0k
Posts