/*********

  [*** RFID based automated entry on booking ***]

*********/


#include <LiquidCrystal_I2C.h>
// #include <soundTracks.h>  // Sound to be played with instructions

#include <Stepper.h>
const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution for your motor
// initialize the stepper library on pins:
Stepper myStepper(stepsPerRevolution, 26, 25, 32, 33);

// ESP32 pin D4 connected to servo motor (via rotateServo1 fun)
// #include <Servo.h>
// #define SERVO_PIN 4
// Servo servoMotor;

// ESP32 connected to servo motor (via openDoor, closeDoor methods)
#include "esp32-hal-ledc.h"
#define COUNT_LOW 0
#define COUNT_HIGH 4800
#define TIMER_WIDTH 16

// Indicator LEDs
const int ledPinRed = 12;
const int ledPinGreen = 13;

// set the LCD number of columns and rows
const int lcdColumns = 16;
const int lcdRows = 2;
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  // set LCD address, number of columns and rows

// Ultra Sonic Sensor Pin
const int trigPin = 5;
const int echoPin = 18;

//define sound speed in cm/uS
#define SOUND_SPEED 0.034

long duration;
int distanceCm;
bool isDoorOpened = false;



void setup() {
  // Stepper Motor
  myStepper.setSpeed(10);   // set the speed at 60 rpm:
  Serial.begin(9600);   // initialize the serial port:

  // Attaches the servo on ESP32 pin (via rotateServo1 fun)
  // servoMotor.attach(SERVO_PIN);  

  // Attaches the servo on ESP32 pin (via openDoor, closeDoor methods)
  ledcSetup(1, 50, TIMER_WIDTH); // channel 1, 50 Hz, 16-bit width
  ledcAttachPin(4, 1);   // GPIO 22 assigned to channel 1
  
  // LED Setup
  pinMode (ledPinRed, OUTPUT);
  pinMode (ledPinGreen, OUTPUT);

  // initialize LCD
  lcd.init();                     
  lcd.backlight();  // turn on LCD backlight 

  // Ultra Sonic Sensor 
  Serial.begin(115200); // Starts the serial communication
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
}




void loop() {
  // Ultra Sonic Sensor
  digitalWrite(trigPin, LOW); // Clears the trigPin
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH); // Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW); // Clears the trigPin
  
  // Reads Ultrasonic (our case: RFID reader)
  duration = pulseIn(echoPin, HIGH);
  distanceCm = (int) duration * SOUND_SPEED/2; // Calculate the distance

  // Print on console
  Serial.print("Distance (cm): ");
  Serial.println(distanceCm);
  
  // Display on LCD 
  lcd.clear();
  disp((String)distanceCm, 0);
  disp("Scan Card      ", 1);


  // RFID Card Detected.
  if(distanceCm >= 200) {
    // Toggle LEDs
    digitalWrite (ledPinRed, HIGH);
    digitalWrite (ledPinGreen, LOW);
    
    // Open and close door once.
    if (!isDoorOpened) {
      isDoorOpened = true;

      // Fetch booking details from server
      disp("Fetching details", 1);
      delay(2000);

      // if details are valid (There is an active booking).
      if(true) {
        disp("OK! Opening ... ", 1);
        myStepper.step(50); //clockwise stepper
        openDoor();
        disp("Opened for 5 sec", 1);
        Serial.println("Opened for 5 sec.");
        delay(5000);

        disp("Closing door ... ", 1);
        myStepper.step(-stepsPerRevolution/4); //anti clockwise stepper
        closeDoor();
        disp("Door is closed.  ", 1);
        Serial.println("Door is closed.");
      }
    }
  }

  else {
    isDoorOpened = false;
    digitalWrite (ledPinGreen,HIGH);
    digitalWrite (ledPinRed,LOW);
  }

  delay(1000);
}


void disp(String value, int curRow){
  lcd.setCursor(0, curRow);    // set cursor to first column, given curRow
  lcd.print(value);     // print message
  // delay(1000);
  // lcd.clear(); 
}


void openDoor() {
  Serial.print("Opening Door ....\n");
  for (int i= 4800; i > 0; i=i-10) {
    ledcWrite(1, i);       // sweep servo 1
    delay(10);
  }
}


