//08:3A:F2:A7:80:6C //esp32 желтые ноги
//08:3A:F2:66:31:30 //esp32 lilygo2,3
//08:3A:F2: //esp32 lilygo4,7
//EC:94:CB:6C:EC:A4  esp32 самоделка
//SD Карта подкл к любым ногам SPI железный H_SPIClass sdSPI(HSPI); или V_ SPIClass sdSPI(VSPI);
#define SD_MISO     23
#define SD_MOSI     13
#define SD_SCLK     14
//#define SD_CS       15
#define SD_CS       2

#include <esp_task_wdt.h>
#define WDT_TIMEOUT 30
#include <WiFi.h>
#include <AsyncTCP.h>
#include "ESPAsyncWebSrv.h"
#include <esp_now.h>
#include "SPI.h"
#include <SPIFFS.h>
#include <esp_task_wdt.h>
#include "NTPClient.h"
#include "WiFiUdp.h"
#include <Arduino_JSON.h>

#include "FS.h"
#include "SD.h"
#include <UnixTime.h>
UnixTime stamp(0);  // указать GMT (3 для Москвы)
// Define deep sleep options
String dataMessage;
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
#include "RTClib.h"
RTC_DS3231 rtc;
#include "nRF24L01.h"
#include "RF24.h"
#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

char msg[16];
//RF24 radio(12, 14, 26, 25, 27);
//RF24 radio(27, 26, 32, 33, 25);//server (ce,csn,sck,miso,mosi)esp32
//gpio19
RF24 radio(17, 16, 32, 33, 25);//server (ce,csn,sck,miso,mosi)esp32

const uint64_t pip = 0x02E423E4E2LL;
SPIClass sdSPI(HSPI);
File myFile;

const char* ssid = "VOVA-47";
const char* password = "vovak26102003";

const int LED_PIN = 2;

AsyncWebServer server(80);
AsyncWebSocket webSocket("/ws");

int ledState = LOW;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Задайте свой статический IP-адрес
IPAddress local_IP(192, 168, 1, 115);
// Укажите IP-адрес шлюза
IPAddress gateway(192, 168, 1, 1);

IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(8, 8, 8, 8);   // опционально
IPAddress secondaryDNS(8, 8, 4, 4); // опционально


//****************************************************************************
// ntp
int countTimeWas;
int countVal;
int countVal1;
String formattedDate;
String formattedTime;
String dayStamp;
String timeStamp;
String timerweek="{\"id\":\"week\",\"timer1_week\":\"0111100\",\"timer2_week\":\"1000011\",\"timer3_week\":\"0101010\"}";
bool tweek; // флаг обновления строки timerweek для записи на SD
String timerdata="{\"timer1\":[\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\"],\"timer2\":[\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\"],\"timer3\":[\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\",\"00:00\"]}";//данные с таймеров
bool tdat=0;// флаг обновления строки timerdat для записи на SD
String timerout="{\"id\":\"tout\",\"t1\":\"011\",\"t2\":\"100\",\"t3\":\"010\"}";//подключние таймеров т1 т2 и т3 к выходам gpio4,gpio26,gpio27
bool tout=0;// флаг обновления строки timerout для записи на SD
bool ntp_on=0;
//**************************JSON***************************************************
JSONVar board;
JSONVar board1;
JSONVar board2;
JSONVar board3;
JSONVar board4;
JSONVar board5;

