Часы с погодой от yandex. ESP8266 + дисплей ILI9341

Текущая погода и 2 последующих периода (ночь, утро, день или вечер).
Необходимо получить ключ yandex-погоды, тариф “Погода на вашем сайте”.

Подключение к WiFi через WiFiManager, IP - 192.168.4.1, сеть = “ESP8266-Clock”
Web-страница для настройки яркости дисплея, только до отключения питания.
После первого запуска настроить потом прописать в “settings.h” и перепрошить.
Скриншоты иконок и фото дисплея в архиве. (рис. IMG_NA пока не используется)

“settings.h”
Подключение дисплея к ESP8266.
Настройки яркости дисплея (день-ночь).
Два набора иконок однолинейные и полноцветные - на выбор.
Архив - clock_ntp_weather_ya.zip — Яндекс Диск



//*   27.04.2023
//   ILI9341 with ESP8266 and Wemos D1   
// Display SDO/MISO  to NodeMCU pin D6 
// Display LED       to NodeMCU pin D2 
// Display SCK       to NodeMCU pin D5
// Display SDI/MOSI  to NodeMCU pin D7
// Display DC (RS/AO)to NodeMCU pin D3
// Display RESET     to NodeMCU pin D4 
// Display CS        to NodeMCU pin D8 
// Display GND       to NodeMCU pin GND (0V)
// Display VCC       to NodeMCU 3.3V
//*/
/*--------------- libraries ----------------------*/
#include                     //version - 6.21.1
#include 
#include 
#include 
#include 
#include 
#include 
#include                         // version=2.5.23
#include 
#include 
#include 
#include 
#include  
//*--------------- Project ----------------------*/
#include "Fonts_Img/ArialRoundedMTBold_36.h" // щрифты
#include "Fonts_Img/FreeSansBold6.h"
#include "Fonts_Img/FreeSansBold10.h"
#include "Fonts_Img/FreeSansBold14.h"
#include "settings.h"                       // Настройки - ввести свои данные!!!
#include "functions.h"                      // функции обработки
#include "Fonts_Img/html.h"                 // веб-страница
//*--------------- Image ----------------------*/
#ifdef theme                                //выбор иконок погоды
  #include "Fonts_Img/weather_img2.h"
#else
  #include "Fonts_Img/weather_img1.h"
#endif
#define ENABLE_OTA_UPDATE true              // OTA обновление
//*--------------- Fonts ----------------------*/
#define AR36 &ArialRoundedMTBold_36         // шрифт температура сейчас 
#define RU14 &FreeSansBold14pt8b            // шрифт рус. дата
#define RU10 &FreeSansBold10pt8b            // шрифт рус. температура период
#define RU6 &FreeSansBold6pt8b              // шрифт рус. восход, закат
//*---- ILI9341 with ESP8266 and Wemos D1 -----*/
#define TFT_CS   D8
#define TFT_DC   D3
#define TFT_RST  D4
#define TFT_MOSI D7
#define TFT_MISO D6
#define TFT_CLK  D5
#define LED_PIN  D2           // управление яркостью дисплея 
#define Serial_Print          // отладка для работы  - закоментить
#define LED_BRIGHTNESS 30     // яркость дисплея при старте
WiFiUDP Udp;
TFT_eSPI tft = TFT_eSPI(); // Use hardware SPI
WiFiManager wifiManager;
ESP8266WebServer server_web(80);
weather_t weather;
StaticJsonDocument<8000> doc;
bool decode_json(String jsonStr);
bool get_YA_Weather();
String convert_unix_time(int unix_time);
String get_description_condition(String str);
String get_partName(String pName);
String getSeason(String season);
time_t prevDisplay = 0;
double temperature = 0.0;
double humidity = 0;
double pressure = 0;
//*------------------- print Img weather --------------------------*/
void print_Img(int x, int y, String condition, String daytime) {
  int w, h;
  w=60;h=60;                                               // ширина, высота иконки
  if ((condition == "clear") and (daytime == "d"))         //Ясно день
  tft.pushImage(x,y,w,h,img_100);	
  if ((condition == "clear") and (daytime == "n"))         //Ясно ночь
  tft.pushImage(x,y,w,h,img_150);
  if ((condition == "partly-cloudy") and (daytime == "d")) //Малооблачно день
  tft.pushImage(x,y,w,h,img_104);	
  if ((condition == "partly-cloudy") and (daytime == "n")) //Малооблачно ночь
  tft.pushImage(x,y,w,h,img_154);
  if ((condition == "cloudy") and (daytime == "d"))        //Облачно день
  tft.pushImage(x,y,w,h,img_104);	
  if ((condition == "cloudy") and (daytime == "n"))        //Облачно ночь
  tft.pushImage(x,y,w,h,img_154);
  if (condition == "overcast")                             //Пасмурно 
  tft.pushImage(x,y,w,h,img_102);	
  if ((condition == "drizzle") or  (condition == "light-rain") or (condition == "rain")) //Небольшой дождь, Дождь
  tft.pushImage(x,y,w,h,img_306);
  if ((condition == "moderate-rain") or  (condition == "heavy-rain") or (condition == "continuous-heavy-rain") or (condition == "showers")) //Сильный дождь, Ливень 
  tft.pushImage(x,y,w,h,img_310);
  if (condition == "wet-snow")                              //Дождь со снегом 
  tft.pushImage(x,y,w,h,img_404); 
  if ((condition == "light-snow") or  (condition == "snow") or (condition == "snow-showers")) //Снег
  tft.pushImage(x,y,w,h,img_403);
  if (condition == "hail")                                  //Град
  tft.pushImage(x,y,w,h,img_313);   
  if ((condition == "thunderstorm") or  (condition == "thunderstorm-with-rain") or (condition == "thunderstorm-with-hail")) //Дождь,гроза
  tft.pushImage(x,y,w,h,img_303);
} // end print_Img

