/
// Подключаем все нужные библиотеки для работы с датчиком и дисплеем
#include <EEPROM.h>                // Библиотека энергонезависимой памяти
#include <GyverWDT.h>              // Библиотека для отслеживания зависаний МК
#include <microDS18B20.h>          // Библиотека для цифрового датчика ds18b20
#include <GyverNTC.h>              // Библиотека для аналового NTC термистора
#include <iarduino_RTC.h>          // Библиотека для модуля реального времени
#define magnetic 2                 // Пин подключения реле управления пускателем
#define ds_temp 3                  // Пин подключения ds18b20
#define led_error 12               // Пин подключения сигнализирующего светодиода об аварии
#define ntc_boiler_temp A0         // Пин подключенияn NTC термистора
#define ntc_street_temp A1         // Пин подключенияn NTC термистора
#define R1 12950                   // Сопратевление делительного резитора 
#define R2 12950                   // Сопратевление делительного резитора 
#define K 3950                     // B-постоянная, K
#define K2 3380                    // B-постоянная, K
#define normal_temp 25             // Заданная температура 
#define normal_R 10000             // Сопративление термистора при заданной температуре 
#define HYSTERESIS 2               // Задаём Гистерезис 
MicroDS18B20<ds_temp> ds;                                                       // Прописываем датчик ds18b20
iarduino_RTC watch(RTC_DS1307);                                                 // Прописываем модуль RTC
GyverNTC ntc_boiler(ntc_boiler_temp, R1, K, normal_temp, normal_R);             // Прописываем NTC датчик
GyverNTC ntc_street(ntc_street_temp, R2, K2, normal_temp, normal_R);            // Прописываем NTC датчик
int temp_boiler;          // Переменная температуры в котле
int temp_room;            // Переменная температуры в помещении
int temp_room_set;        // Переменная для установки комнатной температуры  
int temp_street;          // Переменная температуры на улице
int temp_set;             // Переменная для установки температуры котла
uint8_t time_h;           // Переменная хранящая в себе данные о текущем часе
uint8_t reload;           // Переменная хранящая в себе количество перезагрузок МК при зависании
bool mag_on;              // Флаг включения дневного цикла нагрева
bool mag_on_night;        // Флаг включения ночного цикла нагрева
bool night_mode;          // Флаг включения ночного режима
bool temp_room_test;      // Флаг тестирования комнатной температуры
void setup() {
  Watchdog.enable(INTERRUPT_RESET_MODE, WDT_PRESCALER_128);          // Задаём режим и время для WDT 
  pinMode(magnetic, OUTPUT);            // Прописываем пин magnetic как выход
  pinMode(led_error, OUTPUT);           // Прописываем пин led_error как выход
  watch.begin();                        // Инициализируем модуль RTC 
  watch.period(1);                      // Задаём опрос данных с RTC модуля раз в минуту
  Serial.begin(9600);                   // Открываем порт отладки 
}
void loop() {
  if (EEPROM.put(0, reload) >= 5) digitalWrite(led_error, HIGH);          // Если перезагрузок будет больше 5, то включаем сигнализирующий светодиод ошибки 
  yield();          // Опрашиваем все датчики и модуль RTC
  if (temp_room < temp_room_set - HYSTERESIS) temp_room_test = false;           // Если температура в комнате ниже заданной, то опускаем флаг тестирования комнатной температуры
  if ((time_h >= 19 or time_h <= 6) and temp_room_test == false) {              // Если время с 19 вечера по 6 утра и флаг тестирования температуры опущен, то задаём параметры для ночного режима
    //Serial.println("night_mode");
    temp_room_set = 15;          // Температура в помещении
    temp_set = 35;               // Температура котла
    night_mode = true;           // Поднимаем флаг ночного режима
    mag_on_night = true;         // Поднимаем флаг для ночного цикла нагрева
    magnetic_on();               // Переходим в функцию нагрева
  }
  if ((time_h >= 7 or time_h <= 18) and temp_room_test == false) {              // Если время с 7 утра по 18 вечера и флаг тестирования температуры опущен, то выключаем ночной режим и задаём параметры
    //Serial.println("day_mode");
    night_mode = false;
    if ((temp_street == 8 or temp_street > 0) and night_mode == false) {
      temp_room_set = 22;
      temp_set = 35;
      mag_on = true;
      magnetic_on();
    }
    if ((temp_street == 0 or temp_street > -8) and night_mode == false) {
      temp_room_set = 22;
      temp_set = 40;
      mag_on = true;
      magnetic_on();
    }
    if ((temp_street == -8 or temp_street > -18) and night_mode == false) {
      temp_room_set = 20;
      temp_set = 55;
      mag_on = true;
      magnetic_on();
    }
    if ((temp_street == -18 or temp_street > -25) and night_mode == false) {
      temp_room_set = 20;
      temp_set = 60;
      mag_on = true;
      magnetic_on();
    }
    if ((temp_street == -25 or temp_street < -30) and night_mode == false) {
      temp_room_set = 22;
      temp_set = 68;
      mag_on = true;
      magnetic_on();
    }
  }
  Watchdog.reset(); // Переодический сброс watchdog, означающий, что устройство не зависло
}
void magnetic_on() {
  while(mag_on) {
    yield();                                                   // Опрашиваем датчики 
    if (temp_boiler <= temp_set - HYSTERESIS) {                // Если температура котла меньше заданной 
      if (temp_room <= temp_room_set - HYSTERESIS) {           // И если температура в помещении меньше заданной
        digitalWrite(magnetic, LOW);                           // Включаем тен
        Watchdog.reset();                                      // Переодический сброс watchdog, означающий, что устройство не зависло
      }
    }
    if (temp_boiler >= temp_set + HYSTERESIS) {                // Если температура котла набралась до заданной
      digitalWrite(magnetic, HIGH);                            // Выключаем тен
      Watchdog.reset();                                                               // Переодический сброс watchdog, означающий, что устройство не зависло
    }
    if (temp_room >= temp_room_set + HYSTERESIS) {             // Если температура в помещении набралась до заданной
      digitalWrite(magnetic, HIGH);                            // Выключаем тен 
      mag_on = false;                                          // Опускаем флаг цикла нагрева
      temp_room_test = true;                                   // Поднимаем флаг тестирования температуры в комнате
    }
  }
  while(mag_on_night) {
    yield();                                                                            // Опрашиваем датчики 
    if ((temp_boiler <= temp_set - HYSTERESIS) and night_mode == true) {                // Если температура котла меньше заданной 
      if (temp_room <= temp_room_set - HYSTERESIS) {                                    // И если температура в помещении меньше заданной
        digitalWrite(magnetic, LOW);                                                    // Включаем тен
        Watchdog.reset();                                                               // Переодический сброс watchdog, означающий, что устройство не зависло
      }
    }
    if ((temp_boiler >= temp_set + HYSTERESIS) and night_mode == true) {                // Если температура котла набралась до заданной
      digitalWrite(magnetic, HIGH);                                                     // Выключаем тен
      Watchdog.reset();                                                                 // Переодический сброс watchdog, означающий, что устройство не зависло
    }
    if ((temp_room >= temp_room_set + HYSTERESIS) and night_mode == true) {             // Если температура в помещении набралась до заданной
      digitalWrite(magnetic, HIGH);                                                     // Выключаем тен 
      mag_on = false;                                                                   // Опускаем флаг цикла нагрева
      temp_room_test = true;                                                            // Поднимаем флаг тестирования температуры в комнате
    }
  }
}
void yield() {
  static uint32_t timer_ds = millis();                       // Переменная для таймера на millis() на 1 секунду
  if (millis() - timer_ds >= 1000) {
    timer_ds = millis();
    if (ds.readTemp()) {
      temp_room = ds.getTemp();                              // Записываем данные с датчика в переменную
      temp_street = ntc_street.getTempAverage();             // Записываем данные с датчика в переменную
      temp_boiler = ntc_boiler.getTempAverage();             // Записываем данные с датчика в переменную
      //Serial.println(temp_room);
      //Serial.println(temp_boiler);
      //Serial.println(temp_street);
    }
    ds.requestTemp();
  }
  static uint32_t timer_watch = millis();                    // Переменная для таймера на millis() на 1 минуту
  if (millis() - timer_watch >= 60000) {
    timer_watch = millis();
    watch.gettime();                                         // Опрашиваем модуль RTC 
      time_h = watch.Hours;                                  // Записываем данные с датчика в переменную
  }
}
ISR(WATCHDOG) {
  reload++;
  EEPROM.get(0, reload);           // Дабовляем +1 к перезагрузке
}
}