Uniot Core
0.9.0
Loading...
Searching...
No Matches
Date.h
Go to the documentation of this file.
1/*
2 * This is a part of the Uniot project.
3 * Copyright (C) 2016-2023 Uniot <contact@uniot.io>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
26
32
33#pragma once
34
35#if defined(ESP8266)
36#include <ESP8266WiFi.h>
37#include <coredecls.h>
38#elif defined(ESP32)
39#include <WiFi.h>
40#include <esp_sntp.h>
41#endif
42
43#include <DateEvents.h>
44#include <CBORStorage.h>
45#include <EventEmitter.h>
46#include <IExecutor.h>
47#include <SimpleNTP.h>
48#include <Singleton.h>
49#include <TaskScheduler.h>
50#include <time.h>
51
52namespace uniot {
66class Date : public IExecutor, public CBORStorage, public Singleton<Date>, public CoreEventEmitter {
67 friend class Singleton<Date>;
68
69 public:
75 static time_t now() {
76 return getInstance()._now();
77 }
78
84 static String getFormattedTime() {
85 return getInstance()._getFormattedTime();
86 }
87
97 bool store() override {
98 CBORStorage::object().put("epoch", static_cast<int64_t>(this->_now()));
99 return CBORStorage::store();
100 }
101
111 bool restore() override {
112 if (CBORStorage::restore()) {
113 auto currentEpoch = CBORStorage::object().getInt("epoch");
114 _setTime(currentEpoch);
115 return true;
116 }
117 UNIOT_LOG_ERROR("%s", "epoch not restored");
118 return false;
119 }
120
128 virtual void execute(short _) override {
129 if (!this->store()) {
130 UNIOT_LOG_ERROR("failed to store current epoch in CBORStorage");
131 }
132 }
133
144 return mTaskSync;
145 }
146
154 void forceSync() {
155 _reconfigure();
156 auto epoch = mSNTP.getNtpTime();
157 if (epoch) {
158 _setTime(epoch);
159 } else {
161 }
162 }
163
164 private:
171 Date() : CBORStorage("date.cbor") {
172 // A sync is reported from contexts where storing or emitting events is unsafe. On ESP8266
173 // the core runs settimeofday_cb from inside yield(), including the yields LittleFS makes
174 // while it writes, so a store there nests one filesystem operation inside another. On
175 // ESP32 the SNTP callback runs on the network task, concurrently with the loop. The
176 // callbacks therefore only trigger mTaskSync, and the store and the event run on the
177 // scheduler. This also makes a forced sync store the new time: SimpleNTP reports before
178 // forceSync() has applied it.
179 mTaskSync = TaskScheduler::make([](SchedulerTask &, short) {
180 Date::getInstance()._timeSyncCallback();
181 });
182
183#if defined(ESP8266)
184 settimeofday_cb([](bool) {
185 Date::getInstance().mTaskSync->trigger();
186 });
187#elif defined(ESP32)
188 sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED);
189 sntp_set_time_sync_notification_cb([](struct timeval *) {
190 Date::getInstance().mTaskSync->trigger();
191 });
192#endif
193 mSNTP.setSyncTimeCallback([](time_t) {
194 Date::getInstance().mTaskSync->trigger();
195 });
196
197 _reconfigure();
198
199 this->restore();
200 }
201
208 void _timeSyncCallback() {
209 execute(0);
210 UNIOT_LOG_INFO("time synchronized");
212 }
213
223 bool _setTime(time_t epoch) {
224#if defined(ESP8266)
225 tune_timeshift64(epoch * 1000000ULL);
226#elif defined(ESP32)
227 timeval tv = {epoch, 0};
228 if (settimeofday(&tv, nullptr) != 0) {
229 UNIOT_LOG_ERROR("failed to set system time");
230 return false;
231 }
232#endif
233 return true;
234 }
235
241 void _reconfigure() {
242 configTime(0, 0, SimpleNTP::servers[0], SimpleNTP::servers[1], SimpleNTP::servers[2]);
243 }
244
250 time_t _now() {
251 return time(nullptr);
252 }
253
262 String _getFormattedTime() {
263 tm tm;
264 auto currentEpoc = this->_now();
265 localtime_r(&currentEpoc, &tm);
266
267 char formattedTime[72] = {0};
268 snprintf(formattedTime, sizeof(formattedTime), "%04d-%02d-%02d %02d:%02d:%02d",
269 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
270 tm.tm_hour, tm.tm_min, tm.tm_sec);
271
272 return String(formattedTime);
273 }
274
276 SimpleNTP mSNTP;
277
279 TaskScheduler::TaskPtr mTaskSync;
280};
281
282} // namespace uniot
Date and time event definitions for the Uniot event system.
long getInt(int key) const
Get an integer value at a specific integer key.
Definition CBORObject.h:409
CBORObject & put(int key, int value)
Put an integer value at a specific integer key.
Definition CBORObject.h:180
Definition CBORStorage.h:39
virtual bool restore() override
Restore the CBOR object from the filesystem.
Definition CBORStorage.h:102
virtual bool store() override
Store the CBOR object to the filesystem.
Definition CBORStorage.h:74
CBORStorage(const String &path)
Constructs a new CBORStorage object.
Definition CBORStorage.h:46
CBORObject & object()
Get access to the underlying CBORObject.
Definition CBORStorage.h:60
Definition Date.h:66
TaskScheduler::TaskPtr getSyncTask()
Get the task that stores and reports time synchronizations.
Definition Date.h:143
virtual void execute(short _) override
Periodic execution callback.
Definition Date.h:128
bool restore() override
Restores time from persistent storage.
Definition Date.h:111
static String getFormattedTime()
Gets the current time in human-readable format.
Definition Date.h:84
bool store() override
Stores the current time to persistent storage.
Definition Date.h:97
void forceSync()
Forces immediate NTP time synchronization.
Definition Date.h:154
static time_t now()
Returns the current Unix timestamp.
Definition Date.h:75
void emitEvent(unsigned int topic, int msg)
Interface for executing tasks in the scheduler system.
Definition IExecutor.h:31
Definition TaskScheduler.h:67
static constexpr const char * servers[]
Array of NTP server hostnames to try connecting to.
Definition SimpleNTP.h:34
Singleton(const Singleton &)=delete
static Date & getInstance()
Definition Singleton.h:73
EventEmitter< unsigned int, int, Bytes > CoreEventEmitter
A specialized EventEmitter for core system events.
Definition EventEmitter.h:78
#define UNIOT_LOG_INFO(...)
Log an INFO level message Used for general information about system operation. Only compiled if UNIOT...
Definition Logger.h:315
#define UNIOT_LOG_ERROR(...)
Log an ERROR level message Used for critical errors that may prevent normal operation....
Definition Logger.h:273
SharedPointer< SchedulerTask > TaskPtr
Shared pointer type for scheduler tasks.
Definition TaskScheduler.h:190
static TaskPtr make(SchedulerTask::SchedulerTaskCallback callback)
Static factory method to create a task with a callback.
Definition TaskScheduler.h:212
@ TIME
Time synchronization and date-related operations.
Definition DateEvents.h:61
@ SYNCED
System time has been successfully synchronized with time source.
Definition DateEvents.h:72
@ SYNC_FAILED
Forced NTP synchronization attempt failed (no response from any server)
Definition DateEvents.h:73
Contains all classes and functions related to the Uniot Core.