//*------------------- TFT weather --------------------------*/
void TFT_weather()
{
  get_YA_Weather(); // запрос погоды с яндекс
  tft.fillRect ( 2, 123, 316, 115, TFT_BLACK);                     //область погоды очищаем для перерисовки 
  print_Img(2, 124, weather.fact.condition, weather.fact.daytime); //рисуем картинку на TFT текущая погода 
  tft.setFreeFont(AR36);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK, true); 
  int xpos = 65; // координаты отрисовки температуры  
  if (weather.fact.temp > 0)
    xpos += tft.drawString("+" + String(weather.fact.temp), xpos,130); // добавляем "+" к положительной текущей температуре 
   else
    xpos += tft.drawString(String(weather.fact.temp), xpos,130);       // текущая температура 
  tft.setTextFont(2);
  xpos += tft.drawString(" o", xpos,130);  //  " °C" добавляем градус к температуре 
  tft.setFreeFont(AR36);
  xpos += tft.drawString("C", xpos,130);
  tft.setFreeFont(RU10);
  tft.setTextColor(TFT_WHITE, TFT_BLACK, true);  
  tft.drawString(utf8rus( get_description_condition(weather.fact.condition )), 5, 184); // текущая погода
  tft.setTextColor(TFT_CYAN, TFT_BLACK, true);
  tft.drawString(String(weather.fact.pressure_mm) + utf8rus(" мм.р.ст."), 65,165);      // текущее давление
  tft.setTextColor(TFT_DARKGREY, TFT_BLACK, true);
  tft.drawString(utf8rus(get_partName(weather.forecast.parts[0].part_name)), 184, 185);        // 1-й период погода
  print_Img(184, 125, weather.forecast.parts[0].condition, weather.forecast.parts[0].daytime); //рисуем картинку на TFT 1-й период 
  tft.drawString(utf8rus(get_partName(weather.forecast.parts[1].part_name)), 254, 185);        // 2-й период погода  
  print_Img(254, 125, weather.forecast.parts[1].condition, weather.forecast.parts[1].daytime); //рисуем картинку на TFT 2-й период
  tft.setTextColor(TFT_YELLOW, TFT_BLACK, true); 
  xpos = 184;                                              // 1-й период температура " °C"  
  if (weather.forecast.parts[0].temp_avg > 0)
    xpos += tft.drawString("+" + String(weather.forecast.parts[0].temp_avg), xpos,210);        
   else
	xpos += tft.drawString(String(weather.forecast.parts[0].temp_avg), xpos,210);      
  tft.setTextFont(0);
  xpos += tft.drawString(" o", xpos,210);  //  " °C" добавляем градус к температуре 
  tft.setFreeFont(RU10);
  xpos += tft.drawString("C", xpos,210); 
  xpos = 254;                                              // 2-й период температура
  if (weather.forecast.parts[1].temp_avg > 0)
   xpos += tft.drawString("+" + String(weather.forecast.parts[1].temp_avg), xpos,210); // добавляем "+" к положительной температуре  
   else
	xpos += tft.drawString(String(weather.forecast.parts[1].temp_avg), xpos,210);    
  tft.setTextFont(0);
  xpos += tft.drawString(" o", xpos,210);  //  " °C" добавляем градус к температуре 
  tft.setFreeFont(RU10);
  xpos += tft.drawString("C", xpos,210);
  
  tft.setTextColor(TFT_GREENYELLOW, TFT_BLACK, true);
  tft.setFreeFont(RU6);
  xpos = tft.drawString(utf8rus("Восход:"), 5, 207);   
  tft.drawString(weather.forecast.sunrise, xpos+10, 207);  // Восход
  tft.drawString(utf8rus("Закат:"), 5, 223);               // выравниваем время восхода и заката
  tft.drawString(weather.forecast.sunset, xpos+10, 223);   // Закат
  tft.drawLine( 256, 40, 256, 115, TFT_GREENYELLOW );      //область секунд и дня недели 1 
  tft.drawLine( 256, 85, 316, 85, TFT_GREENYELLOW );       //область секунд и дня недели 2
  tft.drawRect( 1, 1, 319, 122, TFT_NAVY );                //область часы и дата
  tft.drawRect( 1, 122, 319, 118, TFT_NAVY );              //область погоды
  tft.drawLine( 182, 122, 182, 240, TFT_NAVY );            //область периодов погоды
} // end TFT_weather

