#include <LiquidCrystal_I2C.h>
#include <IRrecv.h>

// Define pin numbers for relays and buttons
#define RELAY_PIN_1 19
#define RELAY_PIN_2 18
#define RELAY_PIN_3 16
#define RELAY_PIN_4 15
#define BUTTON_PIN_1 2
#define BUTTON_PIN_2 17
#define BUTTON_PIN_3 4
#define BUTTON_PIN_4 5

// Define the pin for IR receiver
int IR_RECEIVE_PIN = 14;
IRrecv irrecv(IR_RECEIVE_PIN);

// Initialize LCD display
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Structure to hold decoded IR signals
decode_results results;

// State variables for each LED
bool ledState1 = false;
bool ledState2 = false;
bool ledState3 = false;
bool ledState4 = false;

// Setup function runs once when the device starts
void setup() {
  // Initialize serial communication
  Serial.begin(115200);
  Serial.println("IR Receive test");

  // Enable the IR receiver
  irrecv.enableIRIn();
  Serial.println("Enable IRin");

  // Initialize the LCD display
  lcd.init(); 
  lcd.backlight(); 

  // Set relay pins as outputs
  pinMode(RELAY_PIN_1, OUTPUT);
  pinMode(RELAY_PIN_2, OUTPUT);
  pinMode(RELAY_PIN_3, OUTPUT);
  pinMode(RELAY_PIN_4, OUTPUT);

  // Set button pins as inputs with pull-up resistors
  pinMode(BUTTON_PIN_1, INPUT_PULLUP);
  pinMode(BUTTON_PIN_2, INPUT_PULLUP);
  pinMode(BUTTON_PIN_3, INPUT_PULLUP);
  pinMode(BUTTON_PIN_4, INPUT_PULLUP);
}

// Function to process IR button press
void processIRButton(unsigned long buttonValue, int relayPin, bool &ledState, int lcdRow) {
  // Toggle LED state
  ledState = !ledState;

  // Set the relay state based on the LED state
  digitalWrite(relayPin, ledState ? HIGH : LOW);

  // Update LCD display with the current state
  lcd.setCursor(10, lcdRow);
  lcd.print(ledState ? "ON " : "OFF");
}

// Function to process physical button press
void processPushButton(int buttonPin, bool &ledState, int relayPin, int lcdRow) {
  // Check if the button is pressed
  if (digitalRead(buttonPin) == LOW) {  // Change from LOW to HIGH (button pressed)
    // Toggle LED state
    ledState = !ledState;

    // Set the relay state based on the LED state
    digitalWrite(relayPin, ledState ? HIGH : LOW);

    // Update LCD display with the current state
    lcd.setCursor(10, lcdRow);
    lcd.print(ledState ? "ON " : "OFF");

    // Add a small delay to debounce the button
    delay(250);
  }
}

// Main loop function that runs continuously
void loop() {
  // Display status on LCD
  lcd.setCursor(5, 0);
  lcd.print("LED1 ");
  lcd.setCursor(5, 1);
  lcd.print("LED2 ");
  lcd.setCursor(5, 2);
  lcd.print("LED3 ");
  lcd.setCursor(5, 3);
  lcd.print("LED4 ");

  // Process IR remote signals
  if (irrecv.decode(&results)) {
    // Print the decoded IR value to the serial monitor
    Serial.println(results.value, HEX);

    // Match the IR value and perform corresponding actions
    switch (results.value) {
      case 0xFF0CF3: processIRButton(results.value, RELAY_PIN_1, ledState1, 0); break; // NUM 1 BUTTON
      case 0xFF18E7: processIRButton(results.value, RELAY_PIN_2, ledState2, 1); break; // NUM 2 BUTTON
      case 0xFF5EA1: processIRButton(results.value, RELAY_PIN_3, ledState3, 2); break; // NUM 3 BUTTON
      case 0xFF08F7: processIRButton(results.value, RELAY_PIN_4, ledState4, 3); break; // NUM 4 BUTTON
      case 0xFF16E9: // NUM 0 BUTTON
        // Turn off all LEDs
        ledState1 = ledState2 = ledState3 = ledState4 = false;
        digitalWrite(RELAY_PIN_1, LOW);
        digitalWrite(RELAY_PIN_2, LOW);
        digitalWrite(RELAY_PIN_3, LOW);
        digitalWrite(RELAY_PIN_4, LOW);

        // Update LCD display for all LEDs
        for (int i = 0; i < 4; i++) {
          lcd.setCursor(10, i);
          lcd.print("OFF");
        }
        break;
      case 0xFF38C7: // TEST BUTTON
        // Toggle the state of all LEDs
        ledState1 = ledState2 = ledState3 = ledState4 = !ledState1;

        // Set relay states based on the LED states
        digitalWrite(RELAY_PIN_1, ledState1 ? HIGH : LOW);
        digitalWrite(RELAY_PIN_2, ledState2 ? HIGH : LOW);
        digitalWrite(RELAY_PIN_3, ledState3 ? HIGH : LOW);
        digitalWrite(RELAY_PIN_4, ledState4 ? HIGH : LOW);
        lcd.clear();
        lcd.setCursor(7,2);
        lcd.print("TESTING");
        lcd.setCursor(8,3);
        lcd.print("MDOE");

        // Update LCD display for all LEDs
        for (int i = 0; i < 4; i++) {
          lcd.setCursor(10, i);
          lcd.print(ledState1 ? "ON " : "OFF");
        }
        break;
    }

    // Resume IR receiver to receive the next signal
    irrecv.resume();
  }

  // Process push button signals
  processPushButton(BUTTON_PIN_1, ledState1, RELAY_PIN_1, 0);
  processPushButton(BUTTON_PIN_2, ledState2, RELAY_PIN_2, 1);
  processPushButton(BUTTON_PIN_3, ledState3, RELAY_PIN_3, 2);
  processPushButton(BUTTON_PIN_4, ledState4, RELAY_PIN_4, 3);
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module