//String jsonString="{\"id\":\"0\",\"temperature\":\"9.67\",\"humidity\":50.41815185546875,\"tim2\":\"10:10\",\"tim3\":\"11:11\",\"dataserv\":\"12\",\"timeserv\":\"15:30\",\"munthserv\":\"январь\",\"weekserv\":\"среда\"}";
String jsonString="{\"id\":\"0\",\"temperature\":9.6757548,\"humidity\":50.41815185546875,\"tim2\":\"10:10\",\"tim3\":\"11:11\",\"dataserv\":\"12\",\"munthserv\":\"январь\",\"weekserv\":\"среда\"}";
String jsonString1;
String jsonString2="{\"id\":\"2\",\"tkom1\":\"20.0\",\"hkom1\":\"30.0\",\"batkom1\":\"4.10\",\"timekom1\":\"07:08\",\"tkom2\":\"20.5\",\"hkom2\":\"80.5\",\"batkom2\":\"3.95\",\"timekom2\":\"15:15\",\"tkor\":\"23.5\",\"hkor\":\"90.5\",\"batkor\":\"3.75\",\"timekor\":\"13:13\",\"tbal\":\"13.5\",\"hbal\":\"80.5\",\"batbal\":\"3.45\",\"timebal\":\"11:11\",\"tul1\":\"7.3\",\"hul1\":\"75.5\",\"osv1\":\"50\",\"timeul1\":\"12:12\"}";
String jsonStringout= "{\"id\":\"out\",\"out1\":\"1011\"}";// 0-выкл  1-вкл вых1 вых2 вых3 таймер(работаем по кнопкам или по таймеру
String jsonString77="{\"Time\":\"0:17\",\"temperatura\":\"19.73 C\",\"humidity\":\"73.59 %\"}\n{\"Time\":\"0:37\",\"temperatura\":\"19.65 C\",\"humidity\":\"74.34 %\"}\n{\"Time\":\"0:57\",\"temperatura\":\"19.57 C\",\"humidity\":\"74.99 %\"}";
String jsonStringakva="{\"id\":\"akva\",\"tempakv1\":\"20,1\",\"light1\":\"80 %\",\"timakv1\":\"12.31\",\"fan1\":\"OFF\",\"tempakv2\":\"20,2\",\"light2\":\"82 %\",\"timakv2\":\"12.32\",\"fan2\":\"OFF\",\"tempakv3\":\"20,3\",\"light3\":\"83 %\",\"timakv3\":\"12.33\",\"fan3\":\"OFF\"}";
//String jsonString77="{\"id\":\"77\",\"Time\":\"21:23\",\"temperatura\":\"8.88 C\",\"humidity\":\"90.97 %\"}\n";
//String jsonString78="{\"id\":\"77\",\"data\":\'\"Time\":\"21:23\",\"temperatura\":\"8.88 C\",\"humidity\":\"90.97 %\"\'}";
//{"timer1":["00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00"],"timer2":["00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00"],"timer3":["00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00","00:00"]}
//String jsonString7="{\"id\":\"week\",\"timer1_week\":\"0111100\",\"timer2_week\":\"1000011\",\"timer3_week\":\"0101010\"}";
//****************************************************************************
int idcon=0;// ID соединения
//*************************************************************************************************
char* strd[] = {"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"};
  char* strm[] = {"январь","февраль","март","апрель","май","июнь","июль","август","сентябрь","октябрь","ноябрь","декабрь"};
  char* strweek[] = {"воскресенье","понедельник","вторник","среда","четверг","пятница","суббота","воскресенье"};
 int nt=0;//номер термометра
  int nti=0;//номер термометра для сайта
 int temperature1=10;
 String ts;
 String hs;
String t1;
 String h1;
   String t10;//время работы сервера
    String tim3;// время от нтп сервера  при приходе данных с NOW
    String tim2;//время  получ от устройства NOW
     String batz;//заря бат термометра ул запад
    String munthserv;//месяц
    String weekserv;//день недели
    String timer1;//таймер1
    String timer2;//таймер2
    int timerbut1=0;
    int timerbut2=0;
bool tbut1=0;//флаг таймера1
bool tbut2=0;//флаг таймера2
bool res = 0;//флаг разрешения сброса
int timebut=0;// подсчет времени по таймерам

String tkom1;//температура
String hkom1;//влажность
String batkom1;
String timekom1;//время прихода данных комната1

String tkom2;
String hkom2;
String batkom2;
String timekom2;

String tkor;
String hkor;
String batkor;
String timekor;

String tbal;
String hbal;
String batbal;
String timebal;

String timeul1;
String tul1;
String hul1;
String osv1;

String takva1;
String takva2;
String takva3;
String timeakva;
String light;
String fan1;
String fan2;
String fan3;
bool fanak1;
bool fanak2;
bool fanak3;
int lightakv=80;
bool akva=0;//флаг прихода дааных с акваконрол