//*------------ TFT Clocktime -----------------------------*/
void draw_Clocktime()
{
  String str;
  int len;
  uint8_t hh = hour(), mm = minute(), ss = second(); // Get H, M, S from compile time
    if ((hh == 0) and (mm == 0) and (ss == 0))
	  {
	  tft.fillRect ( 5, 40, 53, 76, TFT_BLACK);        // Очистить первый 0 в "00" в часах в 00:00:00 от остатка двойки 23:59:59
      tft.fillRect ( 2, 2, 314, 40, TFT_BLACK);        // Очистить дату
      tft.fillRect ( 262, 89, 56, 30, TFT_BLACK);      // Очистить день недели
	   } 
	  
    if (( hh == 0 ) and ( mm == 0 ))
     {
     tft.setFreeFont(RU14);
     tft.setTextColor(TFT_YELLOW, TFT_BLACK, true);
     str = utf8rus( days[ weekday() ] );
     tft.drawString( str, 265, 87 ); // день недели
     str = utf8rus( String( day() ) + " " + months[ month() ] + " " + year() );  // день, месяц и год
     tft.drawString( str, 160 - tft.textWidth(str) / 2, 2 );
     tft.setTextColor(TFT_WHITE, TFT_BLACK, true);  
     }
    byte omm = 99, oss = 99;
    byte xcolon = 0, xsecs = 0;
    int xpos = 5;   // // d:\arduino-1.8.19\...\libraries\TFT_eSPI\examples\320 x 240\TFT_Clock_Digital
	int ypos = 40;                                          // Верхний левый угол текста часов
    int ysecs = ypos + 24;
    if (omm != mm) {                                        // Обновлять часы и минуты каждую минуту
      omm = mm;
      // рисуем часы и минуты
      tft.setTextColor(TFT_BLACK, TFT_BLACK, true);
      if (hh < 10) xpos += tft.drawChar('0', xpos, ypos, 8); // Добавить 0 в часы  для 24-часового формата и сохранение позиции на дисплее.
      tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
      xpos += tft.drawNumber(hh, xpos, ypos, 8);             // рисуем часы
      xcolon = xpos;                                         // Сохранение координат двоеточия, чтобы мигать позже
      xpos += tft.drawChar(':', xpos, ypos - 8, 8);
      if (mm < 10) xpos += tft.drawChar('0', xpos, ypos, 8); // Добавить 0 в минуты 
      xpos += tft.drawNumber(mm, xpos, ypos, 8);             // рисуем минуты
      xsecs = xpos;                                          // Сохранение положения секунд «x» для последующих обновлений дисплея
    }
    if (oss != ss) {                                         // Перерисовывать секунды каждую секунду
      oss = ss;
      xpos = xsecs;
      if (ss % 2) {                                          // Включить/выключить двоеточие
        tft.setTextColor(TFT_BLACK, TFT_BLACK, true);              // затемнить двоеточие
        tft.drawChar(':', xcolon, ypos - 8, 8);              // Час:минута двоеточие
        tft.setTextColor(TFT_WHITE, TFT_BLACK, true);              // Вернуть цвет 
      }
      else {
        tft.drawChar(':', xcolon, ypos - 8, 8);              // Час:минута двоеточие
      }
      //рисуем секунды
      if (ss < 10) xpos += tft.drawChar('0', xpos+8, ypos-3, 6); // Добавить 0
      tft.drawNumber(ss, xpos+8, ypos-3, 6);                     // рисуем секунды
    }                            
} // end TFT Clocktime

