// File Header
#include <WiFi.h>
#include "ThingsBoard.h"
#include <ESP32Servo.h>

// ESP32 WiFi
#define CURRENT_FIRMWARE_TITLE    "TEST"
#define CURRENT_FIRMWARE_VERSION  "1.0.0"
#define WIFI_SSID           "Wokwi-GUEST"
#define WIFI_PASSWORD       ""
// Server Thingsboard
#define TOKEN               "zFNOLHVN0TD7Dt21EQcb"
#define THINGSBOARD_SERVER  "thingsboard.cloud"
// Sensor PIR
#define pin_PIR 13
// Buzzer
#define pin_Buzzer 12
// Servo
#define pin_Servo 15
// LDR Photoresistor
#define pin_LDR 32
// LED
#define pin_LED 19

// Baud rate for debug serial
#define SERIAL_DEBUG_BAUD 115200

// Deklarasi Objek Perangkat ESP32 WiFi
WiFiClient espClient;
// Deklarasi Objek Perangkat Thingsboard
ThingsBoard tb(espClient);
// Deklarasi Objek Perangkat Servo
Servo servo;

// Variabel perangkat ESP32 WiFi
int status = WL_IDLE_STATUS;
// Variabel perangkat Sensor PIR
int sinyal_PIR = LOW;
int nilai_PIR = 0;
bool status_PIR = false;
// Variabel perangkat Servo
int sudut = 0;
bool status_Servo = false;
// Variabel perangkat LDR
const float GAMMA = 0.7;
const float RL10 = 50;
String status_cahaya = "";
const char* x = "aktif";
float lux = 0;

// Fungsi untuk melakukan koneksi ke Access Point
void config_WiFi()
{
  Serial.println("Mencoba Terkoneksi ke Access Point ...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Berhasil Terkoneksi");
}

// Fungsi untuk mengkoneksikan kembali ke Access Point
void reconnect_WiFi() {
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Berhasil Terkoneksi");
  }
}

// Fungsi mengaktifkan Buzzer
void buzzer_Aktif(int val){
  if (val == 1) {
    // Buzzer berbunyi
    tone(pin_Buzzer, 150); 
  } else if (val == 0){
    // Buzzer mati
    noTone(pin_Buzzer);
  }   
}

// Fungsi mengaktifkan Servo
void servo_Aktif(){
  for (sudut = 0; sudut <= 180; sudut += 10) {
    servo.write(sudut);
    delay(30);
  }
  for (sudut = 180; sudut >= 0; sudut -= 10) {
    servo.write(sudut);
    delay(30);
  }
}

// Fungsi aktifasi Sensor PIR
void sensor_PIR(){
  // Baca data dari sensor PIR
  nilai_PIR = digitalRead(pin_PIR); 
  // Jika objek terdeteksi 
  if (nilai_PIR == HIGH) {        
    if (sinyal_PIR == LOW) {
      Serial.println("Sensor PIR Mendeteksi Gerakan");
      status_PIR = true;  // Data status hama terdeteksi 
      status_Servo = true; // Data status servo       
      buzzer_Aktif(1);
      servo_Aktif();
      delay(1000);
      servo_Aktif();          
      sinyal_PIR = HIGH;
    }
  // Jika objek tidak terdeteksi
  } else { 
    if (sinyal_PIR == HIGH) {
      Serial.println("Sensor PIR Tidak Mendeteksi Gerakan");
      status_PIR = false; // Data status hama tidak terdeteksi 
      status_Servo = false;  // Data status servo
      buzzer_Aktif(0);         
      sinyal_PIR = LOW;
    }
  }
}

// Fungsi aktifasi Sensor LDR
void sensor_LDR(){  
  int analogValue = analogRead(pin_LDR);
  float voltage = analogValue / 1024. * 5;
  float resistance = 2000 * voltage / (1 - voltage / 5);
  lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));

  Serial.print("Cahaya: ");
  if (lux > 100) {
    status_cahaya = "Terang";
    digitalWrite(pin_LED, LOW);
  } 
  else {
    status_cahaya = "Gelap";
    digitalWrite(pin_LED, HIGH);
  }  
  
  delay(100);
}

void setup() {
  // initialize serial for debugging
  Serial.begin(SERIAL_DEBUG_BAUD);
  // Konfigurasi PIN Output
  pinMode(pin_Buzzer, OUTPUT);
  pinMode(pin_LED, OUTPUT);
  // Konfigurasi PIN Input
  pinMode(pin_PIR, INPUT);
  // Memanggil fungsi config_WiFi
  config_WiFi();
  // Memanggil method attach pada Objek Servo
  servo.attach(pin_Servo);

  digitalWrite(pin_LED, LOW);
}

void loop() {
  delay(1000);
  // Jika WiFi belum tekoneksi
  if (WiFi.status() != WL_CONNECTED) {
    reconnect_WiFi();
  }

  sensor_PIR();
  sensor_LDR();
  
  // Jika Belum terhubung ke Server Thingsboard
  if (!tb.connected()) {
    // Koneksi ke Server Thingsboard
    Serial.print("Terkoneksi ke Server: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" dengan token ");
    Serial.println(TOKEN);
    // Jika Gagal terkoneksi ke Server Thingsboard
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Gagal Terkoneksi!");
      return;
    }
  }

  // Menampilkan hasil pengiriman data serial
  Serial.println("Mengirim Data..."); 
  // Data yang akan dikirim ke Thingsboard
  tb.sendTelemetryBool("Hama", status_PIR);
  tb.sendTelemetryBool("Servo", status_Servo);
  tb.sendTelemetryString("ServoStatus", "Aktif"); 
  tb.sendTelemetryString("ServoStatus2", x);   

  Serial.print("Hama : ");
  Serial.print(status_PIR);
  Serial.print(" | Servo : ");
  Serial.println(status_Servo);
  Serial.print("Cahaya : ");
  Serial.print(status_cahaya);
  Serial.print(" | Lux : ");
  Serial.println(lux);


  tb.loop();
}