#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
// PIR sensor
const int pirPin = 2;
// Buzzer
const int buzzerPin = 6;
// GSM module
SoftwareSerial gsmSerial(12, 13);  // RX, TX
const int relay1Pin = 4;
const int relay2Pin = 5;
bool calling = false;
bool sended = false;
String text = "Intruder allert";  // type message to be sent
String phone = "+639501415816";   // receiver's number
// Button
const int buttonPin = 3;
// LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Flag to indicate system activation
volatile bool systemActivated = true;
void setup() {
  Serial.begin(115200);
  Serial.println("start");
  gsmSerial.begin(9600);
  pinMode(pirPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(relay1Pin, OUTPUT);
  digitalWrite(relay1Pin, 1);
  pinMode(relay2Pin, OUTPUT);
  digitalWrite(relay2Pin, 1);
  pinMode(buttonPin, INPUT_PULLUP);
  lcd.backlight();
  lcd.init();
  lcd.setCursor(0, 0);
  lcd.print("Home Security");
  lcd.setCursor(0, 1);
  lcd.print("System Ready");
  sendATCommand("AT");  // Check if the module is responding
  delay(2000);
  attachInterrupt(digitalPinToInterrupt(buttonPin), toggleSystem, FALLING);
  delay(1000);
  Serial.print("ready...");
  gsmSerial.print("AT+CMGF=1\r");
  delay(1000);
  gsmSerial.print("AT+CNMI=2,2,0,0,0\r");
  delay(1000);
  Serial.println("start");
}
void loop() {
  if (systemActivated) {
    int pirValue = digitalRead(pirPin);
    if (pirValue) {
      Serial.println("Intruder alert!");
      lcd.setCursor(0, 0);
      lcd.print("Intruder Alert!");
      lcd.setCursor(0, 1);
      lcd.print("Sending Alert...");
      digitalWrite(relay1Pin, 0);
      digitalWrite(relay2Pin, 0);
      digitalWrite(buzzerPin, 1);
      //do call and txt 1 time until reset
      if (!calling) {
        makeCall();
      }
      while (!sended) {
        Send(text, phone);
        if (sended) {
          return;
        }
      }
    } else {
      sended = false;
      calling = false;
      lcd.setCursor(0, 0);
      lcd.print("Home Security   ");
      lcd.setCursor(0, 1);
      lcd.print("System Ready    ");
    }
  } else {
    Serial.println("System Deactivated");
    digitalWrite(buzzerPin, 0);
    digitalWrite(relay1Pin, 1);
    digitalWrite(relay2Pin, 1);
    sended = false;
    calling = false;
    lcd.setCursor(0, 0);
    lcd.print("Home Security   ");
    lcd.setCursor(0, 1);
    lcd.print("System Inactive ");
  }
}
//dont do other function or calculation unless volatile
void toggleSystem() {
  systemActivated = !systemActivated;
}
void button() {
  // Read the state of the button
  int buttonState = digitalRead(buttonPin);
  // Check if the button is pressed
  if (buttonState == HIGH) {
    Serial.println("Button Clicked!");
    digitalWrite(relay1Pin, 1);
    digitalWrite(relay2Pin, 1);
    delay(1000);  // Add a small delay to debounce the button
  }
}
void Send(String text, String phone) {
  static word startTimer, waitTimer;  // waitTimer > 0 causes the timer to run, good up to 65 second intervals
  static byte procState;
  if (waitTimer > 0) {
    if (word(millis()) - startTimer < waitTimer) return;  // time is not up yet
    else waitTimer = 0;                                   // and on to the switch-case
  }
  switch (procState) {
    case 0:
      gsmSerial.println("AT+CMGF=1");  // Set SMS Text Mode
      procState = 1;                   //  run case 1 next time
      waitTimer = 1000;
      startTimer = millis();
      Serial.println("set gms to send mode");
      break;
    case 1:
      gsmSerial.println("AT+CSCS=\"GSM\"");  //
      procState = 2;                         //  run case 2 next time
      waitTimer = 2000;
      startTimer = millis();
      Serial.println("AT command for send txt");
      break;
    case 2:
      gsmSerial.println("AT+CMGS=\"" + phone + "\"");  // send to desired phone
      procState = 3;                                   //  run case 3 next time
      waitTimer = 2000;
      startTimer = millis();
      Serial.println("AT command for receiver number");
      break;
    case 3:
      gsmSerial.print("\"" + text + "\"");  // containing desired text
      procState = 4;                        //  run case 4 next time
      waitTimer = 2000;
      startTimer = millis();
      Serial.println("AT command for message contain");
      break;
    case 4:
      gsmSerial.print((char)26);  // signals end of text message
      procState = 5;              //  run case 0 next time
      waitTimer = 2000;
      startTimer = millis();
      Serial.println("sent");
      //text = "";
      delay(2000);
      break;
    case 5:
      procState = 0;     // Increment procState to move to the next case
      waitTimer = 2000;  // Adjust the wait time for the call to last longer
      startTimer = millis();
      gsmSerial.println("AT+CMGD=1,4");
      sended = true;
      break;
  }
}
void makeCall() {
  delay(1000);
  Serial.println("Making a call...");
  sendATCommand("ATD+639501415816;");  // Replace with the owner's phone number
  delay(20000);                        // Call for 5 seconds
  sendATCommand("ATH");                // Hang up the call
  delay(1000);
  calling = true;
}
void sendATCommand(const char* command) {
  Serial.print("Sending AT command: ");
  Serial.println(command);
  gsmSerial.println(command);
  delay(500);
  while (gsmSerial.available()) {
    char c = gsmSerial.read();
    Serial.print(c);
  }
  Serial.println();
}