void refresh_display()
{
  draw_Clocktime();
  if ( ( minute() == 59 ) && ( second() == 59 ) )	//обновление погоды 1 раз в 59 мин 59 секунд  
  {
    TFT_weather();
	serial_digitalClockDisplay();
	Serial.println("Get weather");
  }
} // end  refresh_display
//*------------------ setup -----------------------------------*/
void setup()
{
  pinMode(LED_PIN, OUTPUT);
  analogWriteFreq(32768);
  analogWrite(LED_PIN, LED_BRIGHTNESS); // первоначальная яркость дисплея
  Serial.begin(115200);
  delay(250); 
  // Раскомментировать и запустить один раз, если надо стереть всю сохраненную информацию о WiFi в памяти ESP8266
  //wifiManager.resetSettings();
  tft.begin();
  tft.setSwapBytes(true); //Используется 16-битным pushImage() для изменения порядка байтов в цветах.
  tft.setRotation(1);
  tft.setTextSize(2);
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
  tft.setCursor(0, 26);
  tft.println("Connecting");
  Serial.println("");
  Serial.println("NTP Clock");
  Serial.print("Connecting to ");
  Serial.println(WiFi.SSID());
  initWiFi();
  tft.println("");
  tft.println(WiFi.SSID());
  tft.print("IP: ");
  tft.println(WiFi.localIP());
  tft.println("Starting UDP");
  Udp.begin(localPort);
  tft.print("Local port ");
  tft.println(Udp.localPort());
  tft.println("Time sync");
  setSyncProvider(getNtpTime); //Функция setSyncProvider(getTimeFunction) настраивает время
  setSyncInterval(3600);       // Функция setSyncInterval(interval) задает количество секунд между синхронизациями
  tft.println("Weather request");
  display_brightness();
  delay(2500); // читаем что вывели на дисплей
  if ( ENABLE_OTA_UPDATE )
  {
    tft.println("Begin OTA handler Esp8266_Clock");
	initOTA(); // обновление по WiFi 
   }
  tft.setTextSize(1);
  tft.fillScreen(TFT_BLACK);     
  String str;
  tft.setFreeFont(RU14);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK, true);
  str = utf8rus( days[ weekday() ] ); // день недели 
  tft.drawString( str, 265, 87 );
  str = utf8rus( String( day() ) + " " + months[ month() ] + " " + year() ); // день, месяц и год
  tft.drawString( str, 160 - tft.textWidth(str) / 2, 2 );
  tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
  server_web.on("/", handle_OnConnect);
  server_web.on("/update", handle_update);
  server_web.onNotFound(handle_NotFound); //любой URL, отличный от указанного в server.on() = ответить HTTP-статусом 404 (Not Found)
  server_web.begin();//запустить сервер
  draw_Clocktime();  
  TFT_weather(); // отрисовка погоды
}//end setup

//*------------------ loop -----------------------------------*/
void loop()
{
  if ( ENABLE_OTA_UPDATE )
  {
    ArduinoOTA.handle();
  }	
	
  if (timeStatus() != timeNotSet)
  {
    // обновляем дисплей только если время поменялось
    if (now() != prevDisplay)  //Функция now() считывает время, прошедшее с 1 января 1970 года (в секундах).
    {
      prevDisplay = now();     //Конструкция time_t t = now() сохраняет текущее время в переменную t.
	  display_brightness();
      refresh_display();
	   }
  }
  if ((millis() > 60*1000) and (year() == 1970) and (WiFi.status() == WL_CONNECTED))  //при старте время не было задано 
    {
      restart();
     }	
  server_web.handleClient();
} //end loop

