diff --git a/include/Const.h b/include/Const.h index c59d1981..0315a86a 100644 --- a/include/Const.h +++ b/include/Const.h @@ -35,6 +35,9 @@ #define USE_LITTLEFS false #endif +#define MIN_DATETIME 1575158400 +#define LEAP_YEAR(Y) (((1970 + Y) > 0) && !((1970 + Y) % 4) && (((1970 + Y) % 100) || !((1970 + Y) % 400))) + //задачи таскера enum TimerTask_t { WIFI_SCAN, WIFI_MQTT_CONNECTION_CHECK, diff --git a/include/Global.h b/include/Global.h index b0df99f8..72fee7b2 100644 --- a/include/Global.h +++ b/include/Global.h @@ -115,6 +115,23 @@ extern String prex; extern String all_widgets; extern String scenario; +// Time +struct Time_t { + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t day_of_week; + uint8_t day_of_month; + uint8_t month; + uint16_t day_of_year; + uint16_t year; + unsigned long days; + unsigned long valid; +}; + +extern Time_t _time_local; +extern Time_t _time_utc; + // extern DynamicJsonDocument settingsFlashJsonDoc; // extern DynamicJsonDocument paramsFlashJsonDoc; // extern DynamicJsonDocument paramsHeapJsonDoc; \ No newline at end of file diff --git a/include/Main.h b/include/Main.h index 46f0bc72..a8706969 100644 --- a/include/Main.h +++ b/include/Main.h @@ -13,3 +13,4 @@ #include "PeriodicTasks.h" #include "classes/IoTScenario.h" #include "EventsAndOrders.h" +#include "NTP.h" diff --git a/include/NTP.h b/include/NTP.h new file mode 100644 index 00000000..8ae14633 --- /dev/null +++ b/include/NTP.h @@ -0,0 +1,13 @@ +#pragma once +#include "Arduino.h" +#include "Global.h" + +static const uint8_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +extern void breakEpochToTime(unsigned long epoch, Time_t& tm); +extern void ntpInit(); +extern time_t getSystemTime(); +extern void synchTime(); +extern const String getTimeLocal_hhmm(); +extern const String getTimeLocal_hhmmss(); +extern const String getDateTimeDotFormated(); diff --git a/include/utils/TimeUtils.h b/include/utils/TimeUtils.h index 505883fa..7d3f3a0e 100644 --- a/include/utils/TimeUtils.h +++ b/include/utils/TimeUtils.h @@ -1,65 +1,5 @@ #pragma once +#include -#include "Global.h" - -#define ONE_MINUTE_s 60 -#define ONE_HOUR_m 60 -#define ONE_HOUR_s 60 * ONE_MINUTE_s -#define LEAP_YEAR(Y) (((1970 + Y) > 0) && !((1970 + Y) % 4) && (((1970 + Y) % 100) || !((1970 + Y) % 400))) -#define MIN_DATETIME 1575158400 -#define ONE_SECOND_ms 1000 - -/* - * Время (мс) прошедщее с @since - */ -unsigned long millis_since(unsigned long sinse); - -/* - * Интерввал времени (мс) между @start и @finish - */ -unsigned long millis_passed(unsigned long start, unsigned long finish); - -/* - * Форматиронное время интервала (мс) - * "чч:мм:cc", - * "дд чч:мм", если > 24 часов - */ -const String prettyMillis(unsigned long time_ms = millis()); - -/* - * Форматиронное время интервала (c) - * "чч:мм:cc", - * "дд чч:мм", если > 24 часов - */ -const String prettySeconds(unsigned long time_s); - -/* - * Тайм зона в секундах - */ -int getOffsetInSeconds(int timezone); - -/* - * Тайм зона в минутах - */ -int getOffsetInMinutes(int timezone); - -/* - * Разбивает время на составляющие - */ - -struct Time_t { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t day_of_week; - uint8_t day_of_month; - uint8_t month; - uint16_t day_of_year; - uint16_t year; - unsigned long days; - unsigned long valid; -}; - -void breakEpochToTime(unsigned long epoch, Time_t& tm); - -// void timeInit(); \ No newline at end of file +extern const String prettySeconds(unsigned long time_s); +extern const String prettyMillis(unsigned long time_ms); \ No newline at end of file diff --git a/src/Global.cpp b/src/Global.cpp index 70df3d3b..ab169f15 100644 --- a/src/Global.cpp +++ b/src/Global.cpp @@ -64,6 +64,10 @@ String all_widgets = ""; String scenario = ""; String mqttRootDevice = ""; +// Time +Time_t _time_local; +Time_t _time_utc; + // DynamicJsonDocument settingsFlashJsonDoc(JSON_BUFFER_SIZE); // DynamicJsonDocument paramsFlashJsonDoc(JSON_BUFFER_SIZE); // DynamicJsonDocument paramsHeapJsonDoc(JSON_BUFFER_SIZE); \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 19e5ceda..d89a376d 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -47,6 +47,9 @@ void setup() { //инициализация mqtt mqttInit(); + // NTP + ntpInit(); + //настраиваем микроконтроллер configure("/config.json"); @@ -72,13 +75,10 @@ void setup() { // симуляция добавления внешних событий // IoTItems.push_back((IoTItem*)new externalVariable("{\"id\":\"rel1\",\"val\":10,\"int\":20}")); // IoTItems.push_back((IoTItem*)new externalVariable("{\"id\":\"rel4\",\"val\":34,\"int\":30}")); - // пример получения JSON всех Items // Serial.println(getParamsJson()); - //чтение одного параметра // Serial.println(findIoTItem("t1")->getValue()); - //тест перебора пинов из расширения // for (int i = 109; i < 112; i++) { // IoTgpio.pinMode(i, OUTPUT); diff --git a/src/NTP.cpp b/src/NTP.cpp new file mode 100644 index 00000000..21bfef90 --- /dev/null +++ b/src/NTP.cpp @@ -0,0 +1,112 @@ +#include "NTP.h" + +#include "Global.h" +#include "Utils\SerialPrint.h" + +void ntpInit() { + synchTime(); + + ts.add( + TIME, 1000, [&](void*) { + unsigned long unixTime = getSystemTime(); + if (unixTime < MIN_DATETIME) { + // SerialPrint("E", "NTP", "Time not synched"); + synchTime(); + return; + } + breakEpochToTime(unixTime + 3 * 60 * 60, _time_local); + breakEpochToTime(unixTime, _time_utc); + String timenow = getTimeLocal_hhmm(); + static String prevTime; + if (prevTime != timenow) { + prevTime = timenow; + // jsonWriteStr(configLiveJson, "timenow", timenow); + SerialPrint("I", F("NTP"), getDateTimeDotFormated()); + } + }, + nullptr, true); + + SerialPrint("I", F("NTP"), F("Handle time init")); +} + +void synchTime() { + configTime(0, 0, "pool.ntp.org", "ru.pool.ntp.org", "pool.ntp.org"); +} + +time_t getSystemTime() { + timeval tv{0, 0}; + timezone tz = timezone{0, 0}; + time_t epoch = 0; + if (gettimeofday(&tv, &tz) != -1) { + epoch = tv.tv_sec; + } + return epoch; +} + +void breakEpochToTime(unsigned long epoch, Time_t& tm) { + // break the given time_input into time components + // this is a more compact version of the C library localtime function + + unsigned long time = epoch; + tm.second = time % 60; + time /= 60; // now it is minutes + tm.minute = time % 60; + time /= 60; // now it is hours + tm.hour = time % 24; + time /= 24; // now it is days + tm.days = time; + tm.day_of_week = ((time + 4) % 7) + 1; // Sunday is day 1 + + uint8_t year = 0; + unsigned long days = 0; + + while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm.year = year - 30; + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + tm.day_of_year = time; + + uint8_t month; + uint8_t month_length; + for (month = 0; month < 12; month++) { + if (1 == month) { // february + if (LEAP_YEAR(year)) { + month_length = 29; + } else { + month_length = 28; + } + } else { + month_length = days_in_month[month]; + } + + if (time >= month_length) { + time -= month_length; + } else { + break; + } + } + tm.month = month + 1; // jan is month 1 + tm.day_of_month = time + 1; // day of month + tm.valid = (epoch > MIN_DATETIME); +} + +const String getTimeLocal_hhmm() { + char buf[32]; + sprintf(buf, "%02d:%02d", _time_local.hour, _time_local.minute); + return String(buf); +} + +const String getTimeLocal_hhmmss() { + char buf[32]; + sprintf(buf, "%02d:%02d:%02d", _time_local.hour, _time_local.minute, _time_local.second); + return String(buf); +} + +const String getDateTimeDotFormated() { + char buf[32]; + sprintf(buf, "%02d.%02d.%02d %02d:%02d:%02d", _time_local.day_of_month, _time_local.month, _time_local.year, _time_local.hour, _time_local.minute, _time_local.second); + return String(buf); +} diff --git a/src/utils/TimeUtils.cpp b/src/utils/TimeUtils.cpp index 8eea8f06..8ed69931 100644 --- a/src/utils/TimeUtils.cpp +++ b/src/utils/TimeUtils.cpp @@ -1,6 +1,6 @@ -#include "utils/TimeUtils.h" - -static const uint8_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +#include "Utils\TimeUtils.h" +#include "Global.h" +#include "Utils\StringUtils.h" static const char* TIME_FORMAT PROGMEM = "%02d:%02d:%02d"; static const char* TIME_FORMAT_WITH_DAYS PROGMEM = "%dd %02d:%02d"; @@ -32,101 +32,4 @@ const String prettySeconds(unsigned long time_s) { const String prettyMillis(unsigned long time_ms) { return prettySeconds(time_ms / 1000); -} - -unsigned long millis_since(unsigned long sinse) { - return millis_passed(sinse, millis()); -} - -unsigned long millis_passed(unsigned long start, unsigned long finish) { - unsigned long result = 0; - if (start <= finish) { - unsigned long passed = finish - start; - if (passed <= __LONG_MAX__) { - result = static_cast(passed); - } else { - result = static_cast((__LONG_MAX__ - finish) + start + 1u); - } - } else { - unsigned long passed = start - finish; - if (passed <= __LONG_MAX__) { - result = static_cast(passed); - result = -1 * result; - } else { - result = static_cast((__LONG_MAX__ - start) + finish + 1u); - result = -1 * result; - } - } - return result; -} - -int getOffsetInSeconds(int timezone) { - return getOffsetInMinutes(timezone) * ONE_MINUTE_s; -} - -int getOffsetInMinutes(int timezone) { - return timezone * ONE_HOUR_m; -} - -void breakEpochToTime(unsigned long epoch, Time_t& tm) { - unsigned long time = epoch; - tm.second = time % 60; - time /= 60; // now it is minutes - tm.minute = time % 60; - time /= 60; // now it is hours - tm.hour = time % 24; - time /= 24; // now it is days - tm.days = time; - tm.day_of_week = ((time + 4) % 7) + 1; // Sunday is day 1 - - uint8_t year = 0; - unsigned long days = 0; - - while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { - year++; - } - tm.year = year - 30; - - days -= LEAP_YEAR(year) ? 366 : 365; - time -= days; // now it is days in this year, starting at 0 - tm.day_of_year = time; - - uint8_t month; - uint8_t month_length; - for (month = 0; month < 12; month++) { - if (1 == month) { // february - if (LEAP_YEAR(year)) { - month_length = 29; - } else { - month_length = 28; - } - } else { - month_length = days_in_month[month]; - } - - if (time >= month_length) { - time -= month_length; - } else { - break; - } - } - tm.month = month + 1; - tm.day_of_month = time + 1; - tm.valid = (epoch > MIN_DATETIME); -} - -// void timeInit() { -// ts.add( -// TIME, 1000, [&](void*) { -// String timenow = timeNow->getTimeWOsec(); -// static String prevTime; -// if (prevTime != timenow) { -// prevTime = timenow; -// jsonWriteStr(paramsFlashJson, "timenow", timenow); -// eventGen2("timenow", timenow); -// SerialPrint("i", F("NTP"), timenow); -// } -// }, -// nullptr, true); -// SerialPrint("i", F("NTP"), F("Handle time init")); -// } +} \ No newline at end of file