#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>

#define ONE_WIRE_BUS 2 // GPIO для DS18B20
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
ESP8266WebServer server(80);

float setPoint = 20.0; // Устанавливаемая температура
float hysteresis = 1.0; // Гистерезис
int relayPin = 5; // GPIO для реле
unsigned long lastGraphUpdate = 0; // Время последнего обновления графиков

// Хранение исторических данных
const int maxHistorySize = 60; // Максимальное количество записей
float temperatureHistory[maxHistorySize];
int relayStateHistory[maxHistorySize];
int historyIndex = 0;

// Параметры потребления энергии
const float powerConsumptionRate = 1.5; // Потребление в кВт
const float costPerKWh = 4.6; // Стоимость за кВтч
float totalEnergyConsumed = 0.0; // Общее потребление энергии в кВтч

// Объявление функций
void handleRoot();
void handleSet();
void handleData();
void updateGraphs();

void setup() {
    Serial.begin(115200);
    EEPROM.begin(512);
    
    // Чтение настроек из EEPROM
    EEPROM.get(0, setPoint);
    EEPROM.get(4, hysteresis);
    
    pinMode(relayPin, OUTPUT);
    digitalWrite(relayPin, LOW); // Реле выключено
    
    // Создание точки доступа
    WiFi.softAP("ThermoRegulator", "password");
    
    // Установка статического IP-адреса
    IPAddress local_IP(192, 168, 4, 1); 
    IPAddress gateway(192, 168, 4, 1); 
    WiFi.softAPConfig(local_IP, gateway, IPAddress(255, 255, 255, 0));

    server.on("/", handleRoot);
    server.on("/set", handleSet);
    server.on("/data", handleData); // Обработчик для получения данных
    server.begin();
}

void loop() {
    server.handleClient();
    
    sensors.requestTemperatures();
    float currentTemp = sensors.getTempCByIndex(0);
    
    if (currentTemp < (setPoint - hysteresis)) {
        digitalWrite(relayPin, HIGH); // Включить реле
        totalEnergyConsumed += powerConsumptionRate / (3600 / 5); // Добавляем потребление каждые 5 секунд
    } else if (currentTemp > (setPoint + hysteresis)) {
        digitalWrite(relayPin, LOW); // Выключить реле
    }
    
    // Сохранение исторических данных
    temperatureHistory[historyIndex] = currentTemp;
    relayStateHistory[historyIndex] = digitalRead(relayPin);
    historyIndex = (historyIndex + 1) % maxHistorySize; // Циклическое обновление индекса
    
    unsigned long currentMillis = millis();
    
    // Обновление графиков каждые 5 секунд
    if (currentMillis - lastGraphUpdate >= 5000) {
        lastGraphUpdate = currentMillis;
        updateGraphs(); // Функция для обновления графиков
    }
}

void updateGraphs() {
    // Здесь добавьте код для обновления графиков на клиенте через AJAX или WebSocket
}