int ct1=0;//счетчик пропуска данные каждые 3 минуты записываем каждые 20 те 7 пропусков
int wreset=0;//счетчик времени сброса esp(1 раз в 8 часов)
 String out1;//выход1 gpio4
  String out2;//выход2 gpio26
   String out3;//выход3 gpio27
 int tweekday=1;//день недели для таймеров   
 int time17=0;
int hour1=10;
int min1=7;
int sek=0;
int year1;
int month1;
int data1;
int hk=0;//часы для исключения повтора записи данных
int mk=0;//минуты
int hb=0;//часы для исключения повтора записи данных
int mb=0;//минуты
int hkr=0;//часы для исключения повтора записи данных
int mkr=0;//минуты
int timev=0;//для пропуска 20 минут
//String timev1;//для записи на флэш при сбросе
bool outdata=0;//флаг обновления состояния выходов
boolean fdata=0;//флаг обновления данных темп и влажн
int fobnov=1;//флаг обновления данных темп и влажн
String timeserv;//время сервера
String dataserv;//дата
int v=0;
int v1=0;
long EpochTime=0;
 int ind=0;

 String strdat;//накопленые в памяти данные по темп и влажность передаваемые клиенту
  String tempdat;//
int ftdata=0;//флаг запроса данных темп и влажн
int fping=0;// флаг для задержки отр данных на страницу inform
int wright=0;
bool flread=0;
 char* strden[] = {"/01","/02","/03","/04","/05","/06","/07","/08","/09","/10","/11","/12","/13","/14","/15","/16","/17","/18","/19","/20","/21","/22","/23","/24","/25","/26","/27","/28","/29","/30","/31"};  
 char* strmen[] = {"/JAN","/FEBR","/MARCH","/APRIL","/MAY","/JUNE","/JULY","/AUG","/SEPT","/OCT","/NOV","/DEC"};
 char* stryen[] = {"/2014","/2015","/2016","/2017","/D-2018","/D-2019","/D-2020","/D-2021","/D-2022","/D-2023","/D-2024","/D-2025","/D-2026","/D-2027","/D-2028","/D-2029","/D-2030","/D-2031","/D-2032","D-2033","/D-2034","/D-2035"};
 char* strdaten[] = {"/T1.txt","/T2.txt","/T3.txt","/T4.txt","/T5.txt","/T6.txt","/T7.txt","/T8.txt","/T9.txt","/T10.txt"};
//************************************************************
//************************************************************
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
volatile uint32_t isrCounter = 0;
volatile uint32_t lastIsrAt = 0;
  char *time_buf;
//*****************************************************************************

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
  int id;
  float temp;
  float hum;
  unsigned int readingId;
  unsigned int bat;
} struct_message;
int volt11;
struct_message incomingReadings;
//****************************************Timer Budilnik***************************************************************************************************************************************************************************************** 
int minuta;//счетчик минут для проверки времени сработки будильников
uint16_t BTimer1 [11] = {2, 390, 450, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440}; // массивы всех таймеров для суточных каналов (1 - 4) 0-й элемент отвечает за состояние канала (1 - вкл/ 0 - выкл/ 2 - авто))
uint16_t BTimer2 [11] = {2, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440}; // остальное время в минутах (нечетные элементы - таймеры включения, четные - выключения)
uint16_t BTimer3 [11] = {2, 380, 450, 1080, 1410, 1440, 1440, 1440, 1440, 1440, 1440}; // время 1440 отображается на экране как "--:--", это неактивное значение, для основной логики пустая ячейка означает что таймер не задан
uint16_t weekTimer1 [7]={0,0,0,0,0,0,0};//недельные установки t1
uint16_t weekTimer2 [7]={0,0,0,0,0,0,0};//недельные установки t2
uint16_t weekTimer3 [7]={0,0,0,0,0,0,0};//недельные установки t3
uint16_t gpioTimer1 [3]={1,0,0};//выходы подкл к таймеру {gpio 4, gpio 26, gpio 27} {1,0,0} подкл 4
uint16_t gpioTimer2 [3]={1,0,0};//выходы подкл к таймеру  {gpio 4, gpio 26, gpio 27} {0,0,0} откл все
uint16_t gpioTimer3 [3]={0,0,0};//выходы подкл к таймеру  {gpio 4, gpio 26, gpio 27}{1,1,1} подкл все
uint16_t gpio[4]={0,0,0,1};//выходы состояние {gpio 4, gpio 26, gpio 27, timer}{1,1,1,1} timer определяет работу выходов по таймеру=1 или кнопки =0
bool state1 = 0;  //_________________Переменные состояния каналов(вкл/выкл)
bool state2 = 0;
bool state3 = 0;
uint16_t current_time = 0 ; //_______Текущее время в минутах (для основных расчетов)
//*********************************************************************************************
const char* PARAM_INPUT_1 = "output";//Gpio
const char* PARAM_INPUT_2 = "state"; //состояние выхода
const char* PARAM_INPUT = "value";

