#1 Проекти » Створення чи ремонт теплового насосу STEEL на базі Arduino » 2025-01-18 22:33:40

daniil
відповідей: 8

Матеріяли для створення або ремонту теплового насосу:

Дозволено використання у особистих цілях.
Заборонено використання у комерційних цілях.

Для виготовлення потрібен зовнішній блок ON|OFF 24 kBtu на фреоні R410 чи R32.
блок треба дообладнати кабелем підігріву та пускачем якщо його немає.
Кабель підігріву саморгулюючий він шукається у пошуку "Гнучкий ТЕН 3м"
Мідна трубка 3/8 -30 м.
Лист сталі 3 мм
Трубогиб.
Вміння варити та паяти.

Електросхема складається з двох частин
верхня закріплена на лицьовій стороні
нижня внизу блоку поряд з теном.
архів з схемами:
електросхема
електросхема не передбачає що плата буде запускати компресор вона повинна запускати пускач або силове реле у зовнішньому блоці.
до силових реле додати діоди захисні до котушок реле (шукайте у пошуку діод для реле)
чи просто використовуйте плати у проекті та вмонтуйте діоди у плату
силові реле для тенів:   
HLS-T91-16F-2-12VDC-30A

печатна плата


фото плати
фото плати

фото плати 2
фото плати 2


3 д модель друку дісплею
3 д модель друку дісплею
дісплей 2004 синього кольору якщо іншого треба міняти адресу у прошивці
кнопки 12.12 із кришкою

фото дісплею 1
фото 1
фото дісплею 2
фото

Розпіновка МК

Інструкція ТН STEEL

зборочні  без кожуху тільки теплообмінник

В середині укаласти три однакові спіралі по 10 метрів мідної труби 3/8 (9,52) з'єднані паралельно,  можна гнути трубогибом але однакова кількіть гибів повинна бути і однакова довжина відтинків труби, для рывного гыдравлычного супротиву. краще спіраль тоді фреон постійно міняє напрям руху що посилює теплообмін. меньше мідної труби не можна, 12 не можна 6 тне можна бо малий обїєм
можна використовувати пластинчастий теплообмінник але тоді на обратку ставиться бойлер 50 л і в программі треба вносити зміни щоб циркуляційний насос правцював весь час під чам розморозки бо порве теплообмінник.

Монтажні розміри монтажні розміри

інструкція по переобладнанню зовнішнього блоку

Прошивка
Прошивка

#include <Wire.h>             // библиотека 
#include <LiquidCrystal_I2C.h>// дисплей
#include <Time.h>              //часы
#include <EEPROM.h>
#include <avr/wdt.h>
#include <GyverButton.h>


//////////////////////////////////// порты реле
#define pin_Comp     9
#define pin_Valve    8
#define pin_Wentil   7
#define pin_Podogrev 6
#define pin_Pomp     5
#define pin_Ten2     4
#define pin_Ten4     3
#define pin_Gas      2

////////////////////////////////////порты датчиков
#define tempPin0     A0   // улица
#define tempPin1     A1   //дом
#define tempPin2     A2   //подача
#define tempPin3     A3   //хладагент
//#define B            3950  // B-коэффициент термистора
#define SERIAL_R     8000  // сопротивление последовательного резистора, 9,1 кОм
#define THERMISTOR_R 10000 // номинальное сопротивления термистора, 10 кОм

//////////////порты кнопок
#define pin_left     10
#define pin_enter    11
#define pin_rite     12
////////////////////////////////////порты доп устройств
//#define pin_press    A6
#define pin_termost  13
////////////////////////////////////мощность наружного блока
char nomer [] = "15X_02.24_WiFi";
const float powertn = 3.0;
const float powerten = 4.0;
int out = 10 ;                         // тепловой выбег
///////////////////////////////////дисплей
//LiquidCrystal_I2C lcd(0x3F,20,4);     //(3F - зеленый ) устанавливаем адрес lcd, кол-во символов и строк
LiquidCrystal_I2C lcd(0x27, 20, 4); //(27 - синий   ) устанавливаем адрес lcd, кол-во символов и строк
////////////////////////////////////////////////////////переменные датчиков

float v0, v1, v2, v3, tr0, tr1, tr2, tr3;
float TempA0, TempA1, TempA2, TempA3;
int   t0, t1, t2, t3;

class Rele
{ public:
    byte pin = 0     ;
    bool signalon = 0;
    bool prevsost = 0;
    bool sost1 = 0   ;
    char*sost2 = "-" ;
};

Rele Comp    ;
Rele Valve   ;
Rele Wentil  ;
Rele Podogrev;
Rele Ten2    ;
Rele Ten4    ;
Rele Pomp    ;
Rele Gas     ;

////////////////////////////////переменные приема передачи данных

#define parse_in1 9         // число значений в массиве, который хотим получить
int intData[parse_in1];     // массив численных значений после парсинга
boolean recievedFlag;
boolean getStarted;
boolean send1 = 0, send2 = 0, send3 = 0;
byte index;
String string_convert = "";
boolean all_stop = 1;

///////////////////////////символ вертикальная палка

byte man[8] = {
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100
};
//////////////////////////////////////////////менять здесь назначение портов

GButton left  (pin_left );
GButton enter (pin_enter);
GButton rite  (pin_rite );
//      int left  = pin_left;
//      int enter = pin_enter;
//      int rite  = pin_rite;


///////////////////////////////////////////////////////// тайминг

unsigned long currentTime;  //тайминг
unsigned long loopTime;     //тайминг
unsigned long currentTime1;  //тайминг
unsigned long loopTime1;     //тайминг
unsigned long currentTime2;  //тайминг
unsigned long loopTime2;     //тайминг

////////////////////////////////////////////////// переменные для настройки

float tul  ; float etul;
float tdom ; float etdom;
float tpod ; float etpod;
float thlad; float ethlad;
float tzad = 40 ;
int   razm ;
float ptpod = 0;
float ttepl = 0;
float Pten = 0;  //
float Ptn = 0;
float prevPten;
float prevPtn;
const int adrPten = 20;
const int adrPtn = 30;

// чтение значения переменных сохраненных из еепром.

int8_t  koeffb ;  // int8_t  indkoeffb ;
int8_t  vspom  ;  // int8_t  indvspom  ;
int8_t  gradtn ;   //  int8_t  indgradtn ;
int8_t  p_kotla;   // float   indp_kotla ;
int8_t  regim  ;  // int8_t  indregim  ;
int8_t  ftzad  ;  // int8_t  indtzad   ;
byte    summ   ;  // byte    oldsumm   ;
int8_t rleto   ;  // int8_t indrleto   ;

////////////////////////////////////////////////// работа с памятью еепром

byte timeras ;//  int ftimeras  ;    //Корректор времени разморозки.
byte timeoff ; // int ftimeoff  ;    //Время наработки при плюсовой температуре.
byte dtrazm  ; // int fdtrazm   ;    //Разница температур сработки разморозки.
byte mintprod; // int fmintprod ;    //Минимальная температура оттайки продувкой
byte theat   ; // int ftheat    ;    //Температура подогрева картера
byte summ2   ;

///////////////////////////////////////////////////ошибки

byte i10 = 0;         // счетчик ошибок
byte i11 = 0;         // счетчик ошибок
byte err = 0;         // ошибка счетчик перезагрузки
byte err_tul = 0;
byte err_tdom = 0;
byte err_tpod = 0;
byte err_thlad = 0;
byte err_tul_2 = 0;
byte err_tdom_2 = 0;
byte err_tpod_2 = 0;
byte err_thlad_2 = 0;
byte err_tul_3 = 0;
byte err_tdom_3 = 0;
byte err_tpod_3 = 0;
byte err_tpod1 = 0;
byte err_thlad_3 = 0;
byte err_difhlad = 0;
byte err_diful = 0;
byte err_eeprom = 0;
byte termos = 0;
// int  fer=0;
String stroka = "LOAD ";
String stroka_2 = " E";

//   String stroka_3 = "_l";
String stroka_4 = " error";
int Esum = 0;
bool readee = true;


///////////////////////////////////////////////////флаги

byte i25=0;          // каждые 60 секунд отправка данных о настройках
byte x1 = 0;         // таймер для строки состояния
byte fglob = 0;      // флаг глобальных настроек
byte vflag = 0;      // флаг для экрана
byte fs = 0;         // флаг шага настройки
byte fsm = 0;        // флаг шаг сервис мод
byte fsm1 = 0;       // флаг шаг сервис мод
byte fserv = 0;      // флаг для экрана сервис мод
byte fservice = 0;   // предыдущее состояние  servis mode
byte freset = 0;     // предыдущее состояние кнопки reset
byte fset = 0;       // флаг перелистывание дисп
byte fdop = 0;       // флаг дополнительного подогрева
byte pdop = 0;       // флаг дополнительного подогрева
word flag_disp = 0;  // флаг первого таймера
word flag_obhod = 0; // флаг таймера обходчика программы
byte flag_source = 1; // флаг выбора источника тепла 1-тепловой насос, 2 газ, 3 - тэн
byte started = true; // флаг глобального отключения
byte compzad = 0;   // флаг задержки включения
byte compprev = 0;   // флаг задержки включения
bool nagrev = false; // флаг включить отопление
byte ten_power = 0;  // флаг мощности тенов
bool ten_start = false; // флаг сервис мода тен вкл
bool ten_2_on = false; // флаг сервис мода тен 2 кВт
bool ten_4_on = false; // флаг сервис мода тен 4 кВт
///////////////////////////////////////////переменные газовый котел
bool gaz = false;
//        byte zadgasoff=18;    //задержка включения газового котла х*10 сек
//        byte zadgason=90;     //задержка включения газового котла х*10 сек
byte tikgason = 0;
byte tikgasoff = 0;

/////////////////////////////////////продувка разморозка пауза

