/*
   File        : tirai otomatis with esp32.ino
   Author      : leveletech.com / wa 081214584114
   Date        : 2024 04 18
   Description : program untuk kontrol tirai dan lampu otomatis / manual remote blynk
*/

//--------------------------------- Include Libraries-----------------------------------------------
//--------------------------------- Include Libraries-----------------------------------------------

//--------------------------------- Hardware Setting------------------------------------------------
#define BLYNK_TEMPLATE_ID "TMPL6Q-kFc8DB"
#define BLYNK_TEMPLATE_NAME "Tirai Otomatis"
#define BLYNK_AUTH_TOKEN "AEKMu7yN1dsZkcaErkQVRacEPfMQRjVT"
#define BLYNK_PRINT Serial

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

char auth[] = BLYNK_AUTH_TOKEN ; //Auth Token

char ssid[] = "Wokwi-GUEST"; //nama hotspot yang digunakan
char pass[] = ""; //password hotspot yang digunakan


int value0, value1, value2, value3, value6;
//--------------------------------- Hardware Setting------------------------------------------------

//--------------------------------- Define and Constant---------------------------------------------
//motor Pin
const int motor1Pin1 = 25;  //IN 1
const int motor1Pin2 = 33;  //IN 2
const int enable1Pin = 32;  //ENABLE A
const int relay1 = 26;      //relay lampu
const int ldrPin = 35;      // Pin for LDR
const int LS_fullOpen = 14;      //
const int LS_fullClose = 12;      //

// Setting PWM properties
const int freq = 30000;
const int pwmChannel = 0;
const int resolution = 8;

// LDR Characteristics
const float GAMMA = 0.7;
const float RL10 = 50;

//--------------------------------- Define and Constant---------------------------------------------

//--------------------------------- User Define Data Type-------------------------------------------
struct timer_data {
  bool IN;
  bool Q;
  bool BP1; //button pressed
  bool BP2; //button pressed
  int PT;  //preset time
  int ET;  //elapsed time
  unsigned long TN;//time now
};
//--------------------------------- User Define Data Type-------------------------------------------

//----------------------------------Global Variable-------------------------------------------------
//control setting
float LowLux = 200.0;   //close tirai hidupkan lampu
float HighLux = 600.0;  //open tirai matikan lampu
bool S[8] = { false, false, false, false, false, false, false, false };
bool S_P[8] = { false, false, false, false, false, false, false, false };
/* S map
  S[0] = Limit Switch Full Open
  S[1] = Limit Switch Full Close
*/
bool B[8] = {false, false, false, false, false, false, false, false};
/* B map
  B[0] = auto / manual, false = auto, true = manual
  B[1] = manual start lampu
  B[2] = manual buka tirai
  B[3] = manual tutup tirai
  B[4] = manual stop
*/
bool R[8] = { false, false, false, false, false, false, false, false };
/* R map
  R[0] = Relay Output
  R[1] =
  R[2] =
  R[3] =
  R[4] =
*/

bool B_F[8] = {false, false, false, false, false, false, false, false};
/* B_F map
  B_F [0] = Auto / Manual Flag
  B_F [1] =
  B_F [2] =
  B_F [3] =
  B_F [4] =
*/
// Setting PWM properties
int dutyCycle = 0;
float LuxValue;
timer_data T[8]; //TON
//----------------------------------Global Variable-------------------------------------------------

//----------------------------------User Defined Function Stage 1-----------------------------------
void TON(timer_data & Var) {       //Timer On delay function
  if (Var.IN)
  {
    if (!Var.BP1)
    {
      Var.TN = millis();
      Var.BP1 = true;
    }
    if (!Var.Q)
    {
      Var.ET = (millis() - Var.TN);
      if (Var.ET  >= Var.PT) Var.Q = true;
    }

  } else
  {
    Var.Q = false;
    Var.BP1 = false;
    Var.ET = 0;
  }
}

void open_tirai() {
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, HIGH);
  ledcWrite(pwmChannel, 200);
}
void close_tirai() {
  digitalWrite(motor1Pin1, HIGH);
  digitalWrite(motor1Pin2, LOW);
  ledcWrite(pwmChannel, 200);
}
void stop() {
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, LOW);
  ledcWrite(pwmChannel, 0);
}
void Input_Update() {
  //update digital
  S[0] = digitalRead(LS_fullOpen);
  S[1] = digitalRead(LS_fullClose);
  //update analog
  int analogValue = analogRead(ldrPin);
  delay(200);
  //Serial.println(analogValue);
  analogValue = map(analogValue, 4095, 0, 1024, 0); //mengubah nilai pembacaan sensor LDR dari nilai ADC arduino menjadi nilai ADC ESP32
  float voltage = analogValue / 1024. * 5;
  float resistance = 2000 * voltage / (1 - voltage / 5);
  LuxValue = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
}
void BT_Update() {

  if (Serial.available() > 0) {
    String input = Serial.readStringUntil('\n');
    for (int i = 0; i < 8; i++) {
      if (input == String(i)) {
        B[i] = !B[i];
        break;  // Exit the loop once the condition is met
      }
      // Check if input starts with "t1-"
      if (input.startsWith(String("t") + String(i) + "-")) {
        String valueStr = input.substring(3);  // Extract numeric part after "t1-"
        bool isNumeric = true;

        // Check if all characters after "t1-" are numeric
        for (size_t i = 0; i < valueStr.length(); i++) {
          if (!isDigit(valueStr.charAt(i))) {
            isNumeric = false;
            break;
          }
        }

        if (isNumeric) {
          int value = valueStr.toInt();  // Convert the numeric part to an integer
          // Do something with the value if needed
          T[i].PT = value;
          Serial.println(T[i].PT);
        }
      }
    }
  }
}
//----------------------------------User Defined Function Stage 1-----------------------------------

