#include <EEPROM.h>

#define RELAY1_PIN 12  //0  // ATtiny84 Pin PA0
#define RELAY2_PIN 13  //1  // ATtiny84 Pin PA1
#define RELAY3_PIN 2   // ATtiny84 Pin PA2
#define RELAY4_PIN 3   // ATtiny84 Pin PA3
#define RELAY5_PIN 4   // ATtiny84 Pin PA4

#define BUTTON1 10
#define BUTTON2 9
#define BUTTON3 8
#define BUTTON4 7
#define BUTTON5 6

#define LEARN_LED_PIN 5           // ATtiny84 Pin PA5

unsigned long debounce_delay = 50;
unsigned long last_debounce_time = 0;

bool button1_state = HIGH;
bool button2_state = HIGH;
bool button3_state = HIGH;
bool button4_state = HIGH;
bool button5_state = HIGH;

bool last_button1_state = HIGH;
bool last_button2_state = HIGH;
bool last_button3_state = HIGH;
bool last_button4_state = HIGH;
bool last_button5_state = HIGH;

bool button1_handled = false;
bool button2_handled = false;
bool button3_handled = false;
bool button4_handled = false;
bool button5_handled = false;

bool both_button_pressed = false;
bool button1_pressed = false;
bool button2_pressed = false;
bool button3_pressed = false;
bool button4_pressed = false;
bool button5_pressed = false;

bool learn_mode_enable = false;
bool relay1_status = false;
bool relay2_status = false;
bool relay3_status = false;
bool relay4_status = false;
bool relay5_status = false;

bool led_state = false;
int program_slot = 0;

void setup() {
  Serial.begin(115200);

  pinMode(BUTTON1, INPUT_PULLUP);
  pinMode(BUTTON2, INPUT_PULLUP);
  pinMode(BUTTON3, INPUT_PULLUP);
  pinMode(BUTTON4, INPUT_PULLUP);
  pinMode(BUTTON5, INPUT_PULLUP);

  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  pinMode(RELAY3_PIN, OUTPUT);
  pinMode(RELAY4_PIN, OUTPUT);
  pinMode(RELAY5_PIN, OUTPUT);

  pinMode(LEARN_LED_PIN, OUTPUT);
}

void loop() {
  handleButtons();
  if (learn_mode_enable) {
    blinkLearnLED();
    if (program_slot == 0) {
      if (button1_pressed) {
        program_slot = 1;
        Serial.println("Slot 1 is selected!");
        button1_pressed = false;
      } else if (button2_pressed) {
        program_slot = 2;
        Serial.println("Slot 2 is selected!");
        button2_pressed = false;
      } else if (button3_pressed) {
        program_slot = 3;
        Serial.println("Slot 3 is selected!");
        button3_pressed = false;
      } else if (button4_pressed) {
        program_slot = 4;
        Serial.println("Slot 4 is selected!");
        button4_pressed = false;
      } else if (button5_pressed) {
        program_slot = 5;
        Serial.println("Slot 5 is selected!");
        button5_pressed = false;
      }
    } else {
      if (both_button_pressed) {
        if (program_slot != 0) {
          saveRelayChanges(program_slot);
          Serial.println("Slot configuration is saved!");
        }
        program_slot = 0;
        learn_mode_enable = false;

        relay1_status = false;
        relay2_status = false;
        relay3_status = false;
        relay4_status = false;
        relay5_status = false;

        digitalWrite(LEARN_LED_PIN, LOW);
        both_button_pressed = false;
      }

      if (button1_pressed) {
        relay1_status = changeRelayState(RELAY1_PIN);
        button1_pressed = false;
      } else if (button2_pressed) {
        relay2_status = changeRelayState(RELAY2_PIN);
        button2_pressed = false;
      } else if (button3_pressed) {
        relay3_status = changeRelayState(RELAY3_PIN);
        button3_pressed = false;
      } else if (button4_pressed) {
        relay4_status = changeRelayState(RELAY4_PIN);
        button4_pressed = false;
      } else if (button5_pressed) {
        relay5_status = changeRelayState(RELAY5_PIN);
        button5_pressed = false;
      }
    }
    if (both_button_pressed) {
      turnOffAll();
      digitalWrite(LEARN_LED_PIN, LOW);
      learn_mode_enable = false;
      both_button_pressed = false;
      Serial.println("learn mode off");
    }
  } else {
    if (both_button_pressed) {
      turnOffAll();
      learn_mode_enable = true;
      both_button_pressed = false;
      Serial.println("learn mode on");
    }

    if (button1_pressed) {
      loadRelayChanges(1);
      Serial.println("Configures loaded for slot 1");
      button1_pressed = false;
    } else if (button2_pressed) {
      loadRelayChanges(2);
      Serial.println("Configures loaded for slot 2");
      button2_pressed = false;
    } else if (button3_pressed) {
      loadRelayChanges(3);
      Serial.println("Configures loaded for slot 3");
      button3_pressed = false;
    } else if (button4_pressed) {
      loadRelayChanges(4);
      Serial.println("Configures loaded for slot 4");
      button4_pressed = false;
    } else if (button5_pressed) {
      loadRelayChanges(5);
      Serial.println("Configures loaded for slot 5");
      button5_pressed = false;
    }
  }
}