const int output = 4;
const int output1 = 26;
const int output2 = 27;
String ledout;
void IRAM_ATTR onTimer();
//***********************************************************
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) { 
  // Copies the sender mac address to a string
  char macStr[18];
  Serial.print("Packet received from: ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
   Serial.println(macStr);
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  
  Serial.printf("Board ID %u: %u bytes\n", incomingReadings.id, len);
  Serial.printf("t value: %4.2f \n", incomingReadings.temp);
  t1 = incomingReadings.temp;
  Serial.printf("h value: %4.2f \n", incomingReadings.hum);
  h1=incomingReadings.hum;
  Serial.printf("readingID value: %d \n", incomingReadings.readingId);
  int tim11 =incomingReadings.readingId;
  hour1=tim11/100;
  min1=tim11%100;
  volt11 =incomingReadings.bat;//заряд батареи
  Serial.printf("bat value: %d \n", incomingReadings.bat);
    

batz=volt11/100;
batz+=",";
batz+=volt11%100;
 
 Serial.println(batz);
  //tim3=timeserv;
  //получаем из int  incomingReadings= 1530 строку 15:30
 
  tim3=incomingReadings.readingId/100;
  tim3+=":";
  if(incomingReadings.readingId%100<10)tim3+="0";
  
  tim3+=incomingReadings.readingId%100;
//JSONстрока формирование
  ntphome();
  flread=1;
JSstringU(); 
  savedata();
  flread=1;
}//OnDataRecv

 //****************************************************************************
//****************************************************************************************************************************************************************************************************************************************************
//подпрогр Действия вебсекета
void handleWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_DISCONNECT://[3] Disconnected! откл соединения
      Serial.printf("[%u] Disconnected!\n", client->id());
      idcon--;
      break;

    case WS_EVT_CONNECT://[4] Connected from 192.168.1.108 подключение
      {
        IPAddress ip = client->remoteIP();//адрес подкл объкта
        Serial.printf("[%u] Connected from %d.%d.%d.%d\n", client->id(), ip[0], ip[1], ip[2], ip[3]);
         idcon++;
        client->text(jsonString);//отправка дата месяц неделя
        client->text(jsonString2);//отправка темп и влажности в комнатах
             String countUpdate2 = "{\"label3\":\"count2\",\"value\":\"" + String(timeserv) + "\"}";//отправка строковой переменной
          String countUpdate = "{\"label3\":\"count\",\"value\":\"" + String(t10) + "\"}";//отправка строковой переменной время раб сервера  
        client->text(countUpdate2);//отправка  NTP времени  timeserv
        client->text(countUpdate);//отправка время раб сервера t10
        if (ftdata==1)//пришел запрос табл данных /inform1 запад
        {ftdata=0;
          nti=1;
          readdata();
          client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр inform
         }
         if (ftdata==2)//пришел запрос табл данных /inform К1
        {ftdata=0;
          nti=4;
          readdata();
          client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр inform
         }
         if (ftdata==3)//пришел запрос табл данных /inform k2
        {ftdata=0;
          nti=3;
          readdata();
          client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр inform
         }        
         if (ftdata==5)//пришел запрос табл данных /inform балкон
        {ftdata=0;
          nti=2;
          readdata();
          client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр inform
         }
         if (ftdata==4)//пришел запрос табл данных /inform корридор
        {ftdata=0;
          nti=5;
          readdata();
          client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр inform
         }
           if (ftdata==10)//пришел запрос табл данных /inform восток
        {ftdata=0;
          nti=0;
          readdata();
          client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр inform
         }
         if (ftdata==6)//пришел запрос табл данных кухня
        {ftdata=0;
         // nti=6;
         // readdata();
         // client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу на стр 
         }
        if (ftdata==12)//пришел запрос /setting передача значений таймера
           {ftdata=0;
           client->text(timerweek);//таймер дни недели
           Serial.println(timerweek);
           
           client->text(timerdata);//timerout
           Serial.println(timerdata);
           
            client->text(timerout);//timerout
           Serial.println(timerout);
           }
           
            if (ftdata==8)//пришел запрос управления upravlenie.html
           {ftdata=0;
            JSstringOut();
           client->text(jsonStringout);// {"id":"out","out1":"1011"} отправляем состояние выходов
           //Serial.println(jsonStringout);
            }
             if (ftdata==7)//пришел запрос управления akva.html
           {ftdata=0;
            JSstringAkva();
           client->text(jsonStringakva);//jsonStringakva="{\"id\":\"akva\",\"tempakv1\":\"20,1\",\"light1\":\"80 %\",\"timakv1\":\"12.31\",\"fan1\":\"OFF\",\"tempakv2\":\"20,2\",\"light2\":\"82 %\",\"timakv2\":\"12.32\",\"fan2\":\"OFF\",\"tempakv3\":\"20,3\",\"light3\":\"83 %\",\"timakv3\":\"12.33\",\"fan3\":\"OFF\"}";
          Serial.println(jsonStringakva);
            }
            
               if (ftdata==15)//пришел запрос управления akva1.html
           {ftdata=0;
            JSstringAkva();
           client->text(jsonStringakva);//jsonStringakva="{\"id\":\"akva\",\"tempakv1\":\"20,1\",\"light1\":\"80 %\",\"timakv1\":\"12.31\",\"fan1\":\"OFF\",\"tempakv2\":\"20,2\",\"light2\":\"82 %\",\"timakv2\":\"12.32\",\"fan2\":\"OFF\",\"tempakv3\":\"20,3\",\"light3\":\"83 %\",\"timakv3\":\"12.33\",\"fan3\":\"OFF\"}";
         // Serial.println(jsonStringakva);
          readakva();
           client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу
            }
                if (ftdata==16)//пришел запрос управления akva1.html
           {ftdata=0;
            JSstringAkva();
           client->text(jsonStringakva);//jsonStringakva="{\"id\":\"akva\",\"tempakv1\":\"20,1\",\"light1\":\"80 %\",\"timakv1\":\"12.31\",\"fan1\":\"OFF\",\"tempakv2\":\"20,2\",\"light2\":\"82 %\",\"timakv2\":\"12.32\",\"fan2\":\"OFF\",\"tempakv3\":\"20,3\",\"light3\":\"83 %\",\"timakv3\":\"12.33\",\"fan3\":\"OFF\"}";
         // Serial.println(jsonStringakva);
          readakva();
           client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу
            }
                if (ftdata==17)//пришел запрос управления akva1.html
           {ftdata=0;
            JSstringAkva();
           client->text(jsonStringakva);//jsonStringakva="{\"id\":\"akva\",\"tempakv1\":\"20,1\",\"light1\":\"80 %\",\"timakv1\":\"12.31\",\"fan1\":\"OFF\",\"tempakv2\":\"20,2\",\"light2\":\"82 %\",\"timakv2\":\"12.32\",\"fan2\":\"OFF\",\"tempakv3\":\"20,3\",\"light3\":\"83 %\",\"timakv3\":\"12.33\",\"fan3\":\"OFF\"}";
          //Serial.println(jsonStringakva);
          readakva();
           client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу
            }
               if (ftdata==18)//пришел запрос управления akva1.html
           {ftdata=0;
           // JSstringAkva();
          // client->text(jsonStringakva);//jsonStringakva="{\"id\":\"akva\",\"tempakv1\":\"20,1\",\"light1\":\"80 %\",\"timakv1\":\"12.31\",\"fan1\":\"OFF\",\"tempakv2\":\"20,2\",\"light2\":\"82 %\",\"timakv2\":\"12.32\",\"fan2\":\"OFF\",\"tempakv3\":\"20,3\",\"light3\":\"83 %\",\"timakv3\":\"12.33\",\"fan3\":\"OFF\"}";
          //Serial.println(jsonStringakva);
          readakva();
           client->text(strdat.c_str());//отправка суточных данных данных из карты памяти в таблицу
            }
   
     }
      break;

     case WS_EVT_DATA:
      {
        AwsFrameInfo *info = (AwsFrameInfo*)arg;
        if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
          data[len] = '\0';
          String payload = String((char*)data);

          Serial.printf("[%u] Received: %s\n", client->id(), payload.c_str());

          if (payload == "toggle") {//если пришло toggle
            
          }else{                               //{"id":"week","timer1_week":"0111100","timer2_week":"1000011","timer3_week":"0101010"}
            String js = payload.substring(1,11);//"id":"week"  вырезаем нужные данные  {"ido":"4","out":1}
           // Serial.println(js);
            if((js[1] = 'i')&&(js[6]=='w'))
            {timerweek=payload;
            tweek=1;
            }
            if((js[1] = 'i')&&(js[6]=='t'))// "id":"tout","t1":"100","t2":"010","t3":"001"
            {timerout=payload;
             Serial.println(timerout);
            tweek=1;
            }
            if((js[1] = 't')&&(js[6]=='1'))//{"timer1":["08:00","09:00","10:00","11:00","12:00","13:00","14:00","15:00","16:00","17:00"],"timer2":["09:30","10:30","11:30","12:30","13:30","14:30","15:30","16:30","17:30","18:30"],"timer3":["10:15","11:15","12:15","13:15","14:15","15:15","16:15","17:15","18:15","19:15"]}
            {timerdata=payload;
            //Serial.println(timerdata);
            tdat=1;//флаг разрешения парсинга строки и ее записи на SD
            }
           // Serial.println(js);
            if((js[1] = 'i')&&(js[3]=='o'))//{"ido":"4","out":"1"} переключение выхода
            {ledout=payload;
            //Serial.println(ledout);
            outconvert();// получен данные преобразуем в массив gpio[4]={0,0,0,1}
            JSstringOut();//преобразуем состояние выходов gpio[4]={0,0,0,1} в JSON {"id":"out","out1":"1011"}
            webSocket.textAll(jsonStringout);// выводим всем клиентам w/s
              btime(); 
            }
          }


          
        }
      }
      break;
  }
}


