Текущая погода.
- Необходимо получить 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
По умолчанию эта библиотека будет работать для 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