Код:
#include <WiFi.h>
#include <Wire.h>
#include <ArduinoJson.h>
#include "time.h"
#include "Adafruit_BME280.h"
#include <HTTPClient.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

//#define I2C_SDA 4
//#define I2C_SCL 5
#define LED_PIN 2
#define BME280_ADDRESS 0x76

char buffer [256];
char server[] = "smtpcorp.com"; // smtp сервер сайта smtp2go для отправки через него емэйла
int port = 2525;

char login[] = "*****@gmail.com"; // Ваш логин с сайта smtp2go
char password[] = "******";       // Ваш пароль с сайта smtp2go

char email_sendto[] = "*******@gmail.com"; // Адрес получателя письма
char email_sendfrom[] = "******@gmail.com"; // Адрес отправителя письма

char name_sendto[] = "*****"; // Имя получателя письма
char name_sendfrom[] = "*****";      // Имя отправителя письма

char subject[] = "ESP32 was rebooted!"; // Тема письма


const long  gmtOffset_sec = 7200;
const int   daylightOffset_sec = 3600;
const char* ntpServer = "pool.ntp.org";

Adafruit_BME280 bme;

const char* ssid     = "*****";
const char* passwordwifi = "******";

const char * hostDomain = "api.openweathermap.org";
const int hostPort = 80;

const char * narmon = "narodmon.ru";
const int narmonPort = 8283;

String line;

WiFiClient client;

unsigned long WeatherPreviousMillis = 0;
unsigned long NTPPreviousMillis = 0;
unsigned long NarmonPreviousMillis = 0;
String name1;
float temp;
float pressure;
float humidity;
float wind;
float bpi_USD_rate;
float USD_rate;


void Bitcoin() {
  HTTPClient http;
  http.begin("http://api.coindesk.com/v1/bpi/currentprice.json");
  int httpCode = http.GET();

  if (httpCode == HTTP_CODE_OK) {
    String payload = http.getString();
    StaticJsonBuffer<1536> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(payload);
    if (root.success()) {
      {
        String time_updated = root["time"]["updated"];
        //const char* time_updated = time["updated"];
        //JsonObject& bpi = root["bpi"];
        //JsonObject& bpi_USD = bpi["USD"];
        bpi_USD_rate = root["bpi"]["USD"]["rate_float"];
        Serial.print("Curs of bitcoin: ");
        Serial.println(bpi_USD_rate);
        Serial.print("Update time: ");
        Serial.println(time_updated);
      }
    } else {
      Serial.println("parseObject() failed");
      Serial.println(payload);
    }
  } else {
    Serial.println("HTTP error");
    Serial.println(httpCode);
  }
  http.end();
}

void USD() {
  HTTPClient http;
  http.begin("http://www.nbrb.by/API/ExRates/Rates/145");
  int httpCode = http.GET();

  if (httpCode == HTTP_CODE_OK) {
    String payload = http.getString();
    StaticJsonBuffer<1536> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(payload);
    if (root.success()) {
      {
        USD_rate = root["Cur_OfficialRate"];
        Serial.print("Curs of USD: ");
        Serial.println(USD_rate);
      }
    } else {
      Serial.println("parseObject() failed");
      Serial.println(payload);
    }
  } else {
    Serial.println("HTTP error");
    Serial.println(httpCode);
  }
  http.end();
}