//*------------------ web-html -----------------------------------*/
void handle_OnConnect() {
  Serial.println("Web started");
  server_web.send(200, "text/html", index_html); 

} // end handle_OnConnect

void handle_update() {
  server_web.send(200, "text/html", index_html);
  slider_day = server_web.arg("brightness_day").toInt();
  day_ = server_web.arg("hour_day").toInt();  
  slider_night = server_web.arg("brightness_night").toInt();
  night_ = server_web.arg("hour_night").toInt();
  Serial.println(slider_day);
  Serial.println(day_);
  Serial.println(slider_night);
  Serial.println(night_);  
} // end handle_update
 
void handle_NotFound(){
  server_web.send(404, "text/plain", "Not found");
} // end handle_NotFound

// перезапуск ESP8266
void restart()
{
  Serial.println("Restart ESP...");
  ESP.restart();
} // end restart

void display_brightness() // яркость дисплея
{ 
  if ( ( hour() >= day_ ) and ( hour() < night_ ) )
  {
    analogWrite(LED_PIN, slider_day);
  }
  else
  {
    analogWrite(LED_PIN, slider_night);
  }
} // end display_brightness
//*------------------ WiFi -----------------------------------*/
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin();//переключиться в режим станции и подключиться к последней точке доступа на основе данных, сохраненных во flash-памяти.
  //  WiFi.begin(ssid, pass);
  //Если persistent - false,то SSID и пароль будут записаны на flash-память только если новые значения не будут соответствовать тем, что хранятся во flash-памяти.   
  WiFi.persistent(false);
  WiFi.setAutoReconnect(true);// true, модуль сделает попытку повторного подключения к точке доступа, а если false, то нет.  
  Serial.println("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED && millis()<15*1000) {
  delay(500);
  Serial.print(".");
  }
    
    if(WiFi.status() == WL_CONNECTED){
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    }
    else {
     Serial.println("WiFi not connected, starting WiFiManager");
     tft.println("WiFi not connected...");
     tft.println("Starting WiFiManager");    
	 tft.println("SSID: ESP8266-Clock");
	 tft.print("IP address: ");
	 tft.println("192.168.4.1");
     wifiManager.autoConnect("ESP8266-Clock");       
     delay(2000);    
     }
} // end initWiFi
//*------------------ json -----------------------------------*/
bool decode_json(String jsonStr) // https://github.com/discover1977/YWInformer
{
 DeserializationError error = deserializeJson(doc, jsonStr); // преобразовать строку JSON в структуру
 if (error) {    // Проверяем успешность парсинга.
      String errorStr = error.c_str();
      Serial.println("errorStr: ");  Serial.print(errorStr);
      return false;	  
 }else{
      Serial.println("deserializeJson() без ошибок.");
      JsonObject doc_YA = doc.as();	
      weather.fact.condition = doc_YA["fact"]["condition"].as(); // парсинг данных из JsonObject
      weather.fact.daytime = doc_YA["fact"]["daytime"].as();
      weather.fact.feels_like = doc_YA["fact"]["feels_like"].as();
      weather.fact.humidity = doc_YA["fact"]["humidity"].as();
      weather.fact.icon = doc_YA["fact"]["icon"].as();
      weather.fact.obs_time = doc_YA["fact"]["obs_time"].as();
      weather.fact.polar = doc_YA["fact"]["polar"].as();
      weather.fact.pressure_mm = doc_YA["fact"]["pressure_mm"].as();
      weather.fact.pressure_pa = doc_YA["fact"]["pressure_pa"].as();
      weather.fact.season = doc_YA["fact"]["season"].as();
      weather.fact.temp = doc_YA["fact"]["temp"].as();
      weather.fact.temp_water = doc_YA["fact"]["temp_water"].as();
      weather.fact.wind_dir = doc_YA["fact"]["wind_dir"].as();
      weather.fact.wind_gust = doc_YA["fact"]["wind_gust"].as();
      weather.fact.wind_speed = doc_YA["fact"]["wind_speed"].as();
      weather.forecast.date = doc_YA["forecast"]["date"].as();
      weather.forecast.date_ts = doc_YA["forecast"]["date_ts"].as();
      weather.forecast.moon_code = doc_YA["forecast"]["moon_code"].as();
      weather.forecast.moon_text = doc_YA["forecast"]["moon_text"].as();
      for (uint8_t i = 0; i < 2; i++)
      {
        weather.forecast.parts[i].condition = doc_YA["forecast"]["parts"][i]["condition"].as();
        weather.forecast.parts[i].daytime = doc_YA["forecast"]["parts"][i]["daytime"].as();
        weather.forecast.parts[i].feels_like = doc_YA["forecast"]["parts"][i]["feels_like"].as();
        weather.forecast.parts[i].humidity = doc_YA["forecast"]["parts"][i]["humidity"].as();
        weather.forecast.parts[i].icon = doc_YA["forecast"]["parts"][i]["icon"].as();
        weather.forecast.parts[i].part_name = doc_YA["forecast"]["parts"][i]["part_name"].as();
        weather.forecast.parts[i].polar = doc_YA["forecast"]["parts"][i]["polar"].as();
        weather.forecast.parts[i].prec_mm = doc_YA["forecast"]["parts"][i]["prec_mm"].as();
        weather.forecast.parts[i].prec_period = doc_YA["forecast"]["parts"][i]["prec_period"].as();
        weather.forecast.parts[i].prec_prob = doc_YA["forecast"]["parts"][i]["prec_prob"].as();
        weather.forecast.parts[i].pressure_mm = doc_YA["forecast"]["parts"][i]["pressure_mm"].as();
        weather.forecast.parts[i].pressure_pa = doc_YA["forecast"]["parts"][i]["pressure_pa"].as();
        weather.forecast.parts[i].temp_avg = doc_YA["forecast"]["parts"][i]["temp_avg"].as();
        weather.forecast.parts[i].temp_max = doc_YA["forecast"]["parts"][i]["temp_max"].as();
        weather.forecast.parts[i].temp_min = doc_YA["forecast"]["parts"][i]["temp_min"].as();
        weather.forecast.parts[i].temp_water = doc_YA["forecast"]["parts"][i]["temp_water"].as();
        weather.forecast.parts[i].wind_dir = doc_YA["forecast"]["parts"][i]["wind_dir"].as();
        weather.forecast.parts[i].wind_gust = doc_YA["forecast"]["parts"][i]["wind_gust"].as();
        weather.forecast.parts[i].wind_speed = doc_YA["forecast"]["parts"][i]["wind_speed"].as();
      }
     weather.forecast.sunrise = doc_YA["forecast"]["sunrise"].as();
     weather.forecast.sunset = doc_YA["forecast"]["sunset"].as();
     weather.forecast.week = doc_YA["forecast"]["week"].as();
     weather.info.lat = doc_YA["info"]["lat"].as();
     weather.info.lon = doc_YA["info"]["lon"].as();
     weather.info.url = doc_YA["info"]["url"].as();
     weather.now = doc_YA["now"].as();
     weather.now_dt = doc_YA["now_dt"].as();
	 return true;
}} // end decode_json
//*-------------- Weather code -------------------------*/
bool get_YA_Weather()                // запрос погоды с яндекс
{
 if(WiFi.status()== WL_CONNECTED){   // проверяем соединение WiFi
    HTTPClient http;                 // Отправляем HTTP GET запрос
    String _host = "api.weather.yandex.ru";
	String _uri = "/v2/informers?lat=" + String(lat, 6) + "&lon=" + String(lon, 6);
    WiFiClient client;
    client.stop();
    http.begin(client, _host, 80, _uri, true);
	http.addHeader("X-Yandex-API-Key", api_key);
    int httpCode = http.GET();

 if (httpCode > 0) { 
  String response = http.getString();
  Serial.println("  ");
  printStr(response);       //выводим ответ yandex 
  decode_json(response);    // парсинг данных из JsonObject

#ifdef  Serial_Print        //  отладка      
	  Serial.println(" - - fact - - ");
	  Serial.println(get_description_condition(weather.fact.condition));
      Serial.println(weather.fact.daytime);	  
      Serial.println(weather.fact.feels_like);	  
      Serial.println(weather.fact.humidity);
      Serial.println(weather.fact.icon);
	  Serial.println(convert_unix_time(weather.fact.obs_time));
      Serial.println(weather.fact.polar);
      Serial.println(weather.fact.pressure_mm);
      Serial.println(weather.fact.pressure_pa);
	  Serial.println(getSeason(weather.fact.season));
      Serial.println(weather.fact.temp);
      Serial.println(weather.fact.temp_water);
      Serial.println(weather.fact.wind_dir);
      Serial.println(weather.fact.wind_gust);
      Serial.println(weather.fact.wind_speed);
	  Serial.println(" - - forecast - - ");
	  Serial.println(weather.forecast.date);
	  Serial.println(convert_unix_time(weather.forecast.date_ts));
	  Serial.println(weather.forecast.moon_code);
	  Serial.println(weather.forecast.moon_text);
    for (uint8_t i = 0; i < 2; i++)
    {
        Serial.print(" - - part: = "); Serial.println(i);
		Serial.println(get_description_condition(weather.forecast.parts[i].condition));
    	Serial.println(weather.forecast.parts[i].daytime);
        Serial.println(weather.forecast.parts[i].feels_like);
        Serial.println(weather.forecast.parts[i].humidity);
        Serial.println(weather.forecast.parts[i].icon);
		Serial.println(get_partName(weather.forecast.parts[i].part_name));
        Serial.println(weather.forecast.parts[i].polar);
        Serial.println(weather.forecast.parts[i].prec_mm);
        Serial.println(weather.forecast.parts[i].prec_period);
        Serial.println(weather.forecast.parts[i].prec_prob);
        Serial.println(weather.forecast.parts[i].pressure_mm);
        Serial.println(weather.forecast.parts[i].pressure_pa);
        Serial.println(weather.forecast.parts[i].temp_avg);
        Serial.println(weather.forecast.parts[i].temp_max);
        Serial.println(weather.forecast.parts[i].temp_min);
        Serial.println(weather.forecast.parts[i].temp_water);
        Serial.println(weather.forecast.parts[i].wind_dir);
        Serial.println(weather.forecast.parts[i].wind_gust);
        Serial.println(weather.forecast.parts[i].wind_speed);
    } //for	  
	  Serial.println(" - - forecast - - ");
	  Serial.println(weather.forecast.sunrise);
	  Serial.println(weather.forecast.sunset);
	  Serial.println(weather.forecast.week);
	  Serial.println(" - - info - - ");
	  Serial.println(weather.info.lat, 6);
	  Serial.println(weather.info.lon, 6);
	  Serial.println(weather.info.url);
	  Serial.println(" - - now - - ");
//	  Serial.println(weather.now);
	  Serial.println(convert_unix_time(weather.now));
	  Serial.println(weather.now_dt);
#endif
      client.stop();
      http.end();
      return true;
    }
    else
    {
      Serial.println("Connection failed");
      client.stop();
      http.end();
      return false;
    }
}} // end getWeather