void setup() {
   pinMode(2, OUTPUT);
   pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
    pinMode(26, OUTPUT);
  digitalWrite(26, LOW);
    pinMode(27, OUTPUT);
  digitalWrite(27, LOW);
     pinMode(5, OUTPUT);
  digitalWrite(5, LOW);
   pinMode(19, OUTPUT);
  digitalWrite(19, HIGH);
     delay(500);
digitalWrite(19, LOW);

  Serial.begin(115200);
  //pinMode(LED_PIN, OUTPUT);
 rtc.begin(); 
 
 // digitalWrite(2, LOW);
  digitalWrite(2, HIGH);
  Serial.println(WiFi.macAddress());

   sdSPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
  if (!SD.begin(SD_CS, sdSPI))
  {
    // if(!SD.begin()){
    Serial.println("Mounting card mount failed");
   // return;
  }


 
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    //return;
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);

  
if(!SPIFFS.begin()){
    Serial.println("An Error has occurred while mounting SPIFFS");
    //return;
  }


 Nrfsetup(); 
//settimer();//таймер отсчета времени настр на 5 сек
  WiFisetup();
  timeClient.begin();

 timeClient.setTimeOffset(10800);  


// ntp();//NTP init
/*current_time = hour1 * 60 + min1;
for (int i = 0; i <= 1439; i++) {
  if (current_time > 1439) current_time = 0;
  state1 = main_log(BTimer1, state1);
  state2 = main_log(BTimer2, state2);
  state3 = main_log(BTimer3, state3);
//  state4 = main_log(Timer4, state4);
  current_time++;
}
btime();
*/
timedate();
 Sdreaddata();
  Sdread(); 
 mySwitch.enableTransmit(22);
 //mySwitch.send("000000000001010100010011");
 //mySwitch.send("000000000001010100010001");
 esp_now_register_recv_cb(OnDataRecv);


 //*******************server******************************************************************
