#define BLYNK_TEMPLATE_ID "TMPL39sshMipF"
#define BLYNK_TEMPLATE_NAME "heat controller"
#define BLYNK_AUTH_TOKEN "e8Xm8OQs4QUUITtZawrQiBA-k2H5zdc_"

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <BlynkSimpleEsp32.h>
#include <WiFi.h>

// Temperature state ranges
#define TEMP_IDLE_MAX 20
#define TEMP_HEATING_MAX 30
#define TEMP_STABILIZING_MAX 35
#define TEMP_TARGET_MAX 37

// Blynk virtual pins
#define VPIN_TEMP V0
#define VPIN_STATE V1
#define SYSTEM V2

// Pin definitions
#define SWITCH_PIN 14
#define RELAY_PIN 27
#define BUZZER_PIN 25
#define ONE_WIRE_BUS 15

#define BLYNK_PRINT Serial

const char* ssid = "Wokwi-GUEST";
const char* password = "";

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

Adafruit_SSD1306 display(128, 64, &Wire, -1);
float temperature = 0;
volatile bool flag = false;
esp_timer_handle_t periodic_timer;
bool systemEnabled = true;

void periodicTimerCallback(void* arg) {
  flag = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(SWITCH_PIN, INPUT_PULLUP);
  digitalWrite(RELAY_PIN, LOW);
  digitalWrite(BUZZER_PIN, LOW);  


  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    while (true);
  }
  Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("Connected!");

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Starting...");
  display.display();
  delay(1000);

  sensors.begin();
  

  const esp_timer_create_args_t periodic_timer_args = {
    .callback = &periodicTimerCallback,
    .arg = nullptr,
    .dispatch_method = ESP_TIMER_TASK,
    .name = "periodic_timer"
  };

  esp_timer_create(&periodic_timer_args, &periodic_timer);
  esp_timer_start_periodic(periodic_timer, 1000000);  // 1 second
}
const char* mqttServer = "38.242.251.245";
BLYNK_WRITE(V2) {
  systemEnabled = (param.asInt() == 1);
}

void loop() {
  Blynk.run();

  bool switchState = (digitalRead(SWITCH_PIN) == LOW);
  bool systemOn = systemEnabled && switchState;

  if (flag) {
    flag = false;
    if (systemOn) {
      readAndHandleTemperature();
    } else {
      displaySystemOff();
      digitalWrite(RELAY_PIN, LOW);
      Blynk.virtualWrite(VPIN_TEMP, 0);
      Blynk.virtualWrite(VPIN_STATE, "System OFF");
    }
  }

  Blynk.virtualWrite(SYSTEM, systemOn ? 1 : 0);
}

void readAndHandleTemperature() {
  sensors.requestTemperatures();
  temperature = sensors.getTempCByIndex(0);

  if (temperature == DEVICE_DISCONNECTED_C) {
    Serial.println("Error: Could not read temperature");
    return;
  }

  String state;
  if (temperature < TEMP_IDLE_MAX) {
    state = "Idle";
    digitalWrite(RELAY_PIN, LOW);
  } else if (temperature < TEMP_HEATING_MAX) {
    state = "Heating";
    digitalWrite(RELAY_PIN, HIGH);
  } else if (temperature < TEMP_STABILIZING_MAX) {
    state = "Stabilizing";
    digitalWrite(RELAY_PIN, HIGH);
  } else if (temperature < TEMP_TARGET_MAX) {
    state = "Target Reached";
    digitalWrite(RELAY_PIN, LOW);
  } else {
    state = "Overheat";
    digitalWrite(RELAY_PIN, LOW);
    tone(BUZZER_PIN, 2000, 1000); // Buzzer alert
  }

  Blynk.virtualWrite(VPIN_TEMP, temperature);
  Blynk.virtualWrite(VPIN_STATE, state);
  updateOLED(temperature, state);

  Serial.printf("Temp: %.2f °C | State: %s\n", temperature, state.c_str());
}

void updateOLED(float temp, String state) {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.printf("Temp: %.1f C\n", temp);
  display.printf("State: %s\n", state.c_str());
  display.printf("WiFi: %s\n", WiFi.isConnected() ? "OK" : "FAIL");
  display.display();
}

void displaySystemOff() {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("System OFF");
  display.printf("WiFi: %s\n", WiFi.isConnected() ? "OK" : "FAIL");
  display.display();
}
NOCOMNCVCCGNDINLED1PWRRelay Module