//*-------------- NTP code -------------------------*/ // https://wikihandbk.com/wiki/Arduino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/TimeNTP_ESP8266WiFi
const int NTP_PACKET_SIZE = 48;      // NTP-время – в первых 48 байтах сообщения
byte packetBuffer[NTP_PACKET_SIZE];  // буфер для хранения входящих и исходящих пакетов 
// отправляем NTP-запрос серверу времени по указанному адресу:
void sendNTPpacket(IPAddress &address)
{
   // задаем все байты в буфере на «0»: 
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // инициализируем значения для создания NTP-запроса (подробнее о пакетах смотрите по ссылке выше)
  packetBuffer[0] = 0b11100011;   // LI (от «leap indicator», т.е. «индикатор перехода»), версия, режим работы 
  packetBuffer[1] = 0;     // слой (или тип часов) 
  packetBuffer[2] = 6;     // интервал запросов 
  packetBuffer[3] = 0xEC;  // точность
  // 8 байтов с нулями, обозначающие базовую задержку и базовую дисперсию:
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  // После заполнения всех указанных полей можно отправлять пакет с запросом о временной метке:
  Udp.beginPacket(address, 123); //  NTP-запросы к порту 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
} // end sendNTPpacket

time_t getNtpTime()
{
  IPAddress ntpServerIP; // IP-адрес NTP-сервера
  while (Udp.parsePacket() > 0) ; // отбраковываем все пакеты, полученные ранее 
  Serial.println("Transmit NTP Request"); //  "Передача NTP-запроса" 
  WiFi.hostByName(ntpServerName, ntpServerIP);   //  подключаемся к случайному серверу из списка:
  Serial.print(ntpServerName);
  Serial.print(": ");
  Serial.println(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response"); // "Получение NTP-ответа"
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // считываем пакет в буфер 
      unsigned long secsSince1900;
      //конвертируем 4 байта (начиная с позиции 40) в длинное целое число: 
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-("); //  "Нет NTP-ответа :(" 
  return 0; // если время получить не удалось, возвращаем «0» 
} // end getNtpTime

Библиотеки, Почему в коде не отображаются - не знаю. В окне редактирования видны.
//--------------- libraries ----------------------/
#include <ArduinoJson.h> //version - 6.21.1
#include <ESP8266WiFi.h>
#include <SPI.h>
#include <TimeLib.h>
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <TFT_eSPI.h> // version=2.5.23
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>

Иконки:

3 лайка

А почему бы не сделать сохранение настроек?

недостаток один, библиотеку TFT придётся настраивать, можно выложить архивом уже настроенную?
Второе, под каким ядром собиралось?

А почему бы не сделать сохранение настроек?

Можно, но функция одноразовая посмотреть и настроить. Тем более что есть ОТА и перепрошить по воздуху не проблема.

Библиотеку не правил, ссылка на мою - TFT_eSPI-master.zip — Яндекс Диск
Могут быть не большие отличия пока с ней разбирался. Добавлена папка “FontsRus”, но она в проекте не используется.

Зачем тогда веб-страница?

Зачем тогда веб-страница?

Для первоначальной настройки. Посмотреть уровень яркости и когда его уменьшать, увеличивать. И потом просто чтобы было - можно и удалить из кода если Вам не надо.

у этой библиотеки один недостаток, я так и не смог вынести конфигурацию оной в скетч, а так как использую и для разных дисплеев, и для разных контроллеров (esp8266, esp32, rp2040) то приходится изголяться, хранить в папке скетча в архивированном виде и, перед компиляцией заменять

у этой библиотеки один недостаток, я так и не смог вынести конфигурацию оной в скетч, а так как использую и для разных дисплеев, и для разных контроллеров (esp8266, esp32, rp2040) то приходится изголяться, хранить в папке скетча в архивированном виде и, перед компиляцией заменять

У каждого свои недостатки, не её достоинство быстрота отрисовки

быстрее видали )))
так всё таки на каком ядре компилировалось?

