#include <ModbusMaster.h>
#include <Wire.h>
#include <DHT22.h>
#include <WiFi.h>
#include <HTTPClient.h>

// ------------------- WIFI DAN SPREADSHEET -------------------
const char* ssid = "wireless@umsida.ac.id";
const char* password = "AhmadDahlan1868";
const char* sheetUrl = "https://script.google.com/macros/s/AKfycbwYMe8YuPD1FkjufcYyBzVKuMASUhJJze_mR-IO5FoFdq6jdYJ0jA7cWG1xYDiWjhe1/exec";

// ------------------- PIN DEFINISI -------------------
#define RXD2 16
#define TXD2 17
#define RELAY_HEATER 23   // aktif HIGH
#define RELAY_FAN 26      // aktif LOW
#define DHT_PIN 33
#define LED_STATUS 2

// ------------------- SENSOR -------------------
DHT22 dht22(DHT_PIN);

// ------------------- VARIABEL DATA -------------------
float pvvoltage = 0;
float pvcurrent = 0;
float bvoltage = 0;
float battChargeCurrent = 0;
float temperature = 0;
float humidity = 0;

String statusHeater = "OFF";
String statusFan = "OFF";
bool modeManual = false;

// ------------------- MODBUS -------------------
ModbusMaster node;
void preTransmission() {}
void postTransmission() {}

void readSolar() {
  uint8_t result = node.readInputRegisters(0x3100, 6);
  if (result == node.ku8MBSuccess) {
    pvvoltage = node.getResponseBuffer(0x00) / 100.0f;
    pvcurrent = node.getResponseBuffer(0x01) / 100.0f;
    bvoltage = node.getResponseBuffer(0x04) / 100.0f;
    battChargeCurrent = node.getResponseBuffer(0x05) / 100.0f;
  }
}

// ------------------- BATAS KENDALI -------------------
float batasHumAtas = 50.0;
float batasHumBawah = 40.0;
float batasSuhuAtas = 45.0;
float batasSuhuBawah = 40.0;

// ------------------- SENSOR DHT -------------------
void bacaDHT() {
  float t = dht22.getTemperature();
  float h = dht22.getHumidity();
  if (dht22.getLastError() == dht22.OK) {
    temperature = t;
    humidity = h;
  }
}

// ------------------- RELAY -------------------
void kontrolRelay() {
  if (!modeManual) {
    bool heaterOn = false;
    bool fanOn = false;

    // Heater aktif HIGH
    if (humidity >= batasHumAtas || temperature <= batasSuhuBawah)
      heaterOn = true;
    else if (humidity <= batasHumBawah || temperature >= batasSuhuAtas)
      heaterOn = false;

    // Fan aktif LOW
    if (humidity >= batasHumAtas || temperature >= batasSuhuAtas)
      fanOn = true;
    else if (humidity <= batasHumBawah || temperature <= batasSuhuBawah)
      fanOn = false;

    digitalWrite(RELAY_HEATER, heaterOn ? HIGH : LOW);
    statusHeater = heaterOn ? "ON" : "OFF";

    digitalWrite(RELAY_FAN, fanOn ? LOW : HIGH);
    statusFan = fanOn ? "ON" : "OFF";
  }
}

// ------------------- PERINTAH DARI ESP2 -------------------
void bacaPerintahSerial2() {
  static String cmd = "";
  while (Serial2.available()) {
    char c = Serial2.read();
    if (c == '@') cmd = "";
    cmd += c;

    if (c == '!') {
      if (cmd.indexOf("MODE#MANUAL") >= 0) modeManual = true;
      else if (cmd.indexOf("MODE#AUTO") >= 0) modeManual = false;

      if (modeManual) {
        if (cmd.indexOf("HEATER#ON") >= 0) {
          digitalWrite(RELAY_HEATER, HIGH);
          statusHeater = "ON";
        } else if (cmd.indexOf("HEATER#OFF") >= 0) {
          digitalWrite(RELAY_HEATER, LOW);
          statusHeater = "OFF";
        }

        if (cmd.indexOf("FAN#ON") >= 0) {
          digitalWrite(RELAY_FAN, LOW);
          statusFan = "ON";
        } else if (cmd.indexOf("FAN#OFF") >= 0) {
          digitalWrite(RELAY_FAN, HIGH);
          statusFan = "OFF";
        }
      }
      cmd = "";
    }
  }
}

// ------------------- UPLOAD KE SPREADSHEET -------------------
void uploadKeSpreadsheet() {
  if (WiFi.status() != WL_CONNECTED) return;

  HTTPClient http;

  String fullURL = String(sheetUrl) +
                   "?pvvolt=" + String(pvvoltage, 2) +
                   "&pvcur=" + String(pvcurrent, 2) +
                   "&bvolt=" + String(bvoltage, 2) +
                   "&bcur=" + String(battChargeCurrent, 2) +
                   "&temp=" + String(temperature, 1) +
                   "&hum=" + String(humidity, 1) +
                   "&heater=" + statusHeater +
                   "&fan=" + statusFan;

  http.begin(fullURL);
  http.GET();
  http.end();
}

// ------------------- SETUP -------------------
void setup() {
  pinMode(RELAY_HEATER, OUTPUT);
  pinMode(RELAY_FAN, OUTPUT);
  pinMode(LED_STATUS, OUTPUT);

  digitalWrite(RELAY_HEATER, LOW);
  digitalWrite(RELAY_FAN, HIGH);

  Serial.begin(115200); // digunakan untuk Modbus di pin 1 (TX0) & 3 (RX0)
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);

  node.begin(1, Serial);
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  Wire.begin();

  WiFi.begin(ssid, password);
  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
    delay(200);
  }
}

// ------------------- LOOP -------------------
void loop() {
  static unsigned long lastRead = 0, lastSend = 0, lastBlink = 0, lastUpload = 0;
  unsigned long now = millis();

  // LED indikator
  if (now - lastBlink >= 1000) {
    lastBlink = now;
    digitalWrite(LED_STATUS, !digitalRead(LED_STATUS));
  }

  // Baca sensor tiap 2 detik
  if (now - lastRead >= 2000) {
    lastRead = now;
    bacaDHT();
    readSolar();
    kontrolRelay();
  }

  // Kirim data ke ESP2 tiap 1 detik
  if (now - lastSend >= 1000) {
    lastSend = now;
    String dataKirim = "@#" + String(pvvoltage, 2) + "#" +
                       String(pvcurrent, 2) + "#" +
                       String(bvoltage, 2) + "#" +
                       String(battChargeCurrent, 2) + "#" +
                       String(temperature, 1) + "#" +
                       String(humidity, 1) + "#" +
                       statusHeater + "#" +
                       statusFan + "#!";
    Serial2.println(dataKirim);
  }

  // Upload ke spreadsheet tiap 60 detik
  if (now - lastUpload >= 60000) {
    lastUpload = now;
    uploadKeSpreadsheet();
  }

  bacaPerintahSerial2();
}