byte i = 0;                // тэн автоматический режим
byte i1 = 0;               // счетчик 2 для вентилятора
byte produvka = 0;         // счетчик 3 вентилятора
byte dprod = 0;
byte drazm = 0;
byte i3 = 0;               // тэн автоматический режим
byte razm_steep = 0;       // счетчик 3 вентилятора
byte i6 = 0;               // только при запуске
//      byte i7=0;                 // цикл включения
int comp_work = 0;        // счетчик продувки теплообменника
//byte i9=0;               // счетчик перезаписи еепром
byte pauza = 1;
byte ipauza = 0;


void setup()
{
  wdt_disable(); // бесполезная строка до которой не доходит выполнение при bootloop
  ////////////////////////////////////////////////////////////////прием передача по uart
  Serial.begin(115200);
  //Serial.setTimeout(50);
  //////////////////////////////////////////////////////////////////создаем объекты реле

  Comp.    pin = pin_Comp    ;
  Valve.   pin = pin_Valve   ;
  Wentil.  pin = pin_Wentil  ;
  Podogrev.pin = pin_Podogrev;
  Ten2.    pin = pin_Ten2    ;
  Ten4.    pin = pin_Ten4    ;
  Pomp.    pin = pin_Pomp    ;
  Gas.     pin = pin_Gas     ;
  proverka ();

  ////////////////////////////////////////////////////////////////////// порты реле
  /////////////////////////////////////////////////////////////////////////////////

  pinMode(pin_Comp,    OUTPUT); //Comp.signalon=0;  //настройка портов реле
  pinMode(pin_Valve,   OUTPUT);// Valve.signalon=0;    //настройка портов реле
  pinMode(pin_Wentil,  OUTPUT);// Wentil.signalon=0;   //настройка портов реле
  pinMode(pin_Podogrev, OUTPUT); //Podogrev.signalon=0;    //настройка портов реле
  pinMode(pin_Ten2,    OUTPUT); //Ten2.signalon=0;   //настройка портов реле
  pinMode(pin_Ten4,    OUTPUT); //Ten4.signalon=0;    //настройка портов реле
  pinMode(pin_Pomp,    OUTPUT); //Pomp.signalon=0;   //настройка портов реле
  pinMode(pin_Gas,     OUTPUT); //Gas.signalon=0;   //настройка портов реле
  proverka ();

  ////////////////////////////////////////////////////////////////инициализация дисплея

  lcd.init();                       // инициализация дисплея
  lcd.backlight();                  // подсветка включить
  lcdset(0);                        //курсор на первую строку
  lcd.print(stroka);                // приветствие
  lcd.createChar(0, man);

  //////////////////////////////////////////////////////////////////////////////// кнопки
  left.setDebounce(50);        // настройка антидребезга (по умолчанию 80 мс)
  left.setTimeout(2000);        // настройка таймаута на удержание (по умолчанию 500 мс)
  left.setClickTimeout(600);   // настройка таймаута между кликами (по умолчанию 300 мс)
  enter.setDebounce(50);        // настройка антидребезга (по умолчанию 80 мс)
  enter.setTimeout(2000);        // настройка таймаута на удержание (по умолчанию 500 мс)
  enter.setClickTimeout(600);   // настройка таймаута между кликами (по умолчанию 300 мс)
  rite.setDebounce(50);        // настройка антидребезга (по умолчанию 80 мс)
  rite.setTimeout(2000);        // настройка таймаута на удержание (по умолчанию 500 мс)
  rite.setClickTimeout(600);   // настройка таймаута между кликами (по умолчанию 300 мс)

  //
  //      pinMode(left   , INPUT_PULLUP);     //14й – вход  кнопка, замыкающая на землю
  //      pinMode(enter  , INPUT_PULLUP);     //15й – вход  кнопка, замыкающая на землю
  //      pinMode(rite   , INPUT_PULLUP);     //16й – вход  кнопка, замыкающая на землю
  pinMode(pin_termost   , INPUT);     //16й – вход  кнопка, замыкающая на землю

  pinMode( tempPin0, INPUT );
  pinMode( tempPin1, INPUT );
  pinMode( tempPin2, INPUT );
  pinMode( tempPin3, INPUT );
  /////////////////////////////////////////////////////////////////// чтение значения переменных сохраненных в еепром.
  koeffb   = EEPROM.read(1);
  vspom    = EEPROM.read(2);
  gradtn   = EEPROM.read(3);
  p_kotla  = EEPROM.read(4);
  regim    = EEPROM.read(5);  // флаг переключения на внешний источник
  ftzad    = EEPROM.read(6);
  summ     = EEPROM.read(7);
  rleto    = EEPROM.read(8);
  all_stop = EEPROM.read(9);
  if  (summ != koeffb + vspom + gradtn + p_kotla + regim + ftzad)
  {
    err_eeprom = 1;
    readee = false;
    koeffb = 40;
    vspom = 0;
    gradtn = 20;
    p_kotla = 2;
    regim = 2;
    ftzad = 10;
    rleto = 6;
  }
  /////////////////////////////////////////////////////////////////////////глобальные настройки
  timeras = EEPROM.read(11);     //Корректор времени разморозки.
  timeoff = EEPROM.read(12);     //Время наработки при плюсовой температуре.
  dtrazm  = EEPROM.read(13);     //Разница температур сработки разморозки.
  mintprod = EEPROM.read(14);     //Минимальная температура оттайки продувкой
  theat   = EEPROM.read(15);      //Температура подогрева картера
  summ2   = EEPROM.read(16);      //Температура подогрева картера
  //////////////////////////////////////////////////////////переменные тэнов
  EEPROM.get(adrPtn,  Ptn );       //Счетчик мощности
  EEPROM.get(adrPten, Pten);       //Счетчик мощности
  prevPten = Pten;
  prevPtn = Ptn;
  if ( summ2 != timeras + timeoff + dtrazm + mintprod + theat && summ2 > 0 )
  {
    err_eeprom = 1;
    readee = false;
    timeras = 6;
    timeoff = 3;
    dtrazm = 10;
    mintprod = 2;
    theat = 2;
  }

  //      ftimeras = timeras*10 ;    //Корректор времени разморозки.
  //      ftimeoff = timeoff*10 ;    //Время наработки при плюсовой температуре.
  //      fdtrazm  = dtrazm     ;    //Разница температур сработки разморозки.
  //      fmintprod= mintprod   ;    //Минимальная температура оттайки продувкой
  //      ftheat   = theat-1    ;    //Температура подогрева картера

  /////////////////////////////////////////////версия ПО

  /////////////////////////////////////////////////////чтение текущего значения температур
  readsensor ();

  /////////////////////////////////////////////////////таймер вступительный

  //    lcdset(0);lcd.print("> to NM");
  //    lcdset(1);lcd.print("E to TM");         // приветствие
  lcdset(1); lcd.print(nomer);
  if (readee == false) {
    lcdset(2);
    lcd.print("E9");
  }
  lcd.setCursor(0, 3); lcd.print("GS"); lcd.setCursor(9, 3); lcd.print("TM"); lcd.setCursor(17, 3); lcd.print("NM"); // приветствие
  currentTime  = millis() - 1000;
  for (;;) {
    left.tick(); enter.tick(); rite.tick();
    if ( left.isClick()) {
      fglob = 1;
      vflag = 1;
      fs = 1;
      break;
    };
    if (enter.isClick()) {
      fserv = 1;
      fsm = 2;
      break;
    };
    if ( rite.isClick()) {
      fserv = 0;
      break;
    };
    if (i6 >= 60) {
      break;
    }

    if (millis() > currentTime + 1000) {
      i6++;
      lcdset(0);      //курсор на строку 4
      lcd.print("NM :");
      lcd.print((60 - i6));
      lcd.print(" sec");   // приветствие
      currentTime  = millis();
    }

  }
  wifisend1(); wifisend2(); wifisend3();
  wdt_enable (WDTO_8S);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////основной цикл//////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loop()
{ left.tick(); enter.tick(); rite.tick();
  wdt_reset();
  if (millis() > 4000000000) {
    asm volatile("jmp 0x00");
  }

  if (fglob == 1)  {
    globalsettings ();
  }
  else {
    if (fserv == 1) {
      servicemode ();
    }
    else {   // нормальный режим

      currentTime  = millis(); // считываем время, прошедшее с момента запуска программы
      currentTime1 = millis(); // считываем время, прошедшее с момента запуска программы
      if (currentTime  < loopTime ) {
        loopTime  = currentTime;
      }
      if (currentTime1 < loopTime1) {
        loopTime1 = currentTime1;
      }
      knopki  ();
      parsing ();                   // функция парсинга
      if (currentTime1 - loopTime1  > flag_obhod)
      {
        readsensor ();           // чтение датчиков
        logika     ();           // логика работы
        proverka   ();           // проверка состояния реле



        send1 = 0; send2 = 0; 
        i25++; if(i25==6){send3=0;i25=0;}
        flag_obhod = 10000;
        flag_disp = 0  ;         // обновить экран
        loopTime1 = currentTime1;// флаг  обхода
      }
      ////////////////////////////////////////////////////////конец flag_obhod таймера///////////////////////////////////////////////////////////////////
      ////////////////////////////////////////////////////////Дисплей////////////////////////////////////////////////////////////////////////////////
      ////////////////////////////////////////////////////////проход раз в 10 сек (flag_disp)////////////////////////////////////////////////////////////
      if (currentTime1 - loopTime1  >  1600) {
        if (send1 == 0) {
          wifisend1  ();
        }
      }
      if (currentTime1 - loopTime1  >  5000) {
        if (send2 == 0) {
          wifisend2  ();
        }
      }
      if (currentTime1 - loopTime1  >  8300) {
        if (send3 == 0) {
          wifisend3  ();
        }
      }
      if (currentTime - loopTime  >  flag_disp)
      { displey ();          // вывод информации на дисплей
        loopTime = currentTime;
        flag_disp = 10000;        // флаг таймера   дисплея
      }
    }
  }
}
////////////////////////////////////////////////// конец основного цикла

void ochist () {
  lcd.clear();
}
void lcdset(byte stroka) {
  lcd.setCursor(0, stroka);
}
void displey ()
{

      tzad=ftzad*0.5+15;

   // Главный экран
     
  if (vflag==0)
     {
      ochist (); //очистка экрана
      lcdset(0);lcd.print("tvul:");lcd.print(tul, 1 );if(tul>=0){if(tul<10){lcd.print(" ");}}lcd.setCursor(9, 0);lcd.print(char(0));lcd.print("  ");lcd.print(razm );lcd.setCursor(15, 0); lcd.print(char(0));lcd.print("K4WH");
      lcdset(1);lcd.print("tbud:");if (ftzad==1){lcd.print("off ");}else{lcd.print(tdom,1);if(tdom<10){lcd.print(" ");}}lcd.setCursor(9, 1);lcd.print(char(0));if (Pten < 10000){lcd.print(" ");}if (Pten < 1000){lcd.print(" ");}if (Pten < 100){lcd.print(" ");}if (Pten < 10){lcd.print(" ");}lcd.print(Pten,0 );lcd.setCursor(15, 1);lcd.print(char(0)); lcd.print(Comp.sost2);lcd.print(Valve.sost2);lcd.print(Wentil.sost2);lcd.print(Podogrev.sost2);
      lcdset(2);lcd.print("tpod:");lcd.print(tpod,1);if(tpod<10){lcd.print(" ");}lcd.setCursor(9, 2);lcd.print(char(0));if (Ptn  < 10000){lcd.print(" ");}if (Ptn  < 1000){lcd.print(" ");}if (Ptn  < 100){lcd.print(" ");} if (Ptn < 10){lcd.print(" ");}lcd.print(Ptn ,0 );lcd.setCursor(15,2);lcd.print(char(0));lcd.print("TTGP");
      lcdset(3);lcd.print("Ttn :");lcd.print(ttepl,1);lcd.setCursor(9, 3);lcd.print(char(0)); lcd.setCursor(10, 3);  lcd.print(stroka); if (produvka>=1  ){lcd.print(30-produvka );}if (razm_steep>=1){lcd.print(timeras+45-razm_steep);}lcd.setCursor(15, 3);lcd.print(char(0)); lcd.print(Ten2.sost2);lcd.print(Ten4.sost2);lcd.print(Gas.sost2);lcd.print(Pomp.sost2);
      }
//////////////////////////////////////////////////////////////////////////// Экран настроек 1

      if (vflag==1)
      {
        ochist ();
        if (fs<=3){fset = 0;}if (fs==4){fset = -1;}if (fs>=5){fset = -2;} if (fs>=6){fset = -3;}
        if (fs  <=3) {   lcdset(fset)  ; if(fs==1){lcd.print(">");}else{lcd.print(" ");} lcd.print("tzad   : "); if(ftzad==1)    {lcd.print("pump on") ;}else{lcd.print(tzad,1      );}}
        if (fs  <=4) {   lcdset(fset+1); if(fs==2){lcd.print(">");}else{lcd.print(" ");} lcd.print("Power  : "); if(p_kotla==0){lcd.print("auto")   ;}else{lcd.print(p_kotla*powerten,1);}}
        if (fs  <=5) {   lcdset(fset+2); if(fs==3){lcd.print(">");}else{lcd.print(" ");} lcd.print("Ttn    : "); lcd.print(gradtn-20);}
                         lcdset(fset+3); if(fs==4){lcd.print(">");}else{lcd.print(" ");} lcd.print("Pdop   : "); lcd.print(vspom*powerten,1);
        if (fs  >=4)  {  lcdset(fset+4); if(fs==5){lcd.print(">");}else{lcd.print(" ");} lcd.print("Regim  : "); if(regim==1){lcd.print("TN");}   ;if(regim==2) {lcd.print("TN+EK");}if(regim==3){lcd.print("EK");}if(regim==4){lcd.print("TN+GAZ");}if(regim==5){lcd.print("GAZ"); };}
        if (fs  >=5)  {  lcdset(fset+5); if(fs==6){lcd.print(">");}else{lcd.print(" ");} lcd.print("koeffb : "); lcd.print(koeffb); }
        if (fs  >=6)  {  lcdset(fset+6); if(fs==7){lcd.print(">");}else{lcd.print(" ");} lcd.print("hol/tep: "); if(rleto==5){lcd.print("Zima_h");} if(rleto==6){lcd.print("Zima");}if(rleto>=7){lcd.print("Leto "); lcd.print(rleto);lcd.print(" C");} }
      }
//////////////////////////////////////////////////////////////////////////////// Экран настроек 2
      if (vflag==2)
      {       switch (fs){
               case 1: ochist ();lcdset(fset);  lcd.print(" tzad   : ");if(ftzad==1     ){lcd.print("pump on");}else{lcd.print(tzad,1);}; break;
               case 2: ochist ();lcdset(fset+1);lcd.print(" Power  : ");if(p_kotla==0){lcd.print("auto");}else {lcd.print(p_kotla*powerten,1);} break;
               case 3: ochist ();lcdset(fset+2);lcd.print(" Ttn    : ");                 lcd.print(gradtn-20) ; break;
               case 4: ochist ();lcdset(fset+3);lcd.print(" Pdop   : ");lcd.print(vspom*powerten,1); break;
               case 5: ochist ();lcdset(fset+4);lcd.print(" Regim  : ");if(regim==1     ){lcd.print("TN");};  if(regim==2) {lcd.print("TN+EK");}if(regim==3){lcd.print("EK"  );} if(regim==4){lcd.print("TN+GAZ");}if(regim==5){lcd.print("GAZ"); };break; 
               case 6: ochist ();lcdset(fset+5);lcd.print(" koeffb : ");                 lcd.print(koeffb) ;break;
               case 7: ochist ();lcdset(fset+6);lcd.print(" hol/tep: ");if(rleto==5){lcd.print("Zima_h");}if(rleto==6     ){lcd.print("Zima");}if(rleto>=7){lcd.print("Leto "); lcd.print(rleto);lcd.print(" C");} break;
      }}

       
       
}

///////////строка индикации
void strokasost ()
{ if (rleto<=6)     {
  switch (flag_source){
                case 1: stroka = "TN"; break;
                case 3: stroka = "EK"; break;
                case 2: stroka = "GAZ"; break;}
if (tpod>=ttepl+out)   {stroka = "OUT  ";}
}
else                  {stroka = "LITO";}
 if (razm_steep>=1)   {stroka = "RZM";lcd.print(timeras+45-razm_steep);}
 if (produvka>=1  )   {stroka = "PRD";lcd.print(30+dprod-produvka );}
if (started==false)   {stroka = "STOP";}
if (termos==1     )   {stroka = "TERMO";}
if (all_stop==0   )   {stroka = "OFF";}
if (err>0 )           {stroka = "ERROR";}
}
//////////// инидикация ошибок
  void errordisp()
{
 for ( int itest = 0; itest < 10; itest++) {
 ochist (); 
 lcdset(0);lcd.print("STATUS: ");lcd.print(stroka);
 lcdset(1); 
 if (err_tul      >0){lcd.print(stroka_2);lcd.print("vul" ); }
 if (err_tdom     >0){lcd.print(stroka_2);lcd.print("bud" );}
 if (err_tpod     >0){lcd.print(stroka_2);lcd.print("pod" );}
 if (err_thlad    >0){lcd.print(stroka_2);lcd.print("roz" );}
 if (err_eeprom   >0){lcd.print(stroka_2);lcd.print("eprom");}
 if (err_tpod1    >0){lcd.print("pod<5" );}
 if (err_tul_2 +err_tpod_2+err_thlad_2   >0)
 {lcdset(2); lcd.print("old error: ");
 lcdset(3);
 if (err_tul_2    >0){lcd.print(stroka_2);lcd.print("vul" );}
  if (err_tpod_2   >0){lcd.print(stroka_2);lcd.print("pod" );}
   if (err_thlad_2  >0){lcd.print(stroka_2);lcd.print("roz");}
 }
 
// lcdset(3); 
// for (int i2 = 1; i < 12; i2++) {errlog[i2]
// if (errlog[i2]>0){lcd.print("E");lcd.print(i2);lcd.print(" ");lcd.print(errlog[i2]);} // тело цикла
//}
 delay (1000);
 wdt_reset();
  }
}
///////////////////////Действия при ошибках

//  void errorlog()
//{
////  if (tdom  < -10  ) {err_tdom    = 1;tdom=0;}else{
////  if (tdom  > 40   ) {err_tdom    = 2;tdom=0;}err_tdom = 0;}
////  if (ftzad  == 1  ) {err_tdom    = 0;}
////  if (tul   < -35  ) {err_tul     = 1;tul=0;}else{
////  if (tul   > 50   ) {err_tul     = 2;tul=0; }err_tul = 0;}
////  if (thlad < -35  ) {err_thlad   = 1;thlad=0;}else{
////  if (thlad > 120  ) {err_thlad   = 2;thlad=0;}err_thlad = 0;}
////  if (flag_source!=1){err_tul     = 0;err_thlad = 0;}
////  if (tpod  <  5   ) {err_tpod    = 1;tpod=0; }else{
////  if (tpod  >  84  ) {err_tpod    = 2;tpod=0;}err_thlad = 0;}
//
//
////  if (Valve.signalon  ){
////  if (comp_work==20   ){
//////  if (thlad  > tul+7    ){err_difhlad=1;}else{err_difhlad=0;}
//////  if (tul    > thlad+7  ){err_diful  =1;}else{err_diful  =0;}
////  }}
// 
//  
//  Esum = err ;
//
////if (i10>10){err = 0;fer = 0; i10=11;} // если 10 обнулить индикацию ошибок
//strokasost ();
//  }
////глобальные настройки

void globalsettings ()
{
  
  currentTime  = millis(); // считываем время, прошедшее с момента запуска программы
if ( rite.isClick()) 
{    flag_disp=50; 
         if (vflag==1){fs++;if(fs>7){fs=7;}}
         if (vflag==2){   
                  if(fs==1){timeras++ ;if(timeras>30 ){timeras =30;}} 
                  if(fs==2){timeoff++ ;if(timeoff>9  ){timeoff=9;  }} 
                  if(fs==3){dtrazm++  ;if(dtrazm>15  ){dtrazm=15;  }} 
                  if(fs==4){mintprod++;if(mintprod>5 ){mintprod=5; }} 
                  if(fs==5){theat++   ;if(theat<1    ){theat=1;    }}
                  if(fs==6){timeras=6 ;timeoff=3;dtrazm=10;mintprod=2;theat=2;summ2=timeras+timeoff+dtrazm+mintprod+theat;} 
                  if(fs==7){ 
                              EEPROM.write(11, timeras    );
                              EEPROM.write(12, timeoff    );
                              EEPROM.write(13, dtrazm     );
                              EEPROM.write(14, mintprod   );
                              EEPROM.write(15, theat      );
                              summ2=timeras+ timeoff + dtrazm+ mintprod+ theat;
                              EEPROM.write(16, summ2     ); 
                              lcdset(fset+6);lcd.print("save ok reboting");
                              delay (2000);  
                              asm volatile("jmp 0x00");} 
                           }
      }


if (enter.isClick()) // если кнопка ентер нажата
       {  flag_disp=50; 
       if (vflag==1){vflag=2;}else{vflag=1;}
     }

if (left.isClick()) // если кнопка ентер нажата 

    {  flag_disp=50;
        if (vflag==1){fs--;if(fs<1){fs=1;}}
        if (vflag==2){   
                  if(fs==1){timeras-- ;if(timeras <3){timeras =3;}} 
                  if(fs==2){timeoff-- ;if(timeoff<2 ){timeoff=2 ;}} 
                  if(fs==3){dtrazm--  ;if(dtrazm<3  ){dtrazm=3  ;}} 
                  if(fs==4){mintprod--;if(mintprod<1){mintprod=1;}} 
                  if(fs==5){theat--   ;if(theat>10  ){theat=10  ;}}
                    }
    }

  
if(currentTime > (loopTime + flag_disp))
 {   
//////////////////////////////////////////////////////////////////////////// Экран настроек глобальных
//       ftimeras = timeras*10;     //Корректор времени разморозки. 3-30 (30-300)
//       ftimeoff = timeoff*10 ;    //Время наработки при плюсовой температуре.2-9 (20-90)
//       fdtrazm  = dtrazm;         //Разница температур сработки разморозки.3-15 (3-15)
//       fmintprod= mintprod ;      //Минимальная температура оттайки продувкой 1-5 ()
//       ftheat   = theat-1 ;       //Температура подогрева картера1-10  
     
      if (vflag==1)
      {
               ochist ();
        if (fs<=3){fset = 0;}if (fs==4){fset = -1;}if (fs>=5){fset = -2;}if (fs>=6){fset = -3;}
               
        if (fs  <=3)  {  lcdset(fset  ); if(fs==1){lcd.print(">");}else{lcd.print(" ");} lcd.print("timeras : ");lcd.print(timeras*10  );lcd.print(" sek");}
        if (fs  <=4)  {  lcdset(fset+1); if(fs==2){lcd.print(">");}else{lcd.print(" ");} lcd.print("timeoff : ");lcd.print(timeoff*10  );lcd.print(" min");}
        if (fs  <=5)  {  lcdset(fset+2); if(fs==3){lcd.print(">");}else{lcd.print(" ");} lcd.print("dtrazm  : ");lcd.print(dtrazm   );lcd.print(" *C");}
                         lcdset(fset+3); if(fs==4){lcd.print(">");}else{lcd.print(" ");} lcd.print("mintprod: ");lcd.print(mintprod );lcd.print(" *C");
        if (fs  >=4)  {  lcdset(fset+4); if(fs==5){lcd.print(">");}else{lcd.print(" ");} lcd.print("T heat  : ");if(theat==1) {lcd.print("AUTO");}else{lcd.print(theat-1);lcd.print(" *C");}}
        if (fs  >=5)  {  lcdset(fset+5); if(fs==6){lcd.print(">");}else{lcd.print(" ");} lcd.print("zavodskie nastroiki")               ;}
        if (fs  >=6)  {  lcdset(fset+6); if(fs==7){lcd.print(">");}else{lcd.print(" ");} lcd.print("save & exit")                       ;}
      }
//////////////////////////////////////////////////////////////////////////////// Экран настроек 2
      if (vflag==2)
      {
               if(fs==1){ochist ();lcdset(fset);  lcd.print("timeras : ");lcd.print(timeras*10  );lcd.print(" sek");} 
               if(fs==2){ochist ();lcdset(fset+1);lcd.print("timeoff : ");lcd.print(timeoff*10 );lcd.print(" min");}
               if(fs==3){ochist ();lcdset(fset+2);lcd.print("dtrazm  : ");lcd.print(dtrazm  );lcd.print(" *C");if(fs!=10){lcd.print("!!!");}} 
               if(fs==4){ochist ();lcdset(fset+3);lcd.print("mintprod: ");lcd.print(mintprod);lcd.print(" *C");}
               if(fs==5){ochist ();lcdset(fset+4);lcd.print("T heat  : ");if(theat==1) {lcd.print("AUTO");}else{lcd.print(theat-1);lcd.print(" *C");}} 
               if(fs==6){ochist ();lcdset(fset+5);lcd.print("zav. nastr. press >");}
               if(fs==7){ochist ();lcdset(fset+6);lcd.print("save & exit press >");}
    }

 
       
loopTime = currentTime;
flag_disp=10000; // флаг первого таймера   
}
}
void knopki()
{
  //////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// действия при нажатии кнопок//////////////////////////// 
//////////////////////////////////////////////////////////////////////////////////////

if ( rite.isClick())              
     {    flag_disp=50; 
         if (vflag==0){ errordisp();} 
         if (vflag==1){fs++;if(fs>7){fs=7;}}
         if (vflag==2){ 
          switch (fs) { 
                        case 1: ftzad++  ;    if(ftzad >20){ftzad  =20; }break;
                        case 2: p_kotla++;    if(p_kotla>3){p_kotla=3;  }break;
                        case 3: gradtn++ ;    if(gradtn>40){gradtn=40;  }break; 
                        case 4: vspom++  ;    if(vspom>2  ){vspom=2;    }break; 
                        case 5: regim++  ;    if(regim>5  ){regim=5;    }break;
                        case 6: koeffb++ ;    if(koeffb>50){koeffb=50;  }break;  
                        case 7: rleto++  ;    if(rleto>20 ){rleto=20;   }break;
                        } 
      }
     }


 if (enter.isClick()) // если кнопка ентер нажата
 {
      flag_disp=50;send3=0; 
       if (vflag==0){vflag=1;}else {if (vflag==1){vflag=2;if(fs==0){vflag=0;}}else{readeeprom ();vflag=1; fs=0;}}
  }

if ( left.isClick())
    {  flag_disp=50;
        if (vflag==1){fs--;if(fs<1){fs=1;}}
        if (vflag==2){switch (fs) { 
                      case 1:ftzad--  ;      if(ftzad<1   ){ftzad =1;  } break;
                      case 2:p_kotla--;      if(p_kotla<0 ){p_kotla=0; } break;
                      case 3:gradtn-- ;      if(gradtn<5  ){gradtn=5;  } break;
                      case 4:vspom--  ;      if(vspom<0   ){vspom=0;   } break;
                      case 5:regim--  ;      if(regim<1   ){regim=1;   } break;
                      case 6:koeffb-- ;      if(koeffb<30 ){koeffb=30; } break;
                      case 7:rleto--  ;      if(rleto<5   ){rleto=5;   } break;
                               }
                     } 
    }
  
  
  if (rite.isHolded()&& vflag==0) // если кнопка вправо удерживается на главном экране
      {freset=1;  flag_disp=50;tester();}
     
   if (left.isHolded()&& vflag==0) // если кнопка влево удерживается на главном экране 
    { flag_disp=50;  poread();}

         if (enter.isHolded()&& vflag==0) // если кнопка центр
    { flag_disp=50;  
    if (all_stop==0){all_stop=1;flag_disp=50;flag_obhod = 50; EEPROM.write(9, all_stop    );}
                else{all_stop=0;flag_disp=50;flag_obhod = 50; EEPROM.write(9, all_stop    );} readeeprom (); void logika ();}
      
   
      
  }
void logika ()
{
 
////////////////////////////////////////////////условия для безусловного отключения теплового насоса
    started=true;
    if (all_stop==0){started=false;}                          /// отключение веб интерфейсом.
    if (digitalRead(pin_termost ) == LOW ){started=false; termos=1;}else{termos=0;}    /// если на пине 13 минус отрубить все если +5В  то ок.
    if (err_tpod>0){started=false;}                           /// если на пине 13 минус отрубить все если +5В  то ок.
 
  if (rleto<=6) {//////////////////////////////////////////////РЕЖИМ ЗИМА

/////////////////////////////////////////////////включение, режим, условия низкого приоритета, ошибки
        
    //if (tul>=tzad&&tdom>=tzad+0.5){started=false;}else{started=true;}           // выключить если на улице больше 18 и в доме тепло.    
    if (regim==1){if (tul>(gradtn-20)+1)      flag_source=1;
                  if (tul<(gradtn-20)-1)     {started=false;}}                    // только тепловой насос 
    if (regim==2){if (tul>(gradtn-20)+1)     {flag_source=1;}
                  if (tul<(gradtn-20)-1)     {flag_source=3;}}                    // тепловой насос и электрокотел
    if (regim==3){                            flag_source=3;}                     // только электрокотел
    if (regim==4){if (tul>(gradtn-20)+1)     {flag_source=1;}  
                  if (tul<(gradtn-20)-1)     {flag_source=2;}}                    // ТН + газовый
    if (regim==5){                            flag_source=2;}                     // только газовый
   
    ttepl =  koeffb-tul;                                    // расчет температуры теплоносителя
    if (rleto==5){ttepl =  koeffb; 
    if (ttepl>(50-tul)){ ttepl=50-tul;
    if (ttepl>40){ ttepl=40;}
    if (ttepl<30){ ttepl=30;}}
    }

    if (flag_source!=1){if(err_thlad>30||err_tul>30){ttepl=koeffb;}}
    if (ttepl >50            ) {ttepl=50;}                  // максимальная температура работы 50 С
    if (ttepl <25            ) {ttepl=25;}                  // минимальная  температура с включенным тепловым насосом 30 С
    if (flag_source==1&&ttepl>40){ttepl=40;}                // максимальная температура с включенным тепловым насосом 40 С
    if (flag_source==2&&ttepl>45){ttepl=45;} 
  
    if (tpod >= (ttepl+1)){nagrev=false; }                  // условие выключения
    if (tpod <= (ttepl-1)){nagrev=true ; }                  // условие включеня


    
//////////////////////////////////////////////////////////режим тепловой насос

    if (flag_source==1){if(err_thlad>30||err_tul>30||err_tul_2>30||err_thlad_2>30){started=false;}}
    
///////////////////////////////////////////////////////////проверка на ошибки

    if (started){

//////////////////////////////////////////насос циркуляции
  
  if (tdom<(tzad-0.3)){Pomp.signalon=true;}
  if (tdom>(tzad+0.3)){Pomp.signalon=false;} 
  if (ftzad==1)       {Pomp.signalon=true;} 
  
 
  switch (flag_source){

 ///////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////// режим тепловой насос    
 /////////////////////////////////////////////////////////////////////
    case 1:
    if (tpod <  5|| err_tpod1==1){nagrev=false;err_tpod1=1;} /// строка защиты завис открытым 4-х ходовой клапан
    Gas.signalon=false;  
    if(nagrev&&compzad>18){ Comp.signalon=1;compprev=1;}else {Comp.signalon=0;}
    /// задержку включения компрессора
    if(Comp.signalon==0&&compprev==1){compzad=0;compprev=0;}
    if(compzad<18){compzad++;}else {compzad=50;}
    ////////////////////////////////////////////////////////4-х ходовой
    Valve.signalon=true;
    ////////////////////////////////////////////////////////подогрев картера компрессора
    
    if (theat ==1){                                                                           ////если включен режи авто
    if (tul  <= 3 ) {                                                                         ////если на улице холоднее 3-х
      if ( thlad+dtrazm+3<=tul  ) {Podogrev.signalon=true ;}else{Podogrev.signalon=false;}}}  ////включить когда процент разморозки +3
                                                                                              ////если режим авто не включен
    else {if (tul  <= theat     ) {Podogrev.signalon=true ; }                                 ////включить когда меньше чем температура включения подогрева
          if (tul  > theat+1    ) {Podogrev.signalon=false; }}                                ////выключить когда  температура включения подогрева больше уличной +1
          if (  tpod >= ttepl+2 ) {Podogrev.signalon=false;}                                  //// отключить при тепловом выбеге
     
    //////////////////////////////////////////////////////Продувка размомрозка
          if (Comp.signalon){ comp_work++;
          Wentil.signalon=true ;   /// вентилятор включить
                if(comp_work>500){comp_work=500;}
                
                // Включить продувку по времени нароботки
                if(comp_work>timeoff*10*6 && tul>mintprod){produvka=1;compzad=0;}

               // Включить разморозку или продувку по переохлаждению
                if(thlad+dtrazm<=tul){if(tul>mintprod){produvka=1;}else{razm_steep=1;}compzad=0;}
               
                }
             
             else///////////////////////если компрессор встал после нагрева
             {if(comp_work>30&&tul>=mintprod){produvka=1;compzad=0;} /// продувку включит если нагрел и остановился
             Wentil.signalon=false;                        /// остановить вентилятор
             comp_work=0;                                 }/// обнулить время работы компрессора

            // продувка розморозка запустяться если больше 1
          produv();razmorozka ();
///////////////////////////////////////////////////////////////догрев тенами       

        if (vspom >= 1 && regim==2      ){
        if (tdom>=tzad                  ){pdop=0;            }
        if (tdom<(tzad)-0.5||ftzad==1   ){pdop=1;            }
        if (tpod < ttepl-3              ){fdop=1;            }
        if (tpod > ttepl                ){fdop=0;ten_power=0;}
        if (tpod > 40                   ){fdop=0;ten_power=0;}
        if (vspom == 1&&fdop==1&&pdop==1){ ten_power=1;      } 
        if (vspom == 2&&fdop==1&&pdop==1){ ten_power=2;      }
                                    }else{ ten_power=0;      }
                 

  break;
  ///////////////////////////////////////////// режим газовый котел
  case 2:
  ten_power=0; compzad=0;
    Ten2.signalon    =false;   Ten4.signalon    =false;   Comp.signalon    =false;
    Wentil.signalon  =false;   Valve.signalon   =false;   Podogrev.signalon=false;

      if (nagrev==true  && tikgasoff>=18){Gas.signalon=true ;}
      if (nagrev==false || tikgason >=90){Gas.signalon=false;}
      if (Gas.signalon==true ) { tikgason++ ;if(tikgason >90){tikgason =90;}tikgasoff=0;}
                          else { tikgasoff++;if(tikgasoff>18){tikgasoff=18;}tikgason =0;}

  break; 

///////////////////////////////////////////// режим электрокотел
  case 3:
    compzad=0;
    Comp.signalon    =false;
    Gas.signalon     =false;
    Wentil.signalon  =false;
    Valve.signalon   =false;
    Podogrev.signalon=false;
    
    if (p_kotla==0    ){ i++;
    if (nagrev        ){    
    if (ten_power==0  ){ten_power=1;}
    if (i >= 4)           {if (tpod <= ptpod && tpod < (ttepl-1) ){i3++;  i=0;}else {i3=0;}
    if (i3 > 3)           {ten_power++; i3=0; i=0;}
    if (tpod  > (ttepl+1)){ten_power--; i3=0; i=0;} ptpod=tpod;}
                        }else {ten_power=0;}
                      
  ////////////////////////////////////тэн ручной режим  
    }else{ 
    if(p_kotla==1){if(nagrev){ten_power=1;}else  {ten_power=0;}}
    if(p_kotla==2){if(nagrev){ten_power=2;}else  {ten_power=0;}}
    if(p_kotla==3){if(nagrev){ten_power=3;}else  {ten_power=0;}}}
//   }else {ten_power=0;} 
  /////////////////////////////////////доп подогрев тенами
  break;
 

//////////////////////////////////////////////////////////отключить все если нет сигнала старт

}
 ////////////////////////////////////////////////////включение тенов
 switch (ten_power){
 case 0: Ten2.signalon=false; Ten4.signalon=false;  break;
 case 1: Ten2.signalon=true ; Ten4.signalon=false;  break;
 case 2: Ten2.signalon=false; Ten4.signalon=true ;  break;
 case 3: Ten2.signalon=true ; Ten4.signalon=true ;  break;  }     
       
////////////////////////////////////////////////////////счетчик мощности

if (Comp.signalon==1               ){Ptn  = Ptn + powertn *0.00278;}
if ((Ten2.signalon+Ten4.signalon)>0){Pten = Pten + (Ten2.signalon+Ten4.signalon)*powerten*2*0.00278;}
if (prevPten<Pten+2){prevPten=prevPten+2; EEPROM.put(adrPten,  Pten);}
if (prevPtn<Ptn+2  ){prevPtn =prevPtn +2; EEPROM.put(adrPtn ,  Ptn );}

///////////////////////////////////////////////////// Сигналы отключения самый высокий приоритет/
////////////////////////////////////////////////////          Тепловой выбег
if (tpod >= ttepl+out ){
  ten_power=0;Ten2.signalon=false; Ten4.signalon=false;
  Pomp.signalon     =true;
  Wentil.signalon   =false;
  Podogrev.signalon =false; 
  Valve.signalon    =false; 
  Ten2.signalon     =false; 
  Ten4.signalon     =false;  
  Comp.signalon     =false; 
  Gas.signalon      =false;}   // когда греет внешний котел все кроме насоса выключить
  
}else {Comp.signalon=false ; Wentil.signalon=false; Podogrev.signalon=false; Valve.signalon=false;
       Ten2.signalon=false ; Ten4.signalon=false  ; Gas.signalon=false     ;Pomp.signalon=false  ;
       if (tpod >= 60 ){ Pomp.signalon=true;} compzad=0;compprev=0;}
}else{
//////////////////////////////////////////////РЕЖИМ ЛЕТО
if (started){
Podogrev.signalon=false;
Valve.signalon   =false;
Ten2.signalon    =false;
Ten4.signalon    =false;
Gas.signalon     =false;
Pomp.signalon    =true;
ttepl = rleto;
if (tpod   >= ttepl+2) {Comp.signalon=true ; Wentil.signalon=true ;}
if (tpod   <= ttepl  ) {Comp.signalon=false; Wentil.signalon=false;pauza=1;}
if ( thlad >=98      ) {pauza=1;}


  if (pauza>=1){ Wentil.signalon=true; Comp.signalon  =false;
  pauza++; if (pauza > 30) {Wentil.signalon=true; pauza=0;}}
  
}else {Comp.signalon=false ; Wentil.signalon=false; Podogrev.signalon=false; Valve.signalon=false;
       Ten2.signalon=false ; Ten4.signalon=false  ; Gas.signalon=false     ; Pomp.signalon=false ;}
}
}

/*
   Данный алгоритм позволяет получить через Serial пачку значений, и раскидать
   их в целочисленный массив. Использовать можно банально для управления
   ЧЕМ УГОДНО через bluetooth, так как bluetooth модули есть UART интерфейс связи.
   Либо управлять через Serial с какой-то программы с ПК
   Как использовать:
   1) В PARSE_AMOUNT указывается, какое количество значений мы хотим принять.
   От этого значения напрямую зависит размер массива принятых данных, всё просто
   2) Пакет данных на приём должен иметь вид:
   Начало - символ $
   Разделитель - пробел
   Завершающий символ - ;
   Пример пакета: $110 25 600 920;  будет раскидан в массив intData согласно порядку слева направо
   Что делает данный скетч:
   Принимает пакет данных указанного выше вида, раскидывает его в массив intData, затем выводит обратно в порт.
   Отличие от предыдущего примера: написан мной, не используя никаких хитрых функций. Предельно просто и понятно работает
*/

void parsing() {
  if (Serial.available() > 0) {
    char incomingByte = Serial.read();        // обязательно ЧИТАЕМ входящий символ
    if (getStarted) {                         // если приняли начальный символ (парсинг разрешён)
      if (incomingByte != ' ' && incomingByte != ';') {   // если это не пробел И не конец
        string_convert += incomingByte;       // складываем в строку
      } else {                                // если это пробел или ; конец пакета
        intData[index] = string_convert.toInt();  // преобразуем строку в int и кладём в массив
        string_convert = "";                  // очищаем строку
        index++;                              // переходим к парсингу следующего элемента массива
      }
    }
    if (incomingByte == '$') {                // если это $
      getStarted = true;                      // поднимаем флаг, что можно парсить
      index = 0;                              // сбрасываем индекс
      string_convert = "";                    // очищаем строку
    }
    if (incomingByte == ';') {                // если таки приняли ; - конец парсинга
      getStarted = false;                     // сброс
      recievedFlag = true;                    // флаг на принятие
      while (Serial.available()) Serial.read();
    }

    }

  
  if (recievedFlag) {          // если получены данные
       recievedFlag = false; 
       if (intData[0]==1){
        ftzad   = intData[1];if(ftzad  <1 ){ftzad =1;  }if(ftzad >20 ){ftzad= 20; }
        p_kotla = intData[2];if(p_kotla<0 ){p_kotla=0; }if(p_kotla>3 ){p_kotla=3;  }
        gradtn  = intData[3];if(gradtn<5  ){gradtn=5;  }if(gradtn>40 ){gradtn=40;  }
        vspom   = intData[4];if(vspom<0   ){vspom=0;   }if(vspom>2   ){vspom=2;    }
        regim   = intData[5];if(regim<1   ){regim=1;   }if(regim>5   ){regim=5;    }
        koeffb  = intData[6];if(koeffb<30 ){koeffb=30; }if(koeffb>50 ){koeffb=50;  }
        rleto   = intData[7];if(rleto<6   ){rleto=6;   }if(rleto>20  ){rleto=20;   }
        all_stop= intData[8];if(all_stop<0){all_stop=0;}if(all_stop>1){all_stop=1; }
        Serial.println("save");
        }
        if (intData[0]==2){
        all_stop= intData[1];if(all_stop<0){all_stop=0;}if(all_stop>1){all_stop=1; }
        Serial.println("on/off");
        }
        if (intData[0]==3){
        regim   = intData[1];if(regim<1   ){regim=1;   }if(regim>5   ){regim=5;    }
        Serial.println("regim ok");
        }

   }
  
}
void wifisend1() {
   
      Serial.print("$");
      Serial.print("1")  ;Serial.print(" ");
      Serial.print(Comp.signalon)  ;Serial.print(" ");
      Serial.print(Valve.signalon)   ;Serial.print(" ");
      Serial.print(Wentil.signalon);Serial.print(" ");
      Serial.print(Podogrev.signalon);Serial.print(" ");
      Serial.print(Ten2.signalon)  ;Serial.print(" ");
      Serial.print(Ten4.signalon)    ;Serial.print(" ");
      Serial.print(Gas.signalon)   ;Serial.print(" ");
      Serial.print(Pomp.signalon)    ;
      Serial.println(";");
       send1=1;
}
void wifisend2() {
      Serial.print("$"); 
      Serial.print("2")       ;Serial.print(" ");
      Serial.print(tul*10,0  );Serial.print(" ");
      Serial.print(tdom*10,0 );Serial.print(" ");
      Serial.print(tpod*10,0 );Serial.print(" ");
      Serial.print(thlad*10,0);Serial.print(" ");
      Serial.print(ttepl*10,0);
      Serial.println(";");
       send2=1;
}
void wifisend3() {
      Serial.print("$")    ; 
      Serial.print("3")    ;Serial.print(" ");
      Serial.print(ftzad)  ;Serial.print(" ");
      Serial.print(p_kotla);Serial.print(" ");
      Serial.print(gradtn) ;Serial.print(" ");
      Serial.print(vspom)  ;Serial.print(" ");
      Serial.print(regim)  ;Serial.print(" ");
      Serial.print(koeffb) ;Serial.print(" ");
      Serial.print(rleto)  ;Serial.print(" ");
      Serial.print(all_stop);
      Serial.println(";");
      send3=1;

  }
void razmorozka()
{
  if (razm_steep>=1){                                               // цикл продувки теплообменника при низких температурах
          Comp.signalon=0; Ten2.signalon=0;
          Ten4.signalon=0;Podogrev.signalon=1;                      // пока цикл разморозки компрессор выключен а так-же задержка повторного запуска
          razm_steep++; 
          if (tul+1>=0  )  {drazm=3;}else{drazm=0;}
          if (razm_steep>1 )              {Wentil.signalon=0;  }    // выключить вентилятор.
          if (razm_steep>12)              {Valve.signalon=0;   }    // через минуту после стопа выкл 4 ходовой
          if (razm_steep>13)              {Comp.signalon=1;    }    // через 5 минуты включить компрессор.
          if (razm_steep>(13+timeras-drazm   )) {Comp.signalon=false;}    //if (razm_steep>19) {Comp.signalon=0;}                           // через 1 минуту выключить компрессор.
          if (razm_steep>(13+timeras+6       )) {Comp.signalon=true ;}    //if (razm_steep>25) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+7       )) {Comp.signalon=false;}    //if (razm_steep>26) {Comp.signalon=0;}                           // выключить компрессор.
          if (razm_steep>(13+timeras+13      )) {Comp.signalon=true ;}    //if (razm_steep>32) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+14      )) {Comp.signalon=false;}    //if (razm_steep>33) {Comp.signalon=0;}                           // выключить компрессор.
          if (razm_steep>(13+timeras+20      )) {Comp.signalon=true ;}    //if (razm_steep>32) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+21      )) {Comp.signalon=false;}    //if (razm_steep>33) {Comp.signalon=0;}                           // выключить компрессор.
          if (razm_steep>(13+timeras+27      )) {Comp.signalon=true ;}    //if (razm_steep>32) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+28      )) {Comp.signalon=false;}    //if (razm_steep>33) {Comp.signalon=0;}                           // выключить компрессор.
          
          }
if (razm_steep>(13+timeras+32)) {razm_steep=0;}                // всего цикрл разморозки 6 минут 

 }
void produv ()
{
  if (produvka>=1){
           Wentil.signalon=false;                                 // цикл продувки теплообменника при низких температурах
           Comp.signalon=false;                                  // пока цикл разморозки компрессор выключен а так-же задержка повторного запуска
           produvka++; 
           if (produvka>6 ) {Wentil.signalon=true;}                     // через минуту после стопа включить вентилятор
           if (tul<4){dprod=10;}else{dprod=0;}
           if (produvka>(30+dprod)) {Wentil.signalon=false; produvka=0;}               // подождать 4 минуты и выйти из цикла, разрешить запуск компрессора, выключить вентилятор
           }
}
void pauz ()
{
  if (pauza>=1){
           Wentil.signalon=true;                                       // цикл продувки теплообменника при перегреве компрессора
           Comp.signalon  =false;                                      // пока цикл разморозки компрессор выключен а так-же задержка повторного запуска
           pauza++; 
           if (pauza > 30) {Wentil.signalon=true; pauza=0;}            // подождать 4 минуты и выйти из цикла, разрешить запуск компрессора, выключить вентилятор
           }
}
void readeeprom ()
{
      EEPROM.write(1, koeffb   );
      EEPROM.write(2, vspom    );
      EEPROM.write(3, gradtn   );
      EEPROM.write(4, p_kotla  );
      EEPROM.write(5, regim    );
      EEPROM.write(6, ftzad    );
      summ=koeffb+ vspom+ gradtn+ p_kotla+ regim+ ftzad;
      EEPROM.write(7, summ     );
      EEPROM.write(8, rleto    );
      EEPROM.write(9, all_stop );
 //     Serial.println("save eeprom");
 } 

void proverka ()
{
if (Comp.signalon    ){digitalWrite(pin_Comp,0);Comp.sost2="+";          if (!Comp.prevsost){delay (300);}Comp.prevsost=true;}  
                  else{digitalWrite(pin_Comp,1);Comp.sost2="-";          if (Comp.prevsost ){delay (300);}Comp.prevsost=false;}  

if (Valve.signalon   ){digitalWrite(pin_Valve,0);Valve.sost2="+";        if (!Valve.prevsost){delay (300);}Valve.prevsost=true;}  
                  else{digitalWrite(pin_Valve,1);Valve.sost2="-";        if (Valve.prevsost) {delay (300);}Valve.prevsost=false;}   

if (Wentil.signalon  ){digitalWrite(pin_Wentil,0);Wentil.sost2="+";      if (!Wentil.prevsost){delay (300);}Wentil.prevsost=true;}  
                  else{digitalWrite(pin_Wentil,1);Wentil.sost2="-";      if (Wentil.prevsost ){delay (300);}Wentil.prevsost=false;}  

if (Podogrev.signalon){digitalWrite(pin_Podogrev,0);Podogrev.sost2="+";  if (!Podogrev.prevsost){delay (300);}Podogrev.prevsost=true;}  
                  else{digitalWrite(pin_Podogrev,1);Podogrev.sost2="-";  if (Podogrev.prevsost ){delay (300);}Podogrev.prevsost=false;}   

if (Ten2.signalon    ){digitalWrite(pin_Ten2,0);Ten2.sost2="+";          if (!Ten2.prevsost){delay (300);}Ten2.prevsost=true;} 
                  else{digitalWrite(pin_Ten2,1);Ten2.sost2="-";          if (Ten2.prevsost ){delay (300);}Ten2.prevsost=false;}   

if (Ten4.signalon    ){digitalWrite(pin_Ten4,0);Ten4.sost2="+";          if (!Ten4.prevsost){delay (300);}Ten4.prevsost=true;} 
                  else{digitalWrite(pin_Ten4,1);Ten4.sost2="-";          if (Ten4.prevsost ){delay (300);}Ten4.prevsost=false;}   

if (Gas.signalon     ){digitalWrite(pin_Gas,0);Gas.sost2="+";            if (!Gas.prevsost){delay (300);}Gas.prevsost=true;} 
                  else{digitalWrite(pin_Gas,1);Gas.sost2="-";            if (Gas.prevsost ){delay (300);}Gas.prevsost=false;}   

if (Pomp.signalon    ){digitalWrite(pin_Pomp,0);Pomp.sost2="+";          if (!Pomp.prevsost){delay (300);}Pomp.prevsost=true;}  
                  else{digitalWrite(pin_Pomp,1);Pomp.sost2="-";          if (Pomp.prevsost ){delay (300);}Pomp.prevsost=false;}  



}
/////////////////////////////// чтение датчиков показаний

void readsensor ()

{  
  t0 = analogRead( tempPin0 );
if ( t0>1010||t0<50){err_tul++;}
    v0 = t0*0.0048828125;
     tr0 = ((5/v0)*SERIAL_R)-SERIAL_R;
      etul = 0.00335570+ 0.0002531645*log(tr0/THERMISTOR_R);
       etul =  (1.0 /etul)-273;
 if (ftzad >1 ) 
 { 
   t1 = analogRead( tempPin1 );
   if ( t1>1010||t1<50){err_tdom++;}
     v1 = t1*0.0048828125;
     tr1 = ((5/v1)*SERIAL_R)-SERIAL_R;
      etdom = 0.00335570+ 0.0002531645*log(tr1/THERMISTOR_R);
       etdom =  (1.0 / etdom)-273;
       }
   t2 = analogRead( tempPin2 );
   if ( t2>1010||t2<50){err_tpod++;}
    v2= t2*0.0048828125;
     tr2 = ((5/v2)*SERIAL_R)-SERIAL_R;
      etpod = 0.00335570+ 0.0002531645*log(tr2/THERMISTOR_R);
       etpod =  (1.0 / etpod)-273;
       
   t3 = analogRead( tempPin3 );
   if ( t3>1010||t0<50){err_thlad++;}
     v3 = t3*0.0048828125;
     tr3 = ((5/v3)*SERIAL_R)-SERIAL_R;
      ethlad = 0.00335570+ 0.0002531645*log(tr3/THERMISTOR_R);
       ethlad =  (1.0 / ethlad)-273;
  
  /////////////////////////////тут записываем данные если они не выходят за пределы
  if (ftzad  == 1                 ) {err_tdom = 0;}else{ 
  if (etdom  > -20 && etdom  < 40 ) {tdom=etdom;  err_tdom   = 0;}}
  if (etul   > -30 && etul   < 50 ) {tul=etul;    err_tul    = 0;}else{err_tul++;}
  if (etpod  > -5  && etpod  < 120) {tpod=etpod;  err_tpod   = 0;}else{err_tpod++;}
  if (ethlad >-35  && ethlad < 120) {thlad=ethlad;err_thlad  = 0;}else{err_thlad++;}
 
////////////////////////////////////переменная процент обмерзания
if(err_thlad==0){
razm =  tul*10 - thlad*10 ;
if ( razm <= 0 ){razm=0; }
}
/////////////////////////////////тут ограничиваем максимальное значение переменной
if(err_tul>30    ){tul  =0;  err = 1;  err_tul_2= 1 ;   err_tul= 61 ;}  
if(err_tdom>30   ){tdom =0; ftzad= 1;                   err_tdom=61;} /// отключает датчик температуры домашний
if(err_tpod>30   ){tpod =0;  err = 1;  err_tpod_2=1 ;   err_tpod=61 ;}
if(err_thlad>30  ){thlad=0;  err = 1;  err_thlad_2=1;   err_thlad=61;}
 

/////сбрасывает ошибку когда датчик прочитан
if ((err_thlad+err_tpod+err_tul)==0){i10++;}else {i10=0;}
if (i10>30){err = 0;}

////////часть кода которая останавливает работу когда зарегестрирована ошибка
if (err>=1){i11++;}else {i11=0;}
if (i11>180){started=false;}

// errorlog   ();           // действия при ошибках
//Esum = err ;
//if (i10>10){err = 0;fer = 0; i10=11;} // если 10 обнулить индикацию ошибок
strokasost ();
  //////  переменная для индикации уровня обмерзания
//if(err_thlad_2==0){
//razm =  tul*10 - thlad*10 ;
//if ( razm <= 0 ){razm=0; }
//}
 
}
void servicemode ()
{ 
  /////////////////////////////////////////////////////////////////////////// быстрая часть программы
 
 currentTime = millis();// считываем время, прошедшее с момента запуска программы
  
  ///////////////////////////// действия при нажатии кнопок////////////////////////////
      
if ( rite.isClick())// если кнопка вправо нажата
     {  
         flag_disp=50;
              if(fsm1==0) {fsm  ++; if (fsm>10) {fsm=1;}}
              if(fsm1==1) {ttepl++;}

     }  

  if ( enter.isClick())  // если кнопка ентер нажата
          {  flag_disp=50; switch (fsm) {
             case 1 : if(Comp.signalon    ) {Comp.signalon=false;}     else{Comp.signalon=true;}     break;
             case 2 : if(Valve.signalon   ) {Valve.signalon=false;}    else{Valve.signalon=true;}    break;
             case 3 : if(Wentil.signalon  ) {Wentil.signalon=false;}   else{Wentil.signalon=true;}   break;
             case 4 : if(Podogrev.signalon) {Podogrev.signalon=false;} else{Podogrev.signalon=true;} break;
             case 5 : if(ten_2_on         ) {ten_2_on=false;}          else{ten_2_on=true;}          break;
             case 6 : if(ten_4_on         ) {ten_4_on=false;}          else{ten_4_on=true;}          break;
             case 7 : if(Gas.signalon     ) {Gas.signalon=false;}      else{Gas.signalon=true;}      break;
             case 8 : if(Pomp.signalon    ) {Pomp.signalon=false;}     else{Pomp.signalon=true;}     break;
             case 9 :tester();                                                                      break;
             case 10:if(fsm1==1)  {fsm1=0;}  else{fsm1=1;}                                          break;
           }
           }
 
 
 if ( left.isClick())// если кнопка влево нажата
    {  flag_disp=50;
       if(fsm1==0) {fsm --; if (fsm<1) {fsm=10;}}
       if(fsm1==1) {ttepl--;} 
    }
  
  
  ///////////////////////////////////////////////////////////////////медленная часть 
     currentTime2 = millis();
    if(currentTime2 - loopTime2 > 5000){
    readsensor (); 
    loopTime2 = currentTime2;
    }
   if(currentTime - loopTime > flag_disp){
     
     if (tpod<=(ttepl-1)){ten_start=true;}
     if (tpod>=(ttepl+1)){ten_start=false;}
     if (ten_start && ten_2_on ) { Ten2.signalon=true; } else {Ten2.signalon=false;}
     if (ten_start && ten_4_on ) { Ten4.signalon=true; } else {Ten4.signalon=false;}
    /// проверка включения реле.        
     proverka ();
     
  ///////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////Дисплей сервисмод
  ////////////////////////////////////////////////////////////////////////////////////
     
     
               ochist ();
               lcdset(0); lcd.print("      Test mode     ");
               lcdset(1); if (fsm!=10){lcd.setCursor((fsm-1), 1);lcd.print(char(0));}
                          lcd.setCursor(10, 1);lcd.print("tzad=");lcd.print(ttepl,1);
                          if (fsm==10){lcd.setCursor(19, 1);if (fsm1==1){lcd.print("+");}else{lcd.print("-");}}
                          
               lcdset(2); lcd.print("K4WHTTGPt"); lcd.print(" tpod=");lcd.print(tpod,1);
               lcdset(3); lcd.print(Comp.sost2);lcd.print(Valve.sost2);lcd.print(Wentil.sost2);lcd.print(Podogrev.sost2);lcd.print(Ten2.sost2);lcd.print(Ten4.sost2);lcd.print(Gas.sost2);lcd.print(Pomp.sost2);lcd.print("e");

     loopTime = currentTime;
     flag_disp=10000; // флаг первого таймера   
    
}
  
}
void tester()
{
 for ( int itest = 0; itest < 10; itest++) {
 ochist ();   
 lcdset(0);lcd.print("tvul :"); lcd.print(tul , 1); if(err_tul  >0){lcd.print(stroka_4);}
 lcdset(1);lcd.print("tbud :"); lcd.print(tdom ,1); if(err_tdom >0){lcd.print(stroka_4);}
 lcdset(2);lcd.print("tpod :"); lcd.print(tpod ,1); if(err_tpod >0){lcd.print(stroka_4);} 
 lcdset(3);lcd.print("trozm:"); lcd.print(thlad,1);  if(err_thlad>0){lcd.print(stroka_4);} 
 readsensor (); 
 delay (1000);
 wdt_reset();
  }
  
  }
  void poread()
{
  Ptn=1;Pten=1;  EEPROM.put(adrPtn,  Ptn); EEPROM.put(adrPten,  Pten);
  }
  

Дозволено використання у особистих цілях.
Заборонено використання у комерційних цілях.

#2 Проекти » Программа esphome Для теплового насосу STEEL модель 12 чи пізніше » 2024-11-17 10:59:40

daniil
відповідей: 0

Для підключення теплового насосу до системи home-assistant чи MQTT брокеру.
необхідно:
1додати ESPome до системи.
2 додати MQTT до системи.
3 створити новий пристрій.
матеріали:
плата esp-01s
програматор
https://arduino.ua/ru/prod3262-usb-perehodnik-dlya-programmirovaniya-i-otladki-modylei-esp-01-i-esp-01s

код програми я даю повний але вам треба залишити власні ключи ota та інше
фактично ви можете копіювати код починаючи зUART
також можете використовувати api чи mqtt За бажанням.

Данні будуть оновлюватись але вимикач та перемикач режимів працювати не будуть. необхіно замінити мікроконтроллер ТН заертайтесь на електронку вона активна.

Як прошити:
1 вставляєте есп у програматор антеною до юсб роз'єму не переплутайте
2 вставляєте програматор у комп вірогідно треба буде знайти драйвер під нього, як що вставите у распбері драйвер не потрібен.
3 встановлюєте кнопкою install та обираєте спосіб завантаження.
4 міняєте штатний локальний Wi-fi модуль на той що прошили. на платі намальовано антенку не переплутайте якою стороною вставляти модуль.

тепловий насос раз на 10 секунд публікує данні виду
$1 0 0 0 0 0 0 0 0;rn         -   це данні по стану реле
$2 64 213 309 154 436;rn  - це данні по температурі
$3 14 1 8 0 5 50 6 0;rn      - пакет основних налаштувань (відправляє рідко раз на 10 хвилин при завантаженні чи при зміні)
спосіб розшифрування  видно у коді программи далі

де перша цифра номер пакету далі данні.

ТН приймає пакет основних налаштувань
$1 14 1 8 0 5 50 6 0;rn  - це основні налаштування. (як розшифрувати видно у коді)
$2 1;rn                            - увімкнення вимкнення ТН (не працює без заміни мк)
$3 3;rn                            - перемикання режиму ТН   (не працює без заміни мк)


оновлений код опублікую після повного тестування.
також вона може працювати з іншими mqtt брокерами наскільки я розумію.

скрин

esphome:
  name: tn-steel
  friendly_name: TN_steel

esp8266:
  board: esp01_1m

# Enable logging
logger:
  baud_rate: 0
  
# Enable Home Assistant API
#api:
#  encryption:
#    key: "uXYp2/3SlC38i/Cxg/7DjXYwRf/5T7G9i89drS/Xciw="
mqtt:
  id: TN_STEELMQTT
  broker: !secret mqtt_host 
  username: !secret mqtt_username
  password: !secret mqtt_password

ota:
  - platform: esphome
    password: "7e3b09c29591a4ec725addad6dcf4204"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Tn-Steel Fallback Hotspot"
    password: "JsvITClu5byI"

# UART
uart:
  - id: uart_1
    tx_pin: 1
    rx_pin: 3
    baud_rate: 115200
    debug:
      direction: BOTH
      dummy_receiver: true
      after:
        delimiter: ";rn"
      sequence:
        - lambda: |-
            UARTDebug::log_string(direction, bytes);
            int sensorID = 0;
            float sensor1 = 0, sensor2 = 0, sensor3 = 0, sensor4 = 0, sensor5 = 0, sensor6 = 0, sensor7 = 0, sensor8 = 0;
            std::string str(bytes.begin(), bytes.end());

            if (sscanf(str.c_str(), "$%d %f %f %f %f %f %f %f %f", 
              &sensorID, &sensor1, &sensor2, &sensor3, &sensor4, &sensor5, &sensor6, &sensor7, &sensor8) >= 6) {
              if (sensorID == 2) {
                id(temp_ulica).publish_state(sensor1 * 0.1);
                id(temp_dom).publish_state(sensor2 * 0.1);
                id(temp_pod).publish_state(sensor3 * 0.1);
                id(temp_hlad).publish_state(sensor4 * 0.1);
                id(temp_celevaya).publish_state(sensor5 * 0.1);
              } else if (sensorID == 1) {
                id(rele_kompressora).publish_state(sensor1>0.5);
                id(rele_4x_wey).publish_state(sensor2);
                id(rele_fan).publish_state(sensor3);
                id(rele_heat_kab).publish_state(sensor4);
                id(rele_ten2kw).publish_state(sensor5);
                id(rele_TEN4kW).publish_state(sensor6);
                id(rele_gazkot).publish_state(sensor7);
                id(rele_nasos).publish_state(sensor8);
              } else if (sensorID == 3) {
                id(ftzad).publish_state(sensor1*0.5+15);
                id(p_kotla).publish_state(sensor2*2);
                id(gradtn).publish_state(sensor3*1-20);
                id(vspom).publish_state(sensor4);
                id(regim).publish_state(sensor5);
                if (sensor5 == 1) {
                id(select_option).publish_state("TN");
                } else if (sensor5 == 2) {
                id(select_option).publish_state("TN+EK");
                } else if (sensor5 == 3) {
                id(select_option).publish_state("EK");
                } else if (sensor5 == 4) {
                id(select_option).publish_state("TN+GAZ");
                } else if (sensor5 == 5) {
                id(select_option).publish_state("GAZ");
                }
                id(koeffb).publish_state(sensor6);
                id(rleto).publish_state(sensor7);
                id(all_stop).publish_state(sensor8);
                id(on_off_button).publish_state(sensor8 == 1); // Синхронизация кнопки
              }
            }

# Captive Portal
captive_portal:

# Датчики
sensor:
  - platform: template
    name: "T заданная"
    id: "ftzad"
    device_class: temperature
    unit_of_measurement: °C
  - platform: template
    name: "power_EK"
    id: "p_kotla"
  - platform: template
    name: "minimalno_TN"
    id: "gradtn"
  - platform: template
    name: "vspomog_mochnost"
    id: "vspom"
  - platform: template
    name: "Regim_raboty"
    id: "regim"
  - platform: template
    name: "koeficent_b"
    id: "koeffb"
  - platform: template
    name: "leto_zima"
    id: "rleto"
  - platform: template
    name: "T_ulica"
    id: "temp_ulica"
    device_class: temperature
    unit_of_measurement: °C
  - platform: template
    name: "T дом"
    id: "temp_dom"
    device_class: temperature
    unit_of_measurement: °C
  - platform: template
    name: "T подача"
    id: "temp_pod"
    device_class: temperature
    unit_of_measurement: °C
  - platform: template
    name: "T хладагент"
    id: "temp_hlad"
    device_class: temperature
    unit_of_measurement: °C
  - platform: template
    name: "T целевая"
    id: "temp_celevaya"
    device_class: temperature
    unit_of_measurement: °C


# Бинарные датчики
binary_sensor:
  - platform: template
    name: "Включен ТН"
    id: "all_stop"
  - platform: template
    name: "Kompressor"
    id: "rele_kompressora"
  - platform: template
    name: "Fan_TN"
    id: "rele_fan"
  - platform: template
    name: "4_x_wey_walwe"
    id: "rele_4x_wey"
  - platform: template
    name: "Heater_outdor"
    id: "rele_heat_kab"
  - platform: template
    name: "Heater1_indor"
    id: "rele_ten2kw"
  - platform: template
    name: "Heater2_ind"
    id: "rele_TEN4kW"
  - platform: template
    name: "Pomp_cirk"
    id: "rele_nasos"
  - platform: template
    name: "Gas_heater"
    id: "rele_gazkot"

# Выключатель
switch:
  - platform: template
    name: "Выключатель ТН"
    id: on_off_button
    optimistic: true
    on_turn_on:
      - uart.write: 
          id: uart_1
          data: "$2 1;rn"
    on_turn_off:
      - uart.write: 
          id: uart_1
          data: "$2 0;rn"

# Выпадающий список
select:
  - platform: template
    name: "Режим"
    id: select_option
    options:
      - "TN"
      - "TN+EK"
      - "EK"
      - "TN+GAZ"
      - "GAZ"
    optimistic: true
    on_value:
      - lambda: |-
          if (x == "TN") {
            id(uart_1).write_str("$3 1;rn");
          } else if (x == "TN+EK") {
            id(uart_1).write_str("$3 2;rn");
          } else if (x == "EK") {
            id(uart_1).write_str("$3 3;rn");
          } else if (x == "TN+GAZ") {
            id(uart_1).write_str("$3 4;rn");
          } else if (x == "GAZ") {
            id(uart_1).write_str("$3 5;rn");}

# Скрипты
script:
  - id: send_interval
    then:
      - uart.write:
          id: uart_1
          data: "$2 1;rn"
      - delay: 1s
      - uart.write:
          id: uart_1
          data: "$2 0;rn"

  - id: send_uart_command
    then:
      - lambda: |-
          if (id(select_option).state == "TN") {
            id(uart_1).write_str("$3 1;rn");
          } else if (id(select_option).state == "TN+EK") {
            id(uart_1).write_str("$3 2;rn");
          } else if (id(select_option).state == "EK") {
            id(uart_1).write_str("$3 3;rn");
          } else if (id(select_option).state == "TN+GAZ") {
            id(uart_1).write_str("$3 4;rn");
          } else if (id(select_option).state == "GAZ") {
            id(uart_1).write_str("$3 5;rn");}

# Интервалы
#interval:
#  - interval: 55s
#    then:
#      - script.execute: send_interval
#
#  - interval: 60s
#    then:
#      - script.execute: send_uart_command

    
    

Підвал форуму