void closeDoor() {
  Serial.print("Closing Door ....\n");
  for(int i=0 ; i < 4800 ; i=i+10) {
    ledcWrite(1, i);       // sweep servo 1
    delay(5);
  }
}






/*
void scrollText(int row, String message, int delayTime, int lcdColumns) {
  for (int i=0; i < lcdColumns; i++) {
    message = " " + message; 
  } 
  message = message + " "; 
  for (int pos = 0; pos < message.length(); pos++) {
    lcd.setCursor(0, row);
    lcd.print(message.substring(pos, pos + lcdColumns));
    delay(delayTime);
  }
}
*/



// void rotateServo(bool isOpen) {
//   // rotates from 0 degrees to 180 degrees
//   if (isOpen) {
//     for (int pos = 90; pos <= 180; pos += 1) {
//       // in steps of 1 degree
//       servoMotor.write(pos);
//       delay(10); // waits 15ms to reach the position

//     }
//   }
//   else {
//     // rotates from 180 degrees to 0 degrees
//     for (int pos = 180; pos >= 90; pos -= 1) {
//       servoMotor.write(pos);
//       delay(50)); // waits 15ms to reach the position
//     }
//   }
// }



//-----------------------------------------------------//
/////////************* END OF CODE *************/////////
//_____________________________________________________//






/*
#include <Stepper.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution

// ULN2003 Motor Driver Pins
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17

// initialize the stepper library

Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);

void setup() {
  // set the speed at 5 rpm
  myStepper.setSpeed(5);
  // initialize the serial port
  Serial.begin(115200);
}

void loop() {
  // step one revolution in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  delay(1000);

  // step one revolution in the other direction:
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  delay(1000);
}

*/




/*
// Include the AccelStepper Library
#include <AccelStepper.h>

// Define pin connections
const int dirPin = 2;
const int stepPin = 4;

// Define motor interface type
#define motorInterfaceType 1

// Creates an instance
AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
	// set the maximum speed, acceleration factor,
	// initial speed and the target position
	myStepper.setMaxSpeed(1000);
	myStepper.setAcceleration(50);
	myStepper.setSpeed(200);

	myStepper.moveTo(200);
}

void loop() {
	// Change direction once the motor reaches target position
	if (myStepper.distanceToGo() == 0) 
		myStepper.moveTo(-myStepper.currentPosition());

	// Move the motor one step
	myStepper.run();
}*/





/*
// Define pin connections & motor's steps per revolution
const int dirPin = 2;
const int stepPin = 4;
const int stepsPerRevolution = 2000;

void setup()
{
	// Declare pins as Outputs
	pinMode(stepPin, OUTPUT);
	pinMode(dirPin, OUTPUT);
}
void loop()
{
	// Set motor direction clockwise
	digitalWrite(dirPin, HIGH);

	// Spin motor slowly
	for(int x = 0; x < stepsPerRevolution; x++)
	{
		digitalWrite(stepPin, HIGH);
		delayMicroseconds(3000);
		digitalWrite(stepPin, LOW);
		delayMicroseconds(3000);
  }
	delay(1000); // Wait a second
	
	// Set motor direction counterclockwise
	digitalWrite(dirPin, LOW);

	// Spin motor quickly
	for(int x = 0; x < stepsPerRevolution; x++)
	{
		digitalWrite(stepPin, HIGH);
		delayMicroseconds(1000);
		digitalWrite(stepPin, LOW);
		delayMicroseconds(1000);
	}
	delay(1000); // Wait a second
}

*/







/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

/*#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  

void setup(){
  // initialize LCD
  lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
}

void loop(){
  // set cursor to first column, first row
  lcd.setCursor(0, 0);
  // print message
  lcd.print("Hello, World!");
  delay(1000);
  // clears the display to print new message
  lcd.clear();
  // set cursor to first column, second row
  lcd.setCursor(0,1);
  lcd.print("Hello, World!");
  delay(1000);
  lcd.clear(); 
}

*/































/* #include <Wire.h>
 
void setup() {
  Wire.begin();
  Serial.begin(115200);
  Serial.println("\nI2C Scanner");
}
 
void loop() {
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
      nDevices++;
    }
    else if (error==4) {
      Serial.print("Unknow error at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  }
  else {
    Serial.println("done\n");
  }
  delay(5000);          
} */