void SendMon()
{
  String cmd;
  cmd = "#**-**-**-**-**-**";
  cmd += "\n";
  cmd += "#T1#";
  cmd += bme.readTemperature();
  cmd += "\n";
  cmd += "#P1#";
  cmd += (bme.seaLevelForAltitude(138, bme.readPressure() / 100.0F ) / 1.333);
  cmd += "\n";
  cmd += "#H1#";
  cmd += bme.readHumidity();
  cmd += "\n";
  cmd += "#B1#";
  cmd += bpi_USD_rate;
  cmd += "\n";
  cmd += "##";

  Serial.println("Connecting to narodmon.ru:");

  if (!client.connect(narmon, narmonPort))
  {
    Serial.println("connection failed");
    return;
  }
  Serial.println("Connected!");

  client.println(cmd);

  unsigned long timeout = millis();
  while (client.available() == 0)
  {
    if (millis() - timeout > 2000)
    {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }

  Serial.println("closing connection");
  client.stop();
  Serial.println("Weather is loaded to narmon.ru");

}

void requestURL(const char * host, uint8_t port)

{
  Serial.println("Connecting to domain: " + String(host));

  if (!client.connect(host, port))
  {
    Serial.println("connection failed");
    return;
  }
  Serial.println("Connected!");

  client.println("GET /data/2.5/weather?q=Homyel&mode=json&units=metric&APPID=8bb1caef3ad28de754c259361baffd58 HTTP/1.1");
  client.print("Host: api.openweathermap.org\r\n");
  client.print("Connection: close\r\n\r\n");


  unsigned long timeout = millis();
  while (client.available() == 0)
  {
    if (millis() - timeout > 2000)
    {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }

  // Read all the lines of the reply from server and print them to Serial
  while (client.available())
  {
    line = client.readStringUntil('\r');

  }
  Serial.println("closing connection");
  client.stop();


}

void printLocalTime()
{

  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%d.%m.%Y %H:%M:%S");

  int intVar;   //Преобразуем значение времени в целове число, так как функция возвращает нам строку, непригодную для сравнения
  String time_int;
  char output[10];
  strftime(output, 10, "%H", &timeinfo);
  time_int = String(output);
  intVar = time_int.toInt();
  Serial.println(intVar);

  if (intVar > 22 || intVar < 6 )
  {
    Serial.println("SVET OFF");
    lcd.noBacklight();

  }
  else
  {

    Serial.println("SVET ON");
    lcd.backlight();

  }

}
void printLocalTimeDateLcd()
{
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }
  lcd.setCursor(10, 0); //Переходим на 10 ячейку дисплея 1-ой строки
  lcd.println(&timeinfo, "%d.%m.%Y");
  lcd.setCursor(15, 1); //Переходим на 15 ячейку дисплея 2-ой строки
  lcd.print(&timeinfo, "%H:%M:%S");
   }

//void printLocalTimeTimeLcd()
//{
  //struct tm timeinfo;
 // if (!getLocalTime(&timeinfo)) {
 //   Serial.println("Failed to obtain time");
 //   return;
 // }
//  lcd.setCursor(15, 1); //Переходим на 15 ячейку дисплея 2-ой строки
 // lcd.print(&timeinfo, "%H:%M:%S");
//}

void parseJSON(String weather)
{
  StaticJsonBuffer<3000> jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject(weather);
  if (!root.success())
  {
    Serial.print("ParseObject() failed");
  }

  String name = root["name"];
  name1 = name;
  // Serial.print("City: ");
  // Serial.println(name1);

  temp = root["main"]["temp"];
  // Serial.print("Temp: ");
  // Serial.print(temp);
  // Serial.println(" C");

  pressure = root["main"]["pressure"];
  // Serial.print("Pressure: ");
  //  Serial.print(pressure / 1.333);
  //  Serial.println(" mmHg");


  humidity = root["main"]["humidity"];
  // Serial.print("humidity: ");
  //  Serial.print(humidity);
  // Serial.println(" %");

  wind = root["wind"]["speed"];

}

void setup()
{

  bme.begin(0x76);
  lcd.begin(21,22);
//  lcd.init();              // initialize the lcd
  lcd.backlight();

  Serial.begin(9600);
  delay(100);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, passwordwifi);
  int  var = 0;
  while (WiFi.status() != WL_CONNECTED && var < 20) {
    delay(500);
    Serial.print(".");
    Serial.print(var);

    if (var == 19) {
      ESP.restart();
    }
    var++;
  }

  Serial.println("");
  Serial.println("WiFi connected");
  lcd.setCursor(0, 0);
  lcd.print("Connected to ");
  lcd.setCursor(0, 1);
  lcd.print(ssid);
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  lcd.setCursor(0, 3);
  lcd.print(WiFi.localIP());

  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("MAC");
  lcd.setCursor(0, 1);
  lcd.print("30AEA437F33C");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Login on Narmon");
  lcd.setCursor(0, 1);
  lcd.print("leruetkins");

  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.println("Time is updated on NTP");
  requestURL(hostDomain, hostPort);
  parseJSON(line);
  // Serial.println("Weather is updated on openweather.com");
  Bitcoin();
  //Serial.println("Bitcoin curs is updated");
  USD();
   if  (bme.readTemperature() <= 0 )  {
    sendEmail();
    Serial.println(" ESP RESTART");

    delay(2000);
    ESP.restart();
   }
  SendMon();
  // Serial.println("Weather is loaded to narmon.ru");


}
void efail()
{
  byte thisByte = 0;
  int loopCount = 0;
  client.println(F("QUIT"));
  while (!client.available()) {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return;
    }
  }
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }
  client.stop();
  Serial.println(F("disconnected"));
}