// server.on("/", HTTP_GET, handleRoot);
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html");
  });
  server.on("/index.html", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html");
  });
   // Route to load style.css file
  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/style.css", "text/css");
  });
   server.on("/fon.jpg", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/fon.jpg");
  });
//*****************************************************************************************************  
server.on("/upravlenie.html", HTTP_GET, [](AsyncWebServerRequest *request){
    fobnov=1;
    ftdata=8;
    request->send(SPIFFS, "/upravlenie.html", String(), false, processor);
  });
 
  //****************************************************************************************************************
   server.on("/setting.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=12;
   request->send(SPIFFS, "/setting.html");
  });
    server.on("/inform.html", HTTP_GET, [](AsyncWebServerRequest *request){
      ftdata=10;
    request->send(SPIFFS, "/inform.html");
  });
   server.on("/informtabl.html", HTTP_GET, [](AsyncWebServerRequest *request){
      ftdata=10;
    request->send(SPIFFS, "/informtabl.html");
  });

     server.on("/inform1.html", HTTP_GET, [](AsyncWebServerRequest *request){
      ftdata=1;
    request->send(SPIFFS, "/inform1.html");
  });
      server.on("/informtabl1.html", HTTP_GET, [](AsyncWebServerRequest *request){
      ftdata=1;
    request->send(SPIFFS, "/informtabl1.html");
  });

   server.on("/inform2.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=2;
    request->send(SPIFFS, "/inform2.html");
  });
   server.on("/informtabl2.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=2;
    request->send(SPIFFS, "/informtabl2.html");
  });
   server.on("/inform3.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=3;
    request->send(SPIFFS, "/inform3.html");
  });
    server.on("/informtabl3.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=3;
    request->send(SPIFFS, "/informtabl3.html");
  });
   server.on("/inform4.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=4;
    request->send(SPIFFS, "/inform4.html");
  });
  server.on("/informtabl4.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=4;
    request->send(SPIFFS, "/informtabl4.html");
  });
   server.on("/inform5.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=5;
    request->send(SPIFFS, "/inform5.html");
  });
   server.on("/informtabl5.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=5;
    request->send(SPIFFS, "/informtabl5.html");
  });
   server.on("/inform6.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=6;
    request->send(SPIFFS, "/inform6.html");
  });
   server.on("/informtabl6.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=6;
    request->send(SPIFFS, "/informtabl6.html");
  });

   server.on("/akva1.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=15;
    request->send(SPIFFS, "/akva1.html");
  });
  
   server.on("/akva2.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=16;
    request->send(SPIFFS, "/akva2.html");
  });
   server.on("/akva3.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=17;
    request->send(SPIFFS, "/akva3.html");
  });
   server.on("/akvadat.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=18;
    request->send(SPIFFS, "/akvadat.html");
  });
  server.on("/akvagraf.html", HTTP_GET, [](AsyncWebServerRequest *request){
    ftdata=18;
    request->send(SPIFFS, "/akvagraf.html");
  });
   server.on("/timer.html", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/timer.html", String(), false, processor);
  });
    server.on("/akva.html", HTTP_GET, [](AsyncWebServerRequest *request){
     ftdata=7;
    request->send(SPIFFS, "/akva.html");
  });
  
    server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){   
    request->send(SPIFFS, "/favicon.ico");
  });
    server.on("/favicon-32x32.png", HTTP_GET, [](AsyncWebServerRequest *request){    
    request->send(SPIFFS, "/favicon-32x32.png");
  });
   server.on("/favicon-16x16.png", HTTP_GET, [](AsyncWebServerRequest *request){   
    request->send(SPIFFS, "/favicon-16x16.png");
  });