Полумера. Добавить пару строк для сохранения настройки и считывания ее при запуске - логичное решение. А настраивать, чтобы потом перепрошить - такое себе

D:\arduino-1.8.19-YA\portable\sketchbook\2023\ESP8266\clock_ntp_weather_ya\clock_ntp_weather_ya.ino: In function 'bool get_YA_Weather()':
clock_ntp_weather_ya:543:1: error: control reaches end of non-void function [-Werror=return-type]
  543 | } // end getWeather
      | ^
cc1plus.exe: some warnings being treated as errors

Осталось это, не могу одолеть, номера строк с оригиналом не совпадают, чуток правил комментарии, всё таки, под каким ядром компилировалось???

Хотел в стиле Гайвера из …на и палок за час Информатор сколхозить, ан нет…

неожиданно заработало, когда в строке запроса все параметры впрямую указал, вернул взад, тоже работает, чудеса )))

В свободный квадратик посередине внизу можно вывести погоду в доме, температура и влажность
Симпатичненько получилось, даже более - гламурненько )))

Есть такая плата, сделана бутербродом, СH340 на отдельной плате, +3.3 на пин не выведен, но отверстие с металлизацией имеется, на борту фотодиод, то есть яркость можно устанавливать не по времени, а в зависимости от освещения или скомбинировать, на освободившиеся пины повесить DHT-22 или что-то аналогичное…
ESP8266-SOL


С фоторезистром будет мигать экран. Туда - обратно.
Проще сделать ночную яркость от например 23.00 до например 7 утра настраиваемую. И другую яркость настраиваемую от заката до рассвета по данным Яндекса. В Северозападных регионах ночь зимой наступает в 17.00, а летом практически ее нет.

эт от чегой та?

С чего вдруг? Гистерезис для чего придуман?

а вот матом не надо ругаться …

Да как же тут не заругаться?

Вы тоже )))
кстати, продолжение будет, а то без локальной температуры/влажности как то недосказано …