byte eRcv()
{
  byte respCode;
  byte thisByte;
  int loopCount = 0;
  while (!client.available()) {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if (loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }
  respCode = client.peek();
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }
  if (respCode >= '4')
  {
    efail();
    return 0;
  }
  return 1;
}



byte sendEmail() //Функция отправки письма
{
  byte thisByte = 0;
  byte respCode;
  if (client.connect(server, port) == 1) {
    Serial.println(F("connected"));
  }
  else {
    Serial.println(F("connection failed"));
    return 0;
  }
  if (!eRcv()) return 0;
  Serial.println(F("Sending hello"));
  // replace 1.2.3.4 with your Arduino's ip
  client.println("EHLO 1.2.3.4");
  if (!eRcv()) return 0;
  Serial.println(F("Sending auth login"));
  client.println("auth login");
  if (!eRcv()) return 0;
  Serial.println(F("Sending User"));
  // Change to your base64 encoded user
  client.println("bGVydWV0a2luc0BnbWFpbC5jb20=");
  if (!eRcv()) return 0;
  Serial.println(F("Sending Password"));
  // change to your base64 encoded password
  client.println("c210cDEyM2E0NTY=");
  if (!eRcv()) return 0;
  // change to your email address (sender)
  Serial.println(F("Sending From"));
  //  client.println("MAIL From: <leruetkins@gmail.com>");
  client.print("MAIL From: <");
  client.print(email_sendfrom);
  client.println(">");
  if (!eRcv()) return 0;
  // change to recipient address
  Serial.println(F("Sending To"));
  //client.println("RCPT To: <leruetkins@gmail.com>");
  client.print("RCPT To: <");
  client.print(email_sendto);
  client.println(">");
  if (!eRcv()) return 0;
  Serial.println(F("Sending DATA"));
  client.println("DATA");
  if (!eRcv()) return 0;
  Serial.println(F("Sending email"));
  // change to recipient address
  //client.println("To: You <her@gmail.com>");
  client.print("To: ");
  client.print(name_sendto);
  client.print(" <");
  client.print(email_sendto);
  client.println(">");
  // change to your address
  //client.println("From: Me <her@gmail.com>");
  client.print("From: ");
  client.print(name_sendfrom);
  client.print(" <");
  client.print(email_sendfrom);
  client.println(">");
  //client.println("Subject: 111\r\n");
  client.print("Subject: ");
  client.print(subject);
  client.println("\r\n");
  client.print("ESP32 was rebooted at: ");
  struct tm timeinfo;
  getLocalTime(&timeinfo);
  client.println(&timeinfo, "%H:%M:%S %d.%m.%Y");
  client.println("Have a nice day!");
  client.println(".");
  if (!eRcv()) return 0;
  Serial.println(F("Sending QUIT"));
  client.println("QUIT");
  if (!eRcv()) return 0;
  client.stop();
  Serial.println(F("disconnected"));
  return 1;
}



