//This project utilizes Wokwi, Adafruit,IFTTT, and Blynk to create a smart door locking
//system.The Mpu6050 module senses movement of the door, if the door is open 
//(moved from its ideal position) for more than a period of time (in this code 10s) 
//you will get an sms that the door is open , then you can close the door using a web
//switch from Blynk.

#include<ESP32Servo.h>
#include <MPU6050.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
                    
#define BLYNK_AUTH_TOKEN "L1ikQ3ddsV59FI7eFdP9vQEVRTkXVUYi"   //template name in blynk console
#define BLYNK_TEMPLATE_ID "TMPL3faGPeHkh"                     //your BLYNK template ID
#define BLYNK_TEMPLATE_NAME "lockie"                          //your BLYNK template name

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <Wire.h>

WiFiClient client;

char auth[] = BLYNK_AUTH_TOKEN;

char ssid[] = "Wokwi-GUEST";
char pass[] = "";

#define VIRTUAL_BUTTON_PIN V0

#define AIO_SERVER    "io.adafruit.com"                    
#define AIO_SERVERPORT  1883                              
#define AIO_USERNAME  "anonymous0"                           //your AIO Username
#define AIO_KEY       "aio_TKgt81wVxBDxc6rdkk2sJraV5YX9"     //your AIO KEY

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
//setting up MQTT publish to send data to required feed in adafruit
Adafruit_MQTT_Publish Lockk = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Lockk");   // Instead of Lockk enter your feed Name
//change your feed name here

MPU6050 mpu;
Servo s;
int i=0;

#define DOOR_OPEN_THRESHOLD 12000
#define DOOR_OPEN_TIMEOUT_MS 10000 // 10 seconds in milliseconds
unsigned long doorOpenStartTime = 0;
bool doorIsOpen = false;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  s.attach(17);
  Blynk.begin(auth, ssid, pass);
  Wire.begin(21, 22);  // Specify SDA and SCL pins
  mpu.initialize();
  Serial.println("Testing MPU6050 connections...");
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  delay(1000);
  
}

BLYNK_WRITE(VIRTUAL_BUTTON_PIN) {
  int buttonValue = param.asInt();

  if (buttonValue == 1) {
    s.write(0); 
  } else {
    s.write(90); 
  }
}

void connect() {// to connect to adafruit
  Serial.print(F("Connecting to Adafruit IO... "));
  int8_t ret;
  while ((ret = mqtt.connect()) != 0) {
    switch (ret) {
      case 1: Serial.println(F("Wrong protocol")); break;
      case 2: Serial.println(F("ID rejected")); break;
      case 3: Serial.println(F("Server unavail")); break;
      case 4: Serial.println(F("Bad user/pass")); break;
      case 5: Serial.println(F("Not authed")); break;
      case 6: Serial.println(F("Failed to subscribe")); break;
      default: Serial.println(F("Connection failed")); break;
    }

    if(ret >= 0)
      mqtt.disconnect();

    Serial.println(F("Retrying connection..."));
    delay(10000);
  }
  Serial.println(F("Adafruit IO Connected!"));
}

void accel(){
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  // Print the values
  Serial.print("Accel: ");
  Serial.print(ax);
  Serial.print("\n");
  delay(100);

  if (abs(ax) > 12000) {
    doorIsOpen = true;
    doorOpenStartTime = millis();  // Start timer when door opens
  } 
  if (doorIsOpen) {
    unsigned long elapsedTime = millis() - doorOpenStartTime;
    if (elapsedTime >= DOOR_OPEN_TIMEOUT_MS) {
      Serial.print("Door open for more than 10 seconds, sending SMS\n");
      doorIsOpen = false; // Reset door state
    }
  }

  if(!Lockk.publish(static_cast<int32_t>(ax))) {  //function to send data to adafruit                   //Publish to Adafruit
      Serial.println(F("Failed"));
    }else {
      Serial.println(F("Sent!"));
    }
  
  delay(10);
}


void loop() {
  if(! mqtt.ping(3)) {
    // reconnect to adafruit io
    if(! mqtt.connected())
      connect();
  }

  Blynk.run();
  if(i<100){
    accel();
  }
  i++;
}