//----------------------------------User Defined Function Stage 2-----------------------------------
BLYNK_WRITE(V0) {
  value1 = param.asInt(); B[0] = value1;
}
BLYNK_WRITE(V1) {
  value1 = param.asInt(); B[1] = value1;
}
BLYNK_WRITE(V2) {
  value1 = param.asInt(); B[2] = value1;
}
BLYNK_WRITE(V3) {
  value1 = param.asInt(); B[3] = value1;
}
BLYNK_WRITE(V4) {
  value1 = param.asInt(); B[4] = value1;
}

/* B map
  B[0] = auto / manual, false = auto, true = manual
  B[1] = manual start lampu
  B[2] = manual buka tirai
  B[3] = manual tutup tirai
  B[4] = manual stop
*/
//----------------------------------User Defined Function Stage 2-----------------------------------

//----------------------------------User Defined Function Stage 3-----------------------------------
//----------------------------------User Defined Function Stage 3-----------------------------------

//----------------------------------Testing Function------------------------------------------------
//----------------------------------Testing Function------------------------------------------------


//--------------------------------- Setup----------------------------------------------
void setup() {
  Serial.begin(115200);
  //Pin Initialization
  pinMode(LS_fullOpen, INPUT);
  pinMode(LS_fullClose, INPUT);
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  //pinMode(enable1Pin, OUTPUT);
  pinMode(relay1, OUTPUT);

  // configure LED PWM functionalitites
  //ledcSetup ( pwmChannel, freq, resolution );
  // attach the channel to the GPIO to be controlled
  //ledcAttachPin ( enable1Pin, pwmChannel );

  ledcAttach(enable1Pin, freq, resolution);


  //Timer Initialization (dalam milisecond)
  T[0].PT = 1;  // update to ESP32
  T[1].PT = 5;  //
  T[2].PT = 5;  //
  T[3].PT = 5;  //
  T[4].PT = 5;  //
  T[5].PT = 5;  //
  T[6].PT = 5;  //
  T[7].PT = 5;  //

  Blynk.begin(auth, ssid, pass); //memulai Blynk

}

//Start Services

//Testing

//--------------------------------- Setup----------------------------------------------


//--------------------------------- Loop-----------------------------------------------



//--------------------------------- Loop-----------------------------------------------
void loop() {
  //Update Input
  Input_Update();
  //BT_Update();
  Blynk.run(); //menjalankan blynk
  //Process
  //manual process
  if (!B[0]) {             //when Auto
    // Serial.print("auto ");
    Serial.println(LuxValue);
    B_F[0] = true;
    //Serial.print(" ");
    if ((LuxValue < LowLux) && !S[1]) {
      close_tirai();
      digitalWrite(relay1, true);
      //Serial.println("low");
    } else if ((LuxValue > HighLux) && !S[0]) {
      open_tirai();
      digitalWrite(relay1, false);
      //Serial.println("high");
    }

    if ((S[0] && !S_P[0]) || (S[1] && !S_P[1]) ) {
      stop();
      B[2] = false;
      B[3] = false;
      B[4] = false;
      S_P[0] = S[0];
      S_P[1] = S[1];
    }

  } else {                 //when manual
    //relay control
    if (B_F[0]) {
      stop();
      digitalWrite(relay1, false);
      B_F[0] = false;
    }
    digitalWrite(relay1, B[1]);


    //tirai kontrol
    if (B[2] && !S[0]) open_tirai();
    if (B[3] && !S[1]) close_tirai();
    if (B[4] || S[0] || S[1]) {
      stop();
      B[2] = false;
      B[3] = false;
      B[4] = false;
      Blynk.virtualWrite(V2, 0);
      Blynk.virtualWrite(V3, 0);
      Blynk.virtualWrite(V4, 0);
    }


  }


  //for (int i = 0; i < 8; i++) {Serial.print(B[i]);} Serial.println("");

  //Update Output

}

//--------------------------------- Note-----------------------------------------------
/*



*/
//--------------------------------- Note-----------------------------------------------






$abcdeabcde151015202530354045505560fghijfghij
$abcdeabcde151015202530354045505560fghijfghij
esp:0
esp:2
esp:4
esp:5
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:21
esp:22
esp:23
esp:25
esp:26
esp:27
esp:32
esp:33
esp:34
esp:35
esp:3V3
esp:EN
esp:VP
esp:VN
esp:GND.1
esp:D2
esp:D3
esp:CMD
esp:5V
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:D1
esp:D0
esp:CLK
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
NOCOMNCVCCGNDINLED1PWRRelay Module
relay1:VCC
relay1:GND
relay1:IN
relay1:NC
relay1:COM
relay1:NO
led4:A
led4:C
ldr1:VCC
ldr1:GND
ldr1:DO
ldr1:AO
sw1:1
sw1:2
sw1:3
sw2:1
sw2:2
sw2:3
vcc3:VCC
gnd4:GND
r6:1
r6:2
r7:1
r7:2
r4:1
r4:2
r5:1
r5:2
r8:1
r8:2