time_sntp.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #include "defines.h"
  2. #include "Helper.h"
  3. #include "time_sntp.h"
  4. #include <string>
  5. #include <time.h>
  6. #include <sys/time.h>
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "freertos/event_groups.h"
  10. #include "esp_system.h"
  11. #include "esp_log.h"
  12. #include "esp_attr.h"
  13. #include "esp_sleep.h"
  14. #include "esp_netif_sntp.h"
  15. #include "ClassFlow.h"
  16. #include "ClassLogFile.h"
  17. static const char *TAG = "SNTP";
  18. static std::string timeZone = "";
  19. static std::string timeServer = "";
  20. static bool useNtp = true;
  21. static bool timeWasNotSetAtBoot = false;
  22. static bool timeWasNotSetAtBoot_PrintStartBlock = false;
  23. std::string getNtpStatusText(sntp_sync_status_t status);
  24. static void setTimeZone(std::string _tzstring);
  25. static std::string getServerName(void);
  26. int LocalTimeToUTCOffsetSeconds;
  27. std::string ConvertTimeToString(time_t _time, const char *frm)
  28. {
  29. struct tm timeinfo;
  30. char strftime_buf[64];
  31. localtime_r(&_time, &timeinfo);
  32. strftime(strftime_buf, sizeof(strftime_buf), frm, &timeinfo);
  33. std::string result(strftime_buf);
  34. return result;
  35. }
  36. std::string getCurrentTimeString(const char *frm)
  37. {
  38. time_t now;
  39. struct tm timeinfo;
  40. time(&now);
  41. char strftime_buf[64];
  42. localtime_r(&now, &timeinfo);
  43. strftime(strftime_buf, sizeof(strftime_buf), frm, &timeinfo);
  44. std::string result(strftime_buf);
  45. return result;
  46. }
  47. void time_sync_notification_cb(struct timeval *tv)
  48. {
  49. if (timeWasNotSetAtBoot_PrintStartBlock)
  50. {
  51. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
  52. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Start ======================");
  53. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "== Logs before time sync -> log_1970-01-01.txt ==");
  54. timeWasNotSetAtBoot_PrintStartBlock = false;
  55. }
  56. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is synced with NTP Server " + getServerName() + ": " + getCurrentTimeString("%Y-%m-%d %H:%M:%S"));
  57. }
  58. bool time_manual_reset_sync(void)
  59. {
  60. sntp_restart();
  61. // sntp_init();
  62. int retry = 0;
  63. const int retry_count = 10;
  64. while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count)
  65. {
  66. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Waiting for system time to be set... " + std::to_string(retry) + "/" + std::to_string(retry_count));
  67. vTaskDelay(2000 / portTICK_PERIOD_MS);
  68. }
  69. if (retry >= retry_count)
  70. {
  71. return false;
  72. }
  73. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Waiting for system time successfull with " + std::to_string(retry) + "/" + std::to_string(retry_count));
  74. return true;
  75. }
  76. int getUTCOffsetSeconds(std::string &zeitzone)
  77. {
  78. int offset = 0;
  79. int vorzeichen = 1;
  80. int minuten = 0;
  81. int stunden = 0;
  82. time_t now;
  83. struct tm timeinfo;
  84. time(&now);
  85. localtime_r(&now, &timeinfo);
  86. char buffer[80];
  87. strftime(buffer, 80, "%z", &timeinfo);
  88. zeitzone = std::string(buffer);
  89. if (zeitzone.length() == 5)
  90. {
  91. if (zeitzone[0] == '-')
  92. {
  93. vorzeichen = -1;
  94. }
  95. stunden = stoi(zeitzone.substr(1, 2));
  96. minuten = stoi(zeitzone.substr(3, 2));
  97. offset = ((stunden * 60) + minuten) * 60;
  98. }
  99. return offset;
  100. }
  101. void setTimeZone(std::string _tzstring)
  102. {
  103. setenv("TZ", _tzstring.c_str(), 1);
  104. tzset();
  105. _tzstring = "Time zone set to " + _tzstring;
  106. LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
  107. std::string zeitzone;
  108. LocalTimeToUTCOffsetSeconds = getUTCOffsetSeconds(zeitzone);
  109. // std::string zw = std::to_string(LocalTimeToUTCOffsetSeconds);
  110. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "time zone: " + zeitzone + " Delta to UTC: " + std::to_string(LocalTimeToUTCOffsetSeconds) + " seconds");
  111. }
  112. std::string getNtpStatusText(sntp_sync_status_t status)
  113. {
  114. if (status == SNTP_SYNC_STATUS_COMPLETED)
  115. {
  116. return "Synchronized";
  117. }
  118. else if (status == SNTP_SYNC_STATUS_IN_PROGRESS)
  119. {
  120. return "In Progress";
  121. }
  122. else
  123. {
  124. // SNTP_SYNC_STATUS_RESET
  125. return "Reset";
  126. }
  127. }
  128. bool getTimeIsSet(void)
  129. {
  130. time_t now;
  131. struct tm timeinfo;
  132. time(&now);
  133. localtime_r(&now, &timeinfo);
  134. // Is time set? If not, tm_year will be (1970 - 1900).
  135. if ((timeinfo.tm_year < (2022 - 1900)))
  136. {
  137. return false;
  138. }
  139. else
  140. {
  141. return true;
  142. }
  143. }
  144. bool getUseNtp(void)
  145. {
  146. return useNtp;
  147. }
  148. bool getTimeWasNotSetAtBoot(void)
  149. {
  150. return timeWasNotSetAtBoot;
  151. }
  152. std::string getServerName(void)
  153. {
  154. char buf[100];
  155. if (esp_sntp_getservername(0))
  156. {
  157. snprintf(buf, sizeof(buf), "%s", esp_sntp_getservername(0));
  158. return std::string(buf);
  159. }
  160. else
  161. {
  162. // we have either IPv4 or IPv6 address
  163. ip_addr_t const *ip = esp_sntp_getserver(0);
  164. if (ipaddr_ntoa_r(ip, buf, sizeof(buf)) != NULL)
  165. {
  166. return std::string(buf);
  167. }
  168. }
  169. return "";
  170. }
  171. /**
  172. * Load the TimeZone and TimeServer from the config file and initialize the NTP client
  173. */
  174. bool setupTime()
  175. {
  176. FILE *pFile = fopen(CONFIG_FILE, "r");
  177. if (pFile == NULL)
  178. {
  179. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "No ConfigFile defined - exit setupTime()!");
  180. return false;
  181. }
  182. ClassFlow classFlow;
  183. std::string aktparamgraph = "";
  184. while (classFlow.GetNextParagraph(pFile, aktparamgraph))
  185. {
  186. if ((to_upper(aktparamgraph).compare("[SYSTEM]") == 0) || (to_upper(aktparamgraph).compare(";[SYSTEM]") == 0))
  187. {
  188. break;
  189. }
  190. }
  191. if ((to_upper(aktparamgraph).compare("[SYSTEM]") != 0) && (to_upper(aktparamgraph).compare(";[SYSTEM]") != 0))
  192. {
  193. fclose(pFile);
  194. return false;
  195. }
  196. time_t now;
  197. struct tm timeinfo;
  198. char strftime_buf[64];
  199. std::vector<std::string> splitted;
  200. while (classFlow.getNextLine(pFile, &aktparamgraph) && !classFlow.isNewParagraph(aktparamgraph))
  201. {
  202. splitted = split_line(aktparamgraph);
  203. if (splitted.size() > 1)
  204. {
  205. std::string _param = to_upper(splitted[0]);
  206. if (_param == "TIMEZONE")
  207. {
  208. timeZone = splitted[1];
  209. }
  210. else if (_param == "TIMESERVER")
  211. {
  212. timeServer = splitted[1];
  213. }
  214. }
  215. }
  216. fclose(pFile);
  217. /* Setup NTP Server and Timezone */
  218. if (timeServer == "undefined")
  219. {
  220. timeServer = "pool.ntp.org";
  221. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeServer not defined, using default: " + timeServer);
  222. }
  223. else if (timeServer == "")
  224. {
  225. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeServer config empty, disabling NTP");
  226. useNtp = false;
  227. }
  228. else
  229. {
  230. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeServer: " + timeServer);
  231. }
  232. if (timeZone == "")
  233. {
  234. timeZone = "CET-1CEST,M3.5.0,M10.5.0/3";
  235. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeZone not set, using default: " + timeZone);
  236. }
  237. if (useNtp)
  238. {
  239. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
  240. esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeServer.c_str());
  241. config.sync_cb = time_sync_notification_cb;
  242. esp_netif_sntp_init(&config);
  243. setTimeZone(timeZone);
  244. }
  245. /* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
  246. * There should only be a minor correction through NTP */
  247. // Get current time from RTC
  248. time(&now);
  249. localtime_r(&now, &timeinfo);
  250. strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
  251. if (getTimeIsSet())
  252. {
  253. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
  254. }
  255. else
  256. {
  257. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "The local time is unknown, starting with " + std::string(strftime_buf));
  258. if (useNtp)
  259. {
  260. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Once the NTP server provides a time, we will switch to that one");
  261. timeWasNotSetAtBoot = true;
  262. timeWasNotSetAtBoot_PrintStartBlock = true;
  263. }
  264. }
  265. return true;
  266. }