void handleButtons() {
  // Read the current state of the buttons
  int current_button1_state = digitalRead(BUTTON1);
  int current_button2_state = digitalRead(BUTTON2);
  int current_button3_state = digitalRead(BUTTON3);
  int current_button4_state = digitalRead(BUTTON4);
  int current_button5_state = digitalRead(BUTTON5);

  // If any button state has changed, reset the debounce timer
  if (current_button1_state != last_button1_state ||
      current_button2_state != last_button2_state ||
      current_button3_state != last_button3_state ||
      current_button4_state != last_button4_state ||
      current_button5_state != last_button5_state) {
    last_debounce_time = millis();
  }

  // If the debounce time has passed, read the button states
  if ((millis() - last_debounce_time) > debounce_delay) {
    // Check if the button states have stabilized and if they have changed
    if (current_button1_state != button1_state) {
      button1_state = current_button1_state;
      button1_handled = false; // Reset handling flag for button1
    }
    if (current_button2_state != button2_state) {
      button2_state = current_button2_state;
      button2_handled = false; // Reset handling flag for button2
    }
    if (current_button3_state != button3_state) {
      button3_state = current_button3_state;
      button3_handled = false; // Reset handling flag for button3
    }
    if (current_button4_state != button4_state) {
      button4_state = current_button4_state;
      button4_handled = false; // Reset handling flag for button4
    }
    if (current_button5_state != button5_state) {
      button5_state = current_button5_state;
      button5_handled = false; // Reset handling flag for button5
    }

    // Handle button logic only after debouncing is done
    if (button1_state == LOW && button3_state == LOW && !button1_handled && !button3_handled) {
      Serial.println("Both press");
      both_button_pressed = true;
      button1_handled = true; // Mark as handled to prevent multiple prints
      button3_handled = true;
    } else {
      if (button1_state == LOW && !button1_handled) {
        Serial.println("button 1");
        button1_pressed = true;
        button1_handled = true; // Mark as handled
      }
      if (button2_state == LOW && !button2_handled) {
        Serial.println("button 2");
        button2_pressed = true;
        button2_handled = true; // Mark as handled
      }
      if (button3_state == LOW && !button3_handled) {
        Serial.println("button 3");
        button3_pressed = true;
        button3_handled = true; // Mark as handled
      }
      if (button4_state == LOW && !button4_handled) {
        Serial.println("button 4");
        button4_pressed = true;
        button4_handled = true; // Mark as handled
      }
      if (button5_state == LOW && !button5_handled) {
        Serial.println("button 5");
        button5_pressed = true;
        button5_handled = true; // Mark as handled
      }
    }
  }

  // Save the last button states
  last_button1_state = current_button1_state;
  last_button2_state = current_button2_state;
  last_button3_state = current_button3_state;
  last_button4_state = current_button4_state;
  last_button5_state = current_button5_state;
}


// change the relay state
bool changeRelayState(int relay_pin) {
  bool status = digitalRead(relay_pin);
  status = !status;
  digitalWrite(relay_pin, status);
  return status;
}

// save the relays configuration
void saveRelayChanges(int slot) {
  // transfer the 5 relays status on a byte variable to write once.
  byte relayStates = 0;
  relayStates |= relay1_status << 0;
  relayStates |= relay2_status << 1;
  relayStates |= relay3_status << 2;
  relayStates |= relay4_status << 3;
  relayStates |= relay5_status << 4;

  EEPROM.update(slot, relayStates);
}

// load the last relays configuration
void loadRelayChanges(int slot) {
  // read the 5 relays status on a byte variable from EEPROM
  byte relayStates = EEPROM.read(slot);

  digitalWrite(RELAY1_PIN, relayStates & (1 << 0));
  digitalWrite(RELAY2_PIN, relayStates & (1 << 1));
  digitalWrite(RELAY3_PIN, relayStates & (1 << 2));
  digitalWrite(RELAY4_PIN, relayStates & (1 << 3));
  digitalWrite(RELAY5_PIN, relayStates & (1 << 4));

  Serial.print("Relay 1: ");
  Serial.println((relayStates & (1 << 0)) ? "ON" : "OFF");

  Serial.print("Relay 2: ");
  Serial.println((relayStates & (1 << 1)) ? "ON" : "OFF");

  Serial.print("Relay 3: ");
  Serial.println((relayStates & (1 << 2)) ? "ON" : "OFF");

  Serial.print("Relay 4: ");
  Serial.println((relayStates & (1 << 3)) ? "ON" : "OFF");

  Serial.print("Relay 5: ");
  Serial.println((relayStates & (1 << 4)) ? "ON" : "OFF");
}

void turnOffAll() {
  digitalWrite(RELAY1_PIN, 0);
  digitalWrite(RELAY2_PIN, 0);
  digitalWrite(RELAY3_PIN, 0);
  digitalWrite(RELAY4_PIN, 0);
  digitalWrite(RELAY5_PIN, 0);
}


unsigned long led_blink_time = 0;
void blinkLearnLED() {
  if (millis() - led_blink_time > 500) {
    led_state = !led_state;
    digitalWrite(LEARN_LED_PIN, led_state);
    led_blink_time = millis();
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
Button 1
Button 2
Button 3
Button 4
Button 5
Relay 1
Relay 2
Relay 3
Relay 4
Relay 5
Button 1 & Button 3
Button 1 Connector Switch
Button 2 Connector Switch
Learn LED