#include <WiFi.h>
#include <PubSubClient.h>
#include <EEPROM.h>
#include "GravityTDS.h"

#define PIN_KURAS       32 // relay kuras
#define PIN_PUMP        33 // relay pengisian
#define TRIG            2  
#define ECHO            4  
#define PIN_PH          34
#define PIN_TDS         35
#define EEPROM_SIZE 512

// Wi-Fi credentials
const char* ssid = "1234";
const char* password = "11111111";
const char* mqtt_server = "habibigarden.com";
const int mqtt_port = 1883;

// MQTT topics
const char* kuras_topic = "dashboard/kuras";
const char* refill_topic = "dashboard/refill";
const char* mode_topic = "dashboard/mode";

WiFiClient espClient;
PubSubClient client(espClient);

bool autoMode = true;

// Data pH
int nilai_analog_PH;
float Po = 0;
float PH_step;
double TeganganPh;
float PH4 = 3.30;
float PH7 = 2.80;

// Data ketinggian
int duration;
int jarak;
int ketinggian;
int tinggikolam = 7; 

// Data sensor TDS
GravityTDS gravityTds;
float temperature = 25, tdsValue = 0;

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Menghubungkan ke ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi terhubung");
  Serial.print("Alamat IP: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Pesan diterima di topic [");
  Serial.print(topic);
  Serial.print("]: ");
  String message;
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if (String(topic) == kuras_topic) {
    if (!autoMode) {
      if (message == "1") {
        digitalWrite(PIN_KURAS, LOW);
        Serial.println("Kuras ON");
      } else if (message == "0") {
        digitalWrite(PIN_KURAS, HIGH);
        Serial.println("Kuras OFF");
      }
    }
  } else if (String(topic) == refill_topic) {
    if (!autoMode) {
      if (message == "1") {
        digitalWrite(PIN_PUMP, LOW);
        Serial.println("Refill ON");
      } else if (message == "0") {
        digitalWrite(PIN_PUMP, HIGH);
        Serial.println("Refill OFF");
      }
    }
  } 
  if (String(topic) == mode_topic) {
    if (message == "autoON") {
      autoMode = true;
      Serial.println("Auto mode ON");
    } else if (message == "autoOFF") {
      autoMode = false;
      Serial.println("Manual mode ON");
    }
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Menghubungkan ke MQTT... ");
    if (client.connect("ESP32Client")) {
      Serial.println("terhubung");
      client.subscribe(kuras_topic);
      client.subscribe(refill_topic);
      client.subscribe(mode_topic);
    } else {
      Serial.print("gagal, rc=");
      Serial.print(client.state());
      Serial.println(" coba lagi dalam 5 detik");
      delay(5000);
    }
  }
}

void Sensor(int trigPin, int echoPin) {
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  jarak = duration * 0.034 / 2;
  ketinggian = tinggikolam - jarak;
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  pinMode(PIN_KURAS, OUTPUT);
  pinMode(PIN_PUMP, OUTPUT);
  pinMode(ECHO, INPUT);
  pinMode(TRIG, OUTPUT);

  digitalWrite(PIN_KURAS, HIGH);
  digitalWrite(PIN_PUMP, HIGH);

  EEPROM.begin(EEPROM_SIZE);  // Initialize EEPROM
  
  gravityTds.setPin(PIN_TDS);
  gravityTds.setAref(3.3);  // Reference voltage on ADC, default 5.0V on Arduino UNO
  gravityTds.setAdcRange(4096);  // 1024 for 10bit ADC; 4096 for 12bit ADC
  gravityTds.begin();
}

void loop() {
   if (!client.connected()) {
    Serial.println("Koneksi terputus, mencoba menghubungkan kembali...");
    reconnect();
  }

  // Debug: Cek status koneksi
  Serial.print("Status koneksi MQTT: ");
  Serial.println(client.state());

  client.loop();

  if (autoMode) {
    gravityTds.setTemperature(temperature);  // Set the temperature and execute temperature compensation
    gravityTds.update();  // Sample and calculate 
    tdsValue = gravityTds.getTdsValue();  // Get the value
    Serial.print("Nilai tds: ");
    Serial.print(tdsValue, 0);
    Serial.println("ppm");
    delay(1000);
    
    nilai_analog_PH = analogRead(PIN_PH);
    TeganganPh = 3.3 / 4096.0 * nilai_analog_PH;
    PH_step = (PH4 - PH7) / 3;
    Po = 7.00 + ((PH7 - TeganganPh) / PH_step);
    Serial.print("Nilai PH cairan: ");
    Serial.println(Po, 2);
    delay(1000);
    
    Sensor(TRIG, ECHO);
    Serial.print("Ketinggian = ");
    Serial.print(ketinggian);
    Serial.println("cm");

    // Publish data ke tiga topik
    String payload1 = String(Po);
    client.publish("dashboard/ph", payload1.c_str());

    String payload2 = String(tdsValue);
    client.publish("dashboard/tds", payload2.c_str());

    String payload3 = String(ketinggian);
    client.publish("dashboard/ketinggian", payload3.c_str());

    if (tdsValue > 500) {
      Serial.println("KURAS ON");
      digitalWrite(PIN_KURAS, LOW); // Nyala
      digitalWrite(PIN_PUMP, HIGH); // Mati
    } else if (tdsValue < 500 && ketinggian < 3) {
      Serial.println("REFILL ON");
      digitalWrite(PIN_PUMP, LOW);
      digitalWrite(PIN_KURAS, HIGH);
    } else if (tdsValue < 500 && ketinggian < 5) {
      Serial.println("REFILL ON");
      digitalWrite(PIN_PUMP, LOW);
      digitalWrite(PIN_KURAS, HIGH);
    } else {
      digitalWrite(PIN_PUMP, HIGH);
      digitalWrite(PIN_KURAS, HIGH);
    }
  }

  delay(1000);
}
