Текущая погода.
- Необходимо получить API ключ Оpenweathermap.
Members
Производится запрос текущей погоды каждый час. - Настройка библиотеки TFT_eSPI (version=2.5.30, оригинал - изменений нет).
GitHub - Bodmer/TFT_eSPI: Arduino and PlatformIO IDE compatible TFT library optimised for the Raspberry Pi Pico (RP2040), STM32, ESP8266 and ESP32 that supports different driver chips · GitHub
По умолчанию эта библиотека будет работать для ESP8266 с использованием драйвера ILI9341.
Но в нашем случае используем ESP32, поэтому некоторые настройки нужно изменить.
Заменяем файл “User_Setup.h” в корне библиотеки файлом “User_Setup.h” из архива. - Подключение к WiFi через WiFiManager, IP - 192.168.4.1, сеть = “ESP32-Clock”.
Настройки в “settings.h”. Есть OTA обновление прошивки.
Скриншоты, подключение дисплея к ESP32 и фото дисплея в архиве.
Clock_OpenWeather.zip — Яндекс Диск
================================
Подключение дисплея ILI9341 к ESP32 (рис. ili9341_esp32.png)
Display SDO/MISO - подключать не нужно!
Display LED to ESP32 pin 5
Display SCK to ESP32 pin 18
Display SDI/MOSI to ESP32 pin 23
Display DC to ESP32 pin 2
Display RESET to ESP32 pin 4
Display CS to ESP32 pin 15
Display GND to ESP32 pin GND
Display VCC to ESP32 3.3V
===================================