void handleRoot() {
    String html = "<html lang='ru'><head>";
    html += "<meta charset='UTF-8'>"; // Установка кодировки UTF-8 для поддержки кириллицы
    html += "<script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>";
    html += "<style>";
    html += "body { text-align: center; font-size: 24px; }"; // Увеличенный размер шрифта для всего тела
    html += "h1 { font-size: 3em; }"; // Увеличенный заголовок
    html += "h2 { font-size: 2em; }"; // Увеличенные подзаголовки
    html += "input[type=range], input[type=submit] { width: 80%; height: 40px; font-size: 20px; }"; // Увеличенные элементы управления
    html += "span { display: inline-block; min-width: 60px; font-size: 20px; }"; // Увеличенные размеры для отображения значений
    html += "canvas { width: 90%; height: 300px; margin: 20px auto; }"; // Уменьшенная высота графиков
    html += "</style>";
    
    html += "</head><body><h1>Терморегулятор</h1>";
    
    html += "<form action=\"/set\" method=\"GET\">";
    
	html += "Установленная температура: <input type=\"range\" min=\"10\" max=\"70\" step=\"0.1\" name=\"temp\" value=\"" + String(setPoint) + "\" oninput=\"updateValue(this.value, 'tempValue')\">";
	html += "<span id='tempValue'>" + String(setPoint) + "</span>°C<br>";
	
	html += "Гистерезис: <input type=\"range\" min=\"0.1\" max=\"10\" step=\"0.1\" name=\"hyst\" value=\"" + String(hysteresis) + "\" oninput=\"updateValue(this.value, 'hystValue')\">";
	html += "<span id='hystValue'>" + String(hysteresis) + "</span>°C<br>";
	
	html += "<input type=\"submit\" value=\"Сохранить\">";
	
  	// Отображение текущей температуры и состояния реле 
	float currentTemp = sensors.getTempCByIndex(0);
	String relayState = (digitalRead(relayPin) == HIGH) ? "Включено" : "Выключено";
	
	html += "<h2>Текущая температура: <span id='currentTemp'>" + String(currentTemp) + " °C</span></h2>";
	html += "<h2>Состояние реле: <span id='relayState'>" + relayState + "</span></h2>";
	
	// График состояния реле 
	html += "<canvas id='relayChart'></canvas>";
	
	// График потребления энергии 
	html += "<canvas id='energyChart'></canvas>";

	html += "<script>";
	
  	// AJAX-запросы для обновления данных без перезагрузки страницы 
	html += "function fetchData() { ";
	html += "fetch('/data') ";
	html += ".then(response => response.json()) ";
	html += ".then(data => { ";
	html += "document.getElementById('currentTemp').innerText = data.currentTemp.toFixed(1) + ' °C'; ";
	html += "document.getElementById('relayState').innerText = data.relayState ? 'Включено' : 'Выключено'; ";
	html += "}); ";
	html += "} ";
	
	// Обновление данных каждую секунду 
	html += "setInterval(fetchData, 1000);";

	// Инициализация графиков 
	html += "var relayCtx = document.getElementById('relayChart').getContext('2d');";
	html += "var relayChart = new Chart(relayCtx, {";
	html += "type: 'line',";
	html += "data: { labels: [], datasets: [{ label: 'Состояние реле', data: [], borderColor: 'blue', fill: false }] },";
	html += "options: { scales: { yAxes: [{ ticks: { beginAtZero:true } }] } }";
	html += "});";

	html += "var energyCtx = document.getElementById('energyChart').getContext('2d');";
	html += "var energyChart = new Chart(energyCtx, {";
	html += "type: 'line',";
	html += "data: { labels: [], datasets: [{ label: 'Потребление энергии (кВтч)', data: [], borderColor: 'orange', fill: false }] },";
	html += "options: { scales: { yAxes: [{ ticks: { beginAtZero:true } }] } }";
	html += "});";

	// Добавьте данные в графики (пример)
	html += "function updateGraphs() {";
	html += "var now = new Date().toLocaleTimeString();";
	
	// Обновление графика состояния реле 
	html += "relayChart.data.labels.push(now);";
	html += "relayChart.data.datasets[0].data.push(" + String(digitalRead(relayPin)) + ");"; 
	html += "if (relayChart.data.labels.length > "+String(maxHistorySize)+") { relayChart.data.labels.shift(); relayChart.data.datasets[0].data.shift(); }";
	html += "relayChart.update();";

	// Потребление энергии (пример)
	if (digitalRead(relayPin) == HIGH) {
        totalEnergyConsumed += powerConsumptionRate / (3600 / 5); // Добавляем потребление каждые 5 секунд
        
        float costInRubles = totalEnergyConsumed * costPerKWh;
        
        energyChart.data.labels.push(now); 
        energyChart.data.datasets[0].data.push(totalEnergyConsumed); 
        if (energyChart.data.labels.length > "+String(maxHistorySize)+") { energyChart.data.labels.shift(); energyChart.data.datasets[0].data.shift(); } 
        energyChart.update(); 
        
        html+= "document.getElementById('costDisplay').innerText = 'Стоимость потребления: ' + costInRubles.toFixed(2) + ' руб.';";
	}
  	
  	html+= "}";

  	// Обновление графиков каждые 5 секунд 
  	html+= "setInterval(updateGraphs, 5000);";

  	// Отображение стоимости потребления в рублях 
  	html+= "<h2 id='costDisplay'>Стоимость потребления: 0.00 руб.</h2>";

  	// Закрывающий тег скрипта и HTML документа 
  	html+= "</script></body></html>";

	server.send(200, "text/html", html);
}

void handleSet() {
	if (server.hasArg("temp")) {
		setPoint = server.arg("temp").toFloat();
		EEPROM.put(0, setPoint); // Сохранение температуры в EEPROM
		EEPROM.commit();
	}
	
	if (server.hasArg("hyst")) {
		hysteresis = server.arg("hyst").toFloat();
		EEPROM.put(4, hysteresis); // Сохранение гистерезиса в EEPROM
		EEPROM.commit();
	}
	
	server.sendHeader("Location", "/");
	server.send(302, "text/plain", "");
}

void handleData() {
	float currentTemp = sensors.getTempCByIndex(0);
	int relayState = digitalRead(relayPin);

	String jsonResponse = "{\"currentTemp\": " + String(currentTemp) + ", \"relayState\": " + String(relayState) + "}";

	server.send(200, "application/json", jsonResponse);
}