//********************************************************************************************************
JSstringU();
JSstringK();
  server.addHandler(&webSocket);
  webSocket.onEvent(handleWebSocketEvent);

  server.begin();
  esp_task_wdt_init(WDT_TIMEOUT, true); //включить панику, чтобы ESP32 перезапустился
 esp_task_wdt_add(NULL); //добавить текущий поток в WDT watch

}







void loop() {

   // Send data to browser, increasing number every second.
  if (millis() - countTimeWas >= 1000) {
    countTimeWas = millis();
    countVal++;//cчетчик до перезапуска сервера
    countVal1++;
    v++;
    v1++;
     if (idcon>0)// если есть подключения
      { String countUpdate1 = "{\"label3\":\"count1\",\"value\":" + String(countVal1) + "}";//отправка числовой переменной
        webSocket.textAll(countUpdate1);//обновление ws
         if((tdat==1)||(tweek==1))//есть новые данные для установок таймера
         {timerconvert();
          gpio[3]=1;//управление выходами передаем таймеру
             writeFile(SD, "/timerd.txt", timerdata.c_str());//записываем в этот файл значения для таймера
             writeFile(SD, "/week.txt", timerweek.c_str());//записываем в этот файл значения недельного таймера
             writeFile(SD, "/tdout.txt", timerout.c_str());//записываем в этот файл значения выходов к кот подкл таймер
    //timerout= {"id":"tout","t1":"100","t2":"010","t3":"001"}
         }
      }
     
          
         // Serial.println(countUpdate1);

   
    
   if (v1>3600) {//60min-
    delay(0);
    sdsave();// записываем на СД необходимые данные
    delay(0);
   ntp();//считываем время
   v1=0;//обнуляем счетчик =3600с
    delay(0);
  }
//**************20sek*******************************
 if (v>19){//20sek
   JSstringU();
   JSstringK();
   JSstringOut();
 
 
  if((ntp_on==0)&&(idcon==0))
  {if((hour1==8)&&(min1==15))ntp();//синхронизация времени с NTP
  
  if((hour1==8)&&(min1>18)) ntp_on==1; //если NTP не отвечает прекращаем до следующего дня
  }
 
 
 
 
   if((res==1)&&(idcon==0))//idcon=0  клиентов нет
   {
   sdsave();// записываем на СД необходимые данные
   ESP.restart(); //перезагрузка сервака
   }
   
   res=0;  
   ntphome();//считываем время с esp32
   nrf(); //проверяем не приш ли данные на NRF
 Serial.print ("idcon=");
  Serial.println (idcon);
   v=0;//обнуляем счетчик 4*5=20с
   delay(0);
   vrem();//время работы сайта
 btime();//проверка сработки таймеров
 
    
   if (idcon>0)// если есть подключения
     {    webSocket.textAll(jsonString);//{"id":"0","temperature":12.456787109375,"humidity":77.456787109375,"tim2":"18:15","ti
         Serial.println(jsonString);
         webSocket.textAll(jsonString2);//{"id":"2","tkom1":"20.0","hkom1":"30.0","batkom1":"4.10","timekom1"
         Serial.println(jsonString2);
      
      String countUpdate = "{\"label3\":\"count\",\"value\":\"" + String(t10) + "\"}";//отправка строковой переменной время раб сервера
             webSocket.textAll(countUpdate);
             Serial.println(countUpdate);
             delay(0);
       String countUpdate2 = "{\"label3\":\"count2\",\"value\":\"" + String(timeserv) + "\"}";//отправка строковой переменной врем NTP
             webSocket.textAll(countUpdate2);
            Serial.println(countUpdate2);
     }
  }
//**************20sek end*******************************
  
 if((countVal>3600*2)&&(idcon==0))//прошло более 2 часов и нет подкл клиентов
 { if(hour1!=3)res=1;//разрешение на перезагрузку сервака
  
 }
 
 
 
 

  }
  esp_task_wdt_reset();//reset WDT сброс вотчдога
}
