#define BLYNK_PRINT Serial //Blynk+MeteoControl
#include <BlynkSimpleEsp8266.h>
#include <ArduinoOTA.h> // Для прошивки по вафле
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <ESP8266_LCD_1602_RUS.h>
// раздефайнить или задефайнить для использования
#define DEBUG_ENABLE
#ifdef DEBUG_ENABLE
#define DEBUG(x) Serial.println(x)
#else
#define DEBUG(x)
#endif
LCD_1602_RUS lcd(0x27, 16, 2);
#define SEALEVELPRESSURE_HPA (1013.25) //Blynk+MeteoControl
Adafruit_BME280 bme; // I2C
String spaces = "                ";
char auth[] = "***********";
char* ssid[] = {"*****","**********"};
char* pass[] = {"*******","*********"};
bool isFirstConnect=true;
float MyH, MyP, MyT, MyCO2;
long my_timer;
int attempt_conect_count, MyStatus=1;
BlynkTimer timer;
WidgetRTC rtc;
void setup() {
  DEBUG("Tigran-Setup");
  // D1,D2 - I2C by BME280-Module
  ArduinoOTA.setHostname("Mini_CO2_LCD");
  ArduinoOTA.begin();
  MultyWiFiBlynkBegin();
  timer.setInterval(3000, UpdateLCD);
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)
  if (!bme.begin()) {DEBUG("Could not find a valid BME280 sensor, check wiring!");}
  my_timer = millis();
  Serial.begin(9600);         // открыть порт
  lcd.init();                 // инициализация дисплея
  lcd.backlight();            // включить подсветку
}
void loop() {
  ArduinoOTA.handle();
  if (Blynk.connected()) {
    Blynk.run();
    my_timer = millis(); // "сбросить" таймер
    attempt_conect_count=0;  // "сбросить" счетчик попыток перподключиться
  } else {
    if (millis() - my_timer > 60*1000) { // Таймер чтобы не чаще чем раз в 60 сек. пытался законектиться
      DEBUG("Потерена связь с Блянком, делаю повторную попытку");
      Blynk.run();
      if (!Blynk.connected()) {
        DEBUG("Нет результата пробую преподключться... попытка №"+String(attempt_conect_count));
        MultyWiFiBlynkBegin(); //
        attempt_conect_count++;
        if (attempt_conect_count>3) {ESP.deepSleep(1e6);} //Заснуть на 1 сек. (Перегрузить)
      }
      my_timer = millis();   // "сбросить" таймер
    }
  }
  timer.run();
}
void UpdateLCD() {
  //BME280 (Temperature, Pressure, Humidity)
  MyT=bme.readTemperature()+0.7;
  DEBUG("Temperature = " + String(MyT) + " *C");
  MyP=bme.readPressure() / 100.0F *0.750062;
  DEBUG("Pressure = " + String(MyP) + " mmHg");
  MyH=bme.readHumidity();
  DEBUG("Humidity = " + String(MyH) +" %");
  Blynk.virtualWrite(V1,MyT); //LED Widget status
  Blynk.virtualWrite(V2,MyH); //LED Widget status
  Blynk.virtualWrite(V3,MyP); //LED Widget status
  //MHZ-Z19 (PPM CO2)
  #define mySerial Serial // Serial битрейд обязтельно 9600!!!
  static byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; //команда чтения
  byte response[9];
  byte crc = 0;
  while (mySerial.available())mySerial.read();//очистка буфера UART перед запросом
  memset(response, 0, 9);// очистка ответа
  mySerial.write(cmd,9);// запрос на содержание CO2
  mySerial.readBytes(response, 9);//читаем 9 байт ответа сенсора
  //расчет контрольной суммы
  crc = 0;
  for (int i = 1; i <= 7; i++)  {crc += response[i];}
  crc = ((~crc)+1);
  if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) )  {   //проверка CRC
    DEBUG("CRC error");
  }else{
     //расчет значеия CO2
     MyCO2 = (((unsigned int) response[2])<<8) + response[3];
     DEBUG("CO2: " + String(MyCO2) + "PPM");
     Blynk.virtualWrite(V4,MyCO2); //LED Widget status
  }
  delay(50);
  lcd.setCursor(0, 0);
  lcd.print(spaces);    // очищаем цифры с прошлого вывода
  lcd.setCursor(0, 0);        // курсор слева 1 строчка
  lcd.print("СО2: ");
  lcd.setCursor(5, 0);  // курсор,строчка
  lcd.print(String(MyCO2) + " PPM");
  switch (MyStatus) {
  case 1:
    lcd.setCursor(0, 1);        // курсор слева 2 строчка
    lcd.print(spaces);    // очищаем цифры с прошлого вывода
    lcd.setCursor(0, 1);        // курсор слева 2 строчка
    lcd.print("Температура: ");
    lcd.setCursor(12, 1); // курсор,строчка
    lcd.print(String(MyT));  
    MyStatus=2;
    break;
  case 2:
    lcd.setCursor(0, 1);        // курсор слева 2 строчка
    lcd.print(spaces);    // очищаем цифры с прошлого вывода
    lcd.setCursor(0, 1);        // курсор слева 2 строчка
    lcd.print("Влажность: ");
    lcd.setCursor(11, 1); // курсор,строчка
    lcd.print(String(MyH) + "%");  
    MyStatus=3;
    break;
  case 3:
    lcd.setCursor(0, 1);        // курсор слева 2 строчка
    lcd.print(spaces);    // очищаем цифры с прошлого вывода
    lcd.setCursor(0, 1);        // курсор слева 2 строчка
    lcd.print("Давление: ");
    lcd.setCursor(10, 1); // курсор,строчка
    lcd.print(String(MyP));  
    MyStatus=1;
    break;  
  }
}
void MultyWiFiBlynkBegin() {
  int ssid_count=0;
  int ssid_mas_size = sizeof(ssid) / sizeof(ssid[0]);
  do {
    DEBUG("Trying to connect to wi-fi " + String(ssid[ssid_count]));
    WiFi.begin(ssid[ssid_count], pass[ssid_count]);  
    int WiFi_timeout_count=0;
    while (WiFi.status() != WL_CONNECTED && WiFi_timeout_count<20) { //waiting 5 sec (Если делать больше 5 сек. и нет вайфая он вываливаеться с ошибкоой!)
      delay(500);
      Serial.print(".");
      ++WiFi_timeout_count;
    }
    if (WiFi.status() == WL_CONNECTED) {
      DEBUG("Connected to WiFi! Now I will check the connection to the Blynk server");
      Blynk.config(auth);
      Blynk.connect(5000); //waiting 5 sec
    }
    if (ssid_count<ssid_mas_size) {DEBUG("Next SSID");}
    ++ssid_count;
  }
  while (!Blynk.connected() && ssid_count<ssid_mas_size);
  if (!Blynk.connected() && ssid_count==ssid_mas_size) {
    DEBUG("I could not connect to blynk =( Ignore and move on. but still I will try to connect to wi-fi " + String(ssid[ssid_count-1]));
  }
}
BLYNK_CONNECTED() {
  if (isFirstConnect) {} //При первом запуске
  isFirstConnect = false;
  rtc.begin(); // Synchronize time on connection
  DEBUG("BLYNK_CONNECTED syncVirtual ports");
  Blynk.syncVirtual(V0);
}