void loop()
{
  if (WiFi.status() != WL_CONNECTED){         //Проверям, есть ли подключение к wifi и если нету перезагружаемся
  ESP.restart();}
  
  if  (bme.readTemperature() <= 0 )  {        //Проверяем, подключён или  не завис ли bme280 и в случае чего перезагружаемся
    sendEmail();
    Serial.println(" ESP RESTSRT");

    delay(2000);
    ESP.restart();

  }

  unsigned long CurrentMillis = millis();
  Serial.println(CurrentMillis);

  //Получение времени с NTP сервера
  int tntp = 3600000; // Интервал получения времени с NTP сервера
  Serial.println(CurrentMillis - NTPPreviousMillis);
  Serial.print(round((tntp - (CurrentMillis - NTPPreviousMillis)) / 60000)); // Количество оставшихся минут до получения времени с с NTP сервера
  Serial.println(" m. - estimated time to get time from NTP");

  if (CurrentMillis - NTPPreviousMillis > tntp) {
    NTPPreviousMillis = CurrentMillis;
    Serial.println(NTPPreviousMillis);
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    Serial.println("Time is updated on NTP");
  }

  //Получение погоды с сайта openweather.com
  int tw = 1800000; // Интервал получения данных с сайта openweather.com в миллисекундах
  Serial.println(CurrentMillis - WeatherPreviousMillis);
  Serial.print((tw - (CurrentMillis - WeatherPreviousMillis)) / 60000); // Количество оставшихся минут до получения погоды с сайта openweather.com
  Serial.println(" m. - estimated time to get data from openweather.com");
  if (CurrentMillis - WeatherPreviousMillis > tw) {
    WeatherPreviousMillis = CurrentMillis;
    Serial.println(WeatherPreviousMillis);
    requestURL(hostDomain, hostPort);
    parseJSON(line);
    Serial.println("Weather is updated on openweather.com");
  }

  //Отправка данных на народный мониторинг и получение данных о курсе биткоина
  int tn = 600000;
  Serial.println(CurrentMillis - NarmonPreviousMillis);
  Serial.print((tn - (CurrentMillis - NarmonPreviousMillis)) / 60000);
  Serial.println(" m. - estimated time to send data on narodmon.ru");
  if (CurrentMillis - NarmonPreviousMillis > tn) {
    NarmonPreviousMillis = CurrentMillis;
    Serial.println(NarmonPreviousMillis);
    Bitcoin();
    delay(500);
    SendMon();
    delay(500);
    Serial.println("Weather is loaded to narmon.ru");
    Serial.println("Curs of Bitcoin is updated");
  }


  Serial.println();
  Serial.println("-------------");
  Serial.print("Time: ");
  printLocalTime();
delay(500);
  Serial.println();
  Serial.print("City: ");
  Serial.println(name1);

  Serial.print("Temp outdoor: ");
  Serial.print(temp);
  Serial.println(" C");

  Serial.print("Humidity outdoor: ");
  Serial.print(humidity);
  Serial.println(" %");

  Serial.print("Pressure outdoor: ");
  Serial.print(pressure / 1.333);
  Serial.println(" mmHg");

  Serial.print("Wind outdoor: ");
  Serial.print(wind);
  Serial.println(" Km/h");


  //parseJSON(line);
  // Serial.print(line);
  Serial.println();
  Serial.print("Temp in home: ");
  Serial.print(bme.readTemperature());
  Serial.println(" C");
delay(500);
  Serial.print("Humidity in home: ");
  Serial.print(bme.readHumidity());
  Serial.println(" %");
delay(500);
  Serial.print("Pressure in home: ");
  Serial.print(bme.seaLevelForAltitude(138, bme.readPressure() / 100.0F ) / 1.333);
  Serial.println(" mmHg");
delay(500);
  Serial.print("Bitcoin curs: ");
  Serial.print(bpi_USD_rate);
  Serial.println(" USD");
delay(500);
  Serial.print("Curs of USD: ");
  Serial.print(USD_rate * 10000);
  Serial.println(" BEL RUB");

  int T = round (bme.readTemperature());
  delay(500);
  int P = round (bme.seaLevelForAltitude(138, bme.readPressure() / 100.0F ) / 1.333);
  delay(500);
  int H = round (bme.readHumidity());
  delay(500);
  lcd.clear();
  printLocalTimeDateLcd();
  printLocalTimeTimeLcd();


  lcd.setCursor(0, 0);
  lcd.print("T=");
  lcd.print(T); // Вывод округлённого значения температуры с датчика

  lcd.setCursor(4, 0);
  lcd.print("(");
  lcd.print(round (temp));
  lcd.print(")");




  //Вывод давления с датчика BMP180 на дисплей
  lcd.setCursor(0, 1);
  lcd.print("P=");
  //Датчик выводит температуру в  дробных числах в гидропаскалях, поэтому преобразуем их в целые значения миллиметров ртутного столба
  // word pbmp = Pressurebmp / 133.3;
  lcd.print(P);
  lcd.setCursor(5, 1);
  lcd.print("(");
  lcd.print(round (pressure / 1.333));
  lcd.print(")");



  //Вывод влажности с датчика DHT11 на дисплей
  lcd.setCursor(0, 2);
  lcd.print("H=");
  lcd.print(H);
  lcd.setCursor(4, 2);
  lcd.print("(");
  lcd.print(round (humidity));
  lcd.print(")");

  lcd.setCursor(0, 3);
  lcd.print("W=");
  lcd.print(round (wind));
  lcd.print("Km/h");



  lcd.setCursor(10, 2);
  lcd.print("USD=");
  lcd.print(round (USD_rate * 10000));

  lcd.setCursor(10, 3);
  lcd.print("BTC=");
  lcd.print((int)bpi_USD_rate);






  delay(60000);

}