Clock_OpenWeather.ino
#include <ArduinoJson.h> //version - 6.21.2
#include <SPI.h>
#include <TimeLib.h> //version=1.6.1
#include <ArduinoOTA.h>
#include <WiFiUdp.h>
#include <TFT_eSPI.h> // version=2.5.30
#include <WiFiClient.h>
#include <DNSServer.h>
#include <HTTPClient.h>
#include <WiFi.h>
#include <Wire.h>
#include <WiFiManager.h>
#include "fonts.h"
#include "ImgWea60.h"
#include "settings.h"
#define LED_BUILTIN 5 // управление яркостью дисплея
#define LED_BRIGHTNESS 30 // яркость дисплея при старте
#define ENABLE_OTA_UPDATE true // OTA обновление
#define RU10 &FreeSansBold10pt8b
#define RU8 &FreeMonoBold8pt8b
#define RUSW &TinyFont5
#define DIG20 &DIG_Bold_20
#define TFT_W 240 //установить ширину экрана tft
#define TIME_OFFSET timeZone * SECS_PER_HOUR // UTC + timeZone час
//------------------------------------------------
#define Serial_Print // отладка для работы - закоментить
//------------------------------------------------
WiFiUDP Udp;
WiFiManager wifiManager;
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite ClockSpr = TFT_eSprite(&tft);
TFT_eSprite ScrollWeatherSpr = TFT_eSprite(&tft);
HTTPClient http;
WiFiClient client;
/*----- Weather Json -----*/
typedef struct {
float lon; // 37.71
float lat; // 51.84
String description; // "небольшая облачность"
String icon; // "03n"
float temp; // 12.56
float feels_like; // 11.96
int pressure; // 1022 // приведённое к уровню моря давление.
int humidity; // 80
int grnd_level; // 1001 // давление на местности
int visibility; // 10000
float speed; // 2.1
int deg; // 354
float gust; // 2.15
long dt; // 1686079705
String country; // "RU"
long sunrise; // 1686013976
long sunset; // 1686073370
long id; // 540121
String name; // "Кшенский"
} weather_t;
weather_t weather;
void draw_Clocktime();
void MSG_Weather_Print(String& MSG_W);
void draw_Scroll();
void TFT_weather_cur();
void draw_Sectime();
bool decode_json(Stream& jsonStr);
void Get_Weather_http(String& MSG_http);
void getWeather();
void restart();
void display_brightness();
void initWiFi();
void print_Img(int x, int y, String WeaIcon) {
int w, h; w=60; h=60;
if (WeaIcon == "01d") tft.pushImage(x,y,w,h,img_01d);
else if (WeaIcon == "01n") tft.pushImage(x,y,w,h,img_01n);
else if (WeaIcon == "02d") tft.pushImage(x,y,w,h,img_02d);
else if (WeaIcon == "02n") tft.pushImage(x,y,w,h,img_02n);
else if (WeaIcon == "03d" || WeaIcon == "03n") tft.pushImage(x,y,w,h,img_03dn);
else if (WeaIcon == "04d" || WeaIcon == "04n") tft.pushImage(x,y,w,h,img_04dn);
else if (WeaIcon == "09d" || WeaIcon == "09n") tft.pushImage(x,y,w,h,img_09dn);
else if (WeaIcon == "10d" || WeaIcon == "10n") tft.pushImage(x,y,w,h,img_10dn);
else if (WeaIcon == "11d" || WeaIcon == "11n") tft.pushImage(x,y,w,h,img_11dn);
else if (WeaIcon == "13d" || WeaIcon == "13n") tft.pushImage(x,y,w,h,img_13dn);
else if (WeaIcon == "50d" || WeaIcon == "50n") tft.pushImage(x,y,w,h,img_50dn);
Serial.println("Icon name: " + WeaIcon);
}// print_Img
/*------------ TFT Clocktime -----------------------------*/
void draw_Clocktime() {
uint8_t hh = hour(), mm = minute(), ss = second();
ClockSpr.setTextColor(TFT_WHITE, TFT_BLACK);
ClockSpr.setFreeFont(RU10);
ClockSpr.drawString(utf8rus( days[ weekday() ] ), 120, ypos + 20);
ClockSpr.setTextColor(TFT_YELLOW, TFT_BLACK);
ClockSpr.setFreeFont(DIG20);
if (weather.temp > 0)
ClockSpr.drawString(("+" + String(weather.temp,1) + "@C"), 120,ypos + 50);
else //@ - перерисован на знак градуса °C, текущая температура
ClockSpr.drawString((String(weather.temp,1) + "@C"), 120,ypos + 50);
ClockSpr.setFreeFont(RU10);
ClockSpr.setTextColor(TFT_GREENYELLOW, TFT_BLACK);
ClockSpr.drawString( utf8rus( String( day() ) + " " + months[ month() ] + " " + year()), 120, 10 );
ClockSpr.setTextColor(TFT_WHITE, TFT_BLACK);
byte omm = 99, oss = 99;
byte xcolon = 0;
int x_pos = 51; // // d:\arduino-1.8.19\...\libraries\TFT_eSPI\examples\320 x 240\TFT_Clock_Digital
ClockSpr.setTextDatum(TL_DATUM );
if (omm != mm) { // Обновлять часы и минуты каждую минуту
omm = mm; // рисуем часы и минуты
ClockSpr.setTextColor(TFT_WHITE, TFT_BLACK);
if (hh < 10) x_pos += ClockSpr.drawChar('0', x_pos, ypos - 40, 7); // Добавить 0 в часы
x_pos += ClockSpr.drawNumber(hh, x_pos, ypos - 40, 7); // рисуем часы
xcolon = x_pos; // Сохранение координат двоеточия, чтобы мигать позже
x_pos += ClockSpr.drawChar(':', x_pos, ypos - 40, 7);
if (mm < 10) x_pos += ClockSpr.drawChar('0', x_pos, ypos - 40, 7); // Добавить 0 в минуты
x_pos += ClockSpr.drawNumber(mm, x_pos, ypos - 40, 7); // рисуем минуты
}
if (oss != ss) { // Перерисовывать секунды каждую секунду
oss = ss;
if (ss % 2) { // Включить/выключить двоеточие
ClockSpr.setTextColor(TFT_BLACK, TFT_BLACK); // затемнить двоеточие
ClockSpr.drawChar(':', xcolon, ypos - 40, 7); // Час:минута двоеточие
ClockSpr.setTextColor(TFT_WHITE, TFT_BLACK); // Вернуть цвет
}
else {
ClockSpr.drawChar(':', xcolon, ypos - 40, 7); // Час:минута двоеточие
}
ClockSpr.setFreeFont(DIG20);
x_pos = 103;
if (ss < 10) x_pos += ClockSpr.drawNumber(0, x_pos, ypos - 65); // Добавить 0
ClockSpr.drawNumber(ss, x_pos, ypos - 65); // рисуем секунды
}
ClockSpr.setTextDatum(MC_DATUM);
} // end draw_Clocktime
/*------------ TFT draw_Sectime -----------------------------*/
void draw_Scroll() {
String MSG_Weather;
MSG_Weather.reserve(350);
MSG_Weather += F(" Погода ");
MSG_Weather += weather.name;
MSG_Weather += F(",");
MSG_Weather += weather.description;
MSG_Weather += F(",Температура ");
MSG_Weather += String(weather.temp,1);
MSG_Weather += F("@C,Ощущается как ");
MSG_Weather += String(weather.feels_like,1);
MSG_Weather += F("@C,Давление ");
MSG_Weather += String(weather.grnd_level * 0.750062, 0); // давление на местности
MSG_Weather += F(" мм,Влажность ");
MSG_Weather += String(weather.humidity);
MSG_Weather += F("%,Ветер ");
MSG_Weather += String(WindDeg_Direction(weather.deg));
MSG_Weather += F(",");
MSG_Weather += String(weather.speed, 1);
MSG_Weather += F(" м/c,Порывы ");
MSG_Weather += String(weather.gust, 1);
MSG_Weather += F(" м/c");
int16_t MSG_Weather_Width;//Ширина прокручиваемого всего сообщения в пикселях.
int Space_Repeats = 50; //Пробел между повторами в пикселях.
MSG_Weather_Width = tft.textWidth(utf8rus(MSG_Weather))+ Space_Repeats; // -60
ScrollWeatherSpr.createSprite(MSG_Weather_Width + TFT_W, 12 );
Step_Count--;
if (Step_Count <= 0) {
Step_Count = (MSG_Weather_Width / abs(Step_Scroll));
MSG_Weather_Print(MSG_Weather);
}
ScrollWeatherSpr.scroll(Step_Scroll); // Сдвиньте спрайт на пиксели Step_Scroll.
ScrollWeatherSpr.pushSprite(0, 247); // Верхний левый угол спрайта
} // end draw_Scroll
void TFT_weather_cur() // отрисовка прогноза погоды
{
String Sun_Time;
String Sun_Hour;
int x_Sun = 80; // координаты отрисовки
tft.fillRect ( 0, 259, 239, 60, TFT_BLACK); // Очистить Восход - Закат
print_Img(10, 259, weather.icon);
tft.setFreeFont(RU10);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK, true);
tft.drawString(utf8rus(weather.name), 80, 259); // нас. пункт
tft.setFreeFont(RU8);
tft.setTextSize(1);
tft.setTextColor(TFT_GREENYELLOW, TFT_BLACK, true);
time_t hour_t = hour(weather.sunrise + TIME_OFFSET); // Восход
time_t minute_t = minute(weather.sunrise + TIME_OFFSET);
if (hour_t < 10) // добавить 0 к часам Восход
Sun_Hour = "0" + String(hour_t);
else Sun_Hour = String(hour_t);
if (minute_t < 10) // добавить 0 к минутам Восход
Sun_Time = Sun_Hour + ":0" + String(minute_t);
else Sun_Time = Sun_Hour + ":" + String(minute_t);
x_Sun += tft.drawString(utf8rus("Восход:"), 80, 285); // Восход
tft.drawString(Sun_Time, x_Sun+5, 285); // Восход
hour_t = hour(weather.sunset + TIME_OFFSET); // Закат
minute_t = minute(weather.sunset + TIME_OFFSET);
if (minute_t < 10) // добавить 0 к минутам Закат
Sun_Time = String(hour_t) + ":0" + String(minute_t);
else Sun_Time = String(hour_t) + ":" + String(minute_t);
tft.drawString(utf8rus("Закат:"), 80, 303); // Закат
tft.drawString(Sun_Time, x_Sun+5, 303); // Закат
} // end TFT_weather_cur
/*------------ TFT draw_Sectime -----------------------------*/
void draw_Sectime() {
float value, circle = 100;
double rad = 0.01745;
String sec_t[12] = {"45", "40", "35", "30", "25", "20", "15", "10", "05", "0", "55", "50"};
int start[12], startP[60], angle = 0, r = 105, lastAngle = 0, rAngle = 359, b = 0, b2 = 0;
bool dir = 0;
for (int i = 0; i < 360; i++) {
x[i] = (r * cos(rad * i)) + xpos;
y[i] = (r * sin(rad * i)) + ypos;
px[i] = ((r - 16) * cos(rad * i)) + xpos;
py[i] = ((r - 16) * sin(rad * i)) + ypos;
lx[i] = ((r - 26) * cos(rad * i)) + xpos;
ly[i] = ((r - 26) * sin(rad * i)) + ypos;
if (i % 30 == 0) {
start[b] = i;
b++;
}
if (i % 6 == 0) {
startP[b2] = i;
b2++;
}
}
rAngle = rAngle - 2;
angle = second() * 6;
if (angle >= 360) angle = 0;
if (rAngle <= 0) rAngle = 359;
if (dir == 0) circle = circle + 0.5;
else circle = circle - 0.5;
if (circle > 140) dir = !dir;
if (circle < 100) dir = !dir;
if (angle > -1) {
lastAngle = angle;
value = ((angle - 270) / 3.60) * -1;
if (value < 0) value = value + 100;
ClockSpr.fillSprite(TFT_BLACK);
ClockSpr.fillCircle(xpos, ypos, 124, TFT_BLACK);
for (int i = 0; i < 12; i++)
if (start[i] + angle < 360) {
ClockSpr.drawString(sec_t[i], x[start[i] + angle], y[start[i] + angle], 2);
ClockSpr.drawLine(px[start[i] + angle], py[start[i] + angle], lx[start[i] + angle], ly[start[i] + angle], TFT_WHITE);
}
else {
ClockSpr.drawString(sec_t[i], x[(start[i] + angle) - 360], y[(start[i] + angle) - 360], 2);
ClockSpr.drawLine(px[(start[i] + angle) - 360], py[(start[i] + angle) - 360], lx[(start[i] + angle) - 360], ly[(start[i] + angle) - 360], TFT_WHITE);
}
for (int i = 0; i < 60; i++)
if (startP[i] + angle < 360)
ClockSpr.fillCircle(px[startP[i] + angle], py[startP[i] + angle], 1, TFT_YELLOW);
else
ClockSpr.fillCircle(px[(startP[i] + angle) - 360], py[(startP[i] + angle) - 360], 1, TFT_YELLOW);
ClockSpr.fillTriangle(xpos, ypos - 80, xpos - 3, ypos - 70, xpos + 3, ypos - 70, TFT_RED);
}
}// end draw_Sectime
void setup(void) {
pinMode(LED_BUILTIN, OUTPUT);
analogWrite(LED_BUILTIN, LED_BRIGHTNESS); // первоначальная яркость дисплея
Serial.begin(115200);
tft.begin();
tft.setSwapBytes(true); //*/
tft.setRotation(0);
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("Clock_Esp32");
tft.println(WiFi.SSID());
tft.print("IP: ");
tft.println(WiFi.localIP());
tft.println("Starting UDP");
Udp.begin(localPort);
tft.println("Time sync");
setSyncProvider(getNtpTime);
setSyncInterval(3600);
display_brightness();
delay(2500); // читаем что вывели на дисплей
if ( ENABLE_OTA_UPDATE )
{
tft.println("Begin OTA handler");
tft.println("Esp32-Clock");
initOTA(); // обновление по WiFi
}
tft.fillScreen(TFT_BLACK);
ClockSpr.setColorDepth(8);
ClockSpr.setSwapBytes(true);
ClockSpr.createSprite(240, 245);
ClockSpr.setTextDatum(MC_DATUM);
ScrollWeatherSpr.setTextDatum(TL_DATUM );
ScrollWeatherSpr.setColorDepth(1); // Глубина цвета сильно влияет на размер спрайта, который вы можете использовать, и на скорость его перемещения.
ScrollWeatherSpr.setSwapBytes(true);
ScrollWeatherSpr.setTextSize(2);
ScrollWeatherSpr.setFreeFont(RUSW);
getWeather();
TFT_weather_cur();
}// end setup
void loop() {
if ( ENABLE_OTA_UPDATE )
{
ArduinoOTA.handle();
}
if ((millis() > 60*1000) and (year() == 1970) and (WiFi.status() == WL_CONNECTED)) //при старте время не было задано
{
restart();
}
display_brightness();
draw_Sectime();
draw_Clocktime();
ClockSpr.pushSprite(0, 0);
// draw_Scroll();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
draw_Scroll();
previousMillis = currentMillis; }
if ((millis() - lastTime) > timerDelay*60*1000) {
getWeather();
TFT_weather_cur();
lastTime = millis(); }
} // end loop
bool decode_json(Stream& jsonStr)
{
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, jsonStr);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return false;
} else
{
Serial.println("deserializeJson() без ошибок.");
JsonObject doc_OPW = doc.as<JsonObject>();
weather.lon = doc_OPW["coord"]["lon"].as<float>();
weather.lat = doc_OPW["coord"]["lat"].as<float>();
weather.description = doc_OPW["weather"][0]["description"].as<const char *>();
weather.icon = doc_OPW["weather"][0]["icon"].as<const char *>();
weather.temp = doc_OPW["main"]["temp"].as<float>();
weather.feels_like = doc_OPW["main"]["feels_like"].as<float>();
weather.pressure = doc_OPW["main"]["pressure"].as<int>();
weather.humidity = doc_OPW["main"]["humidity"].as<int>();
weather.grnd_level = doc_OPW["main"]["grnd_level"].as<int>();
weather.visibility = doc_OPW["visibility"].as<int>();
weather.speed = doc_OPW["wind"]["speed"].as<float>();
weather.deg = doc_OPW["wind"]["deg"].as<int>();
weather.gust = doc_OPW["wind"]["gust"].as<float>();
weather.dt = doc_OPW["dt"].as<long>();
weather.country = doc_OPW["sys"]["country"].as<const char *>();
weather.sunrise = doc_OPW["sys"]["sunrise"].as<long>();
weather.sunset = doc_OPW["sys"]["sunset"].as<long>();
weather.id = doc_OPW["id"].as<long>();
weather.name = doc_OPW["name"].as<const char *>();
return true;
}//end else
}//end decode_json
void getWeather() {
if(WiFi.status()== WL_CONNECTED){ // проверяем соединение WiFi
String host_uri;
host_uri.reserve(150);
host_uri += F("http://api.openweathermap.org/data/2.5/");
host_uri += F("weather?lat=");
host_uri += Latitude;
host_uri += F("&lon=");
host_uri += Longitude;
host_uri += F("&lang=ru&appid=");
host_uri += apikey;
host_uri += F("&mode=json&units=metric&cnt=1");
client.stop();
Get_Weather_http(host_uri);
int httpCode = http.GET();
Serial.println(httpCode);
if (httpCode > 0) {
Stream& response = http.getStream(); // ответ
decode_json(response); // парсинг данных из JsonObject
#ifdef Serial_Print // отладка
Serial.println(" - - weather - - ");
Serial.print("weather.lon "); Serial.println(weather.lon);
Serial.print("weather.lat "); Serial.println(weather.lat);
Serial.print("weather.description "); Serial.println(weather.description);
Serial.print("weather.icon "); Serial.println(weather.icon);
Serial.print("weather.temp "); Serial.println(weather.temp);
Serial.print("weather.feels_like "); Serial.println(weather.feels_like);
Serial.print("weather.pressure "); Serial.println(weather.pressure);
Serial.print("weather.humidity "); Serial.println(weather.humidity);
Serial.print("weather.grnd_level "); Serial.println(weather.grnd_level);
Serial.print("weather.visibility "); Serial.println(weather.visibility);
Serial.print("weather.speed "); Serial.println(weather.speed);
Serial.print("weather.deg "); Serial.println(weather.deg);
Serial.print("weather.gust "); Serial.println(weather.gust);
Serial.print("weather.dt "); Serial.println(weather.dt);
Serial.print("weather.country "); Serial.println(weather.country);
Serial.print("weather.sunrise "); Serial.println(weather.sunrise);
Serial.print("weather.sunset "); Serial.println(weather.sunset);
Serial.print("weather.id "); Serial.println(weather.id);
Serial.print("weather.name "); Serial.println(weather.name);
#endif
client.stop();
http.end();
} else
{
Serial.println("Connection failed");
client.stop();
http.end();
}
}
} //end getWeather
String WindDeg_Direction(int Wind_direction) {
if (Wind_direction >= 338 || Wind_direction < 22) return Wind_N; //"Северный";
if (Wind_direction >= 22 && Wind_direction < 68) return Wind_NE; //"Северо-Восточный";
if (Wind_direction >= 68 && Wind_direction < 112) return Wind_E; //"Восточный";
if (Wind_direction >= 112 && Wind_direction < 158) return Wind_SE; //"Юго-Восточный";
if (Wind_direction >= 158 && Wind_direction < 202) return Wind_S; //"Южный";
if (Wind_direction >= 202 && Wind_direction < 248) return Wind_SW; //"Юго-Западный";
if (Wind_direction >= 248 && Wind_direction < 292) return Wind_W; //"Западный";
if (Wind_direction >= 292 && Wind_direction < 338) return Wind_NW; //"Северо-Западный";
return " ?";
} //end WindDeg_Direction
void restart() // перезапуск ESP32
{
Serial.println("Restart ESP...");
ESP.restart();
} // end restart
void display_brightness() // яркость дисплея
{
if ( ( hour() >= day_ ) and ( hour() < night_ ) )
{
analogWrite(LED_BUILTIN, slider_day);
}
else
{
analogWrite(LED_BUILTIN, slider_night);
}
} // end display_brightness
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin();
WiFi.persistent(false);
WiFi.setAutoReconnect(true);
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: ");
Serial.println(WiFi.localIP());
}
else {
Serial.println("WiFi not connected, starting WiFiManager");
tft.println("WiFi not connected..");
tft.println("Starting WiFiManager");
tft.println("SSID: ESP32-Clock");
tft.println("IP: 192.168.4.1");
wifiManager.autoConnect("ESP32-Clock");
delay(2000);
}
} // end initWiFi
void MSG_Weather_Print(String& MSG_W) {
ScrollWeatherSpr.drawString(utf8rus(MSG_W), TFT_W,0);
}
void Get_Weather_http(String& MSG_http) {
Serial.println(MSG_http);
http.begin(client, MSG_http);
}
/*-------------- 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;
secsSince1900 = (unsigned long)packetBuffer[40] << 24; //конвертируем 4 байта (начиная с позиции 40)
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
/*-------- ArduinoOTA code ----------*/
void initOTA()
{
ArduinoOTA.setHostname("Clock_Esp32");
Serial.println("Begin OTA handler Clock_Esp32");
// ArduinoOTA.setPassword("admin");
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
}
/*------- RUS fonts from UTF-8 to Windows-1251 -----*/
String utf8rus(String source)
{
int i, k;
String target;
unsigned char n;
char m[2] = { '0', '\0' };
k = source.length(); i = 0;
while (i < k) {
n = source[i]; i++;
if (n >= 127) {
switch (n) {
case 208: {
n = source[i]; i++;
if (n == 129) {
n = 192; // перекодируем букву Ё
break;
}
break;
}
case 209: {
n = source[i]; i++;
if (n == 145) {
n = 193; // перекодируем букву ё
break;
}
break;
}
}
}
m[0] = n; target = target + String(m);
}
return target;
}
//
settings.h
#ifndef SETTINGS_H
#define SETTINGS_H
unsigned long timerDelay = 60;// минуты -таймер обновления погоды
// Данные openweathermap.org
String apikey = F("ZxZxZxZxZxZxZxZxZxzxzx"); // API key
String Latitude = F("51.8408");
String Longitude = F("37.7136");
// настройки яркости дисплея
byte slider_day = 80; //Яркость день максимум 100
byte slider_night = 10; //Яркость ночь
byte night_ = 22; //ночь - время уменьшения яркости дисплея
byte day_ = 7; //день - время увеличения яркости дисплея
// время
static const char ntpServerName[] = "us.pool.ntp.org";
const int timeZone = 3; // часовой пояс: UTC+3 MSK
unsigned int localPort = 8888; // локальный порт для прослушивания UDP-пакетов
String months[13] = {"", "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"};
String days[8] = {"", "Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"};
//Ветер
const String Wind_N = F("Северный");
const String Wind_NE = F("Северо-Восточный");
const String Wind_E = F("Восточный");
const String Wind_SE = F("Юго-Восточный");
const String Wind_S = F("Южный");
const String Wind_SW = F("Юго-Западный");
const String Wind_W = F("Западный");
const String Wind_NW = F("Северо-Западный");
// Глобальные переменные
int Step_Count = 0; // Счетчик шагов прокрутки
const long interval = 320; // интервал прокрутки мсек
int Step_Scroll = -25; // шаг прокрутки
float x[360], y[360], px[360], py[360], lx[360], ly[360];
int xpos = 120, ypos = 135;
unsigned long previousMillis = 0;
unsigned long lastTime = 0;
#endif

