⏰ Refactors ntp service
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
let ntpStatus: NTPStatus;
|
let ntpStatus: NTPStatus;
|
||||||
|
|
||||||
async function getNTPStatus() {
|
async function getNTPStatus() {
|
||||||
const result = await api.get<NTPStatus>('/api/ntpStatus');
|
const result = await api.get<NTPStatus>('/api/ntp/status');
|
||||||
if (result.isErr()) {
|
if (result.isErr()) {
|
||||||
console.error('Error:', result.inner);
|
console.error('Error:', result.inner);
|
||||||
return;
|
return;
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getNTPSettings() {
|
async function getNTPSettings() {
|
||||||
const result = await api.get<NTPSettings>('/api/ntpSettings');
|
const result = await api.get<NTPSettings>('/api/ntp/settings');
|
||||||
if (result.isErr()) {
|
if (result.isErr()) {
|
||||||
console.error('Error:', result.inner);
|
console.error('Error:', result.inner);
|
||||||
return;
|
return;
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function postNTPSettings(data: NTPSettings) {
|
async function postNTPSettings(data: NTPSettings) {
|
||||||
const result = await api.post<NTPSettings>('/api/ntpSettings', data);
|
const result = await api.post<NTPSettings>('/api/ntp/settings', data);
|
||||||
if (result.isErr()) {
|
if (result.isErr()) {
|
||||||
notifications.error('User not authorized.', 3000);
|
notifications.error('User not authorized.', 3000);
|
||||||
console.error('Error:', result.inner);
|
console.error('Error:', result.inner);
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ ESP32SvelteKit::ESP32SvelteKit(PsychicHttpServer *server, unsigned int numberEnd
|
|||||||
_taskManager(),
|
_taskManager(),
|
||||||
_featureService(server),
|
_featureService(server),
|
||||||
_socket(server),
|
_socket(server),
|
||||||
#if FT_ENABLED(USE_NTP)
|
|
||||||
_ntpSettingsService(server, &ESPFS),
|
|
||||||
_ntpStatus(server),
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(USE_UPLOAD_FIRMWARE)
|
#if FT_ENABLED(USE_UPLOAD_FIRMWARE)
|
||||||
_uploadFirmwareService(server),
|
_uploadFirmwareService(server),
|
||||||
#endif
|
#endif
|
||||||
@@ -97,6 +93,18 @@ void ESP32SvelteKit::setupServer() {
|
|||||||
return _apService.endpoint.handleStateUpdate(request, json);
|
return _apService.endpoint.handleStateUpdate(request, json);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// NTP
|
||||||
|
#if FT_ENABLED(USE_NTP)
|
||||||
|
_server->on("/api/ntp/status", HTTP_GET, [this](PsychicRequest *r) { return _ntpService.getStatus(r); });
|
||||||
|
_server->on("/api/ntp/time", HTTP_POST,
|
||||||
|
[this](PsychicRequest *r, JsonVariant &json) { return _ntpService.handleTime(r, json); });
|
||||||
|
_server->on("/api/ntp/settings", HTTP_GET,
|
||||||
|
[this](PsychicRequest *request) { return _ntpService.endpoint.getState(request); });
|
||||||
|
_server->on("/api/ntp/settings", HTTP_POST, [this](PsychicRequest *request, JsonVariant &json) {
|
||||||
|
return _ntpService.endpoint.handleStateUpdate(request, json);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
// SYSTEM
|
// SYSTEM
|
||||||
_server->on("/api/system/reset", HTTP_POST, system_service::handleReset);
|
_server->on("/api/system/reset", HTTP_POST, system_service::handleReset);
|
||||||
_server->on("/api/system/restart", HTTP_POST, system_service::handleRestart);
|
_server->on("/api/system/restart", HTTP_POST, system_service::handleRestart);
|
||||||
@@ -182,8 +190,7 @@ void ESP32SvelteKit::startServices() {
|
|||||||
_downloadFirmwareService.begin();
|
_downloadFirmwareService.begin();
|
||||||
#endif
|
#endif
|
||||||
#if FT_ENABLED(USE_NTP)
|
#if FT_ENABLED(USE_NTP)
|
||||||
_ntpSettingsService.begin();
|
_ntpService.begin();
|
||||||
_ntpStatus.begin();
|
|
||||||
#endif
|
#endif
|
||||||
#if FT_ENABLED(USE_ANALYTICS)
|
#if FT_ENABLED(USE_ANALYTICS)
|
||||||
_analyticsService.begin();
|
_analyticsService.begin();
|
||||||
|
|||||||
@@ -30,10 +30,9 @@
|
|||||||
#include <EventSocket.h>
|
#include <EventSocket.h>
|
||||||
#include <FeaturesService.h>
|
#include <FeaturesService.h>
|
||||||
#include <MotionService.h>
|
#include <MotionService.h>
|
||||||
#include <NTPSettingsService.h>
|
#include <ntp_service.h>
|
||||||
#include <CameraService.h>
|
#include <CameraService.h>
|
||||||
#include <CameraSettingsService.h>
|
#include <CameraSettingsService.h>
|
||||||
#include <NTPStatus.h>
|
|
||||||
#include <PsychicHttp.h>
|
#include <PsychicHttp.h>
|
||||||
#include <TaskManager.h>
|
#include <TaskManager.h>
|
||||||
#include <UploadFirmwareService.h>
|
#include <UploadFirmwareService.h>
|
||||||
@@ -74,10 +73,6 @@ class ESP32SvelteKit {
|
|||||||
|
|
||||||
EventSocket *getSocket() { return &_socket; }
|
EventSocket *getSocket() { return &_socket; }
|
||||||
|
|
||||||
#if FT_ENABLED(USE_NTP)
|
|
||||||
StatefulService<NTPSettings> *getNTPSettingsService() { return &_ntpSettingsService; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FT_ENABLED(USE_BATTERY)
|
#if FT_ENABLED(USE_BATTERY)
|
||||||
BatteryService *getBatteryService() { return &_batteryService; }
|
BatteryService *getBatteryService() { return &_batteryService; }
|
||||||
#endif
|
#endif
|
||||||
@@ -117,8 +112,7 @@ class ESP32SvelteKit {
|
|||||||
APService _apService;
|
APService _apService;
|
||||||
EventSocket _socket;
|
EventSocket _socket;
|
||||||
#if FT_ENABLED(USE_NTP)
|
#if FT_ENABLED(USE_NTP)
|
||||||
NTPSettingsService _ntpSettingsService;
|
NTPService _ntpService;
|
||||||
NTPStatus _ntpStatus;
|
|
||||||
#endif
|
#endif
|
||||||
#if FT_ENABLED(USE_UPLOAD_FIRMWARE)
|
#if FT_ENABLED(USE_UPLOAD_FIRMWARE)
|
||||||
UploadFirmwareService _uploadFirmwareService;
|
UploadFirmwareService _uploadFirmwareService;
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <NTPSettingsService.h>
|
|
||||||
|
|
||||||
NTPSettingsService::NTPSettingsService(PsychicHttpServer *server, FS *fs)
|
|
||||||
: _server(server),
|
|
||||||
_httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH),
|
|
||||||
_fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE) {
|
|
||||||
addUpdateHandler([&](const String &originId) { configureNTP(); }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTPSettingsService::begin() {
|
|
||||||
WiFi.onEvent(
|
|
||||||
std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
|
||||||
WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
|
|
||||||
|
|
||||||
_httpEndpoint.begin();
|
|
||||||
_server->on(TIME_PATH, HTTP_POST,
|
|
||||||
[this](PsychicRequest *request, JsonVariant &json) { return configureTime(request, json); });
|
|
||||||
|
|
||||||
ESP_LOGV("NTPSettingsService", "Registered POST endpoint: %s", TIME_PATH);
|
|
||||||
|
|
||||||
_fsPersistence.readFromFS();
|
|
||||||
configureNTP();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTPSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { configureNTP(); }
|
|
||||||
|
|
||||||
void NTPSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { configureNTP(); }
|
|
||||||
|
|
||||||
void NTPSettingsService::configureNTP() {
|
|
||||||
if (WiFi.isConnected() && _state.enabled) {
|
|
||||||
configTzTime(_state.tzFormat.c_str(), _state.server.c_str());
|
|
||||||
} else {
|
|
||||||
setenv("TZ", _state.tzFormat.c_str(), 1);
|
|
||||||
tzset();
|
|
||||||
sntp_stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t NTPSettingsService::configureTime(PsychicRequest *request, JsonVariant &json) {
|
|
||||||
if (!sntp_enabled() && json.is<JsonObject>()) {
|
|
||||||
struct tm tm = {0};
|
|
||||||
String timeLocal = json["local_time"];
|
|
||||||
char *s = strptime(timeLocal.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
|
|
||||||
if (s != nullptr) {
|
|
||||||
time_t time = mktime(&tm);
|
|
||||||
struct timeval now = {.tv_sec = time};
|
|
||||||
settimeofday(&now, nullptr);
|
|
||||||
return request->reply(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return request->reply(400);
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
#ifndef NTPSettingsService_h
|
|
||||||
#define NTPSettingsService_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <HttpEndpoint.h>
|
|
||||||
#include <FSPersistence.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <ESPFS.h>
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <lwip/apps/sntp.h>
|
|
||||||
|
|
||||||
#ifndef FACTORY_NTP_ENABLED
|
|
||||||
#define FACTORY_NTP_ENABLED true
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_NTP_TIME_ZONE_LABEL
|
|
||||||
#define FACTORY_NTP_TIME_ZONE_LABEL "Europe/London"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_NTP_TIME_ZONE_FORMAT
|
|
||||||
#define FACTORY_NTP_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_NTP_SERVER
|
|
||||||
#define FACTORY_NTP_SERVER "time.google.com"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NTP_SETTINGS_SERVICE_PATH "/api/ntpSettings"
|
|
||||||
|
|
||||||
#define TIME_PATH "/api/time"
|
|
||||||
|
|
||||||
class NTPSettings {
|
|
||||||
public:
|
|
||||||
bool enabled;
|
|
||||||
String tzLabel;
|
|
||||||
String tzFormat;
|
|
||||||
String server;
|
|
||||||
|
|
||||||
static void read(NTPSettings &settings, JsonObject &root) {
|
|
||||||
root["enabled"] = settings.enabled;
|
|
||||||
root["server"] = settings.server;
|
|
||||||
root["tz_label"] = settings.tzLabel;
|
|
||||||
root["tz_format"] = settings.tzFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
static StateUpdateResult update(JsonObject &root, NTPSettings &settings) {
|
|
||||||
settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED;
|
|
||||||
settings.server = root["server"] | FACTORY_NTP_SERVER;
|
|
||||||
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
|
|
||||||
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class NTPSettingsService : public StatefulService<NTPSettings> {
|
|
||||||
public:
|
|
||||||
NTPSettingsService(PsychicHttpServer *server, FS *fs);
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
HttpEndpoint<NTPSettings> _httpEndpoint;
|
|
||||||
FSPersistence<NTPSettings> _fsPersistence;
|
|
||||||
|
|
||||||
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
void configureNTP();
|
|
||||||
esp_err_t configureTime(PsychicRequest *request, JsonVariant &json);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end NTPSettingsService_h
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <NTPStatus.h>
|
|
||||||
|
|
||||||
NTPStatus::NTPStatus(PsychicHttpServer *server) : _server(server) {}
|
|
||||||
|
|
||||||
void NTPStatus::begin() {
|
|
||||||
_server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET, [this](PsychicRequest *request) { return ntpStatus(request); });
|
|
||||||
|
|
||||||
ESP_LOGV("NTPStatus", "Registered GET endpoint: %s", NTP_STATUS_SERVICE_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Formats the time using the format provided.
|
|
||||||
*
|
|
||||||
* Uses a 25 byte buffer, large enough to fit an ISO time string with offset.
|
|
||||||
*/
|
|
||||||
String formatTime(tm *time, const char *format) {
|
|
||||||
char time_string[25];
|
|
||||||
strftime(time_string, 25, format, time);
|
|
||||||
return String(time_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
String toUTCTimeString(tm *time) { return formatTime(time, "%FT%TZ"); }
|
|
||||||
|
|
||||||
String toLocalTimeString(tm *time) { return formatTime(time, "%FT%T"); }
|
|
||||||
|
|
||||||
esp_err_t NTPStatus::ntpStatus(PsychicRequest *request) {
|
|
||||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
|
||||||
JsonObject root = response.getRoot();
|
|
||||||
|
|
||||||
// grab the current instant in unix seconds
|
|
||||||
time_t now = time(nullptr);
|
|
||||||
|
|
||||||
// only provide enabled/disabled status for now
|
|
||||||
root["status"] = sntp_enabled() ? 1 : 0;
|
|
||||||
|
|
||||||
// the current time in UTC
|
|
||||||
root["utc_time"] = toUTCTimeString(gmtime(&now));
|
|
||||||
|
|
||||||
// local time with offset
|
|
||||||
root["local_time"] = toLocalTimeString(localtime(&now));
|
|
||||||
|
|
||||||
// the sntp server name
|
|
||||||
root["server"] = sntp_getservername(0);
|
|
||||||
|
|
||||||
// device uptime in seconds
|
|
||||||
root["uptime"] = millis() / 1000;
|
|
||||||
|
|
||||||
return response.send();
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#ifndef NTPStatus_h
|
|
||||||
#define NTPStatus_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <lwip/apps/sntp.h>
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <PsychicHttp.h>
|
|
||||||
|
|
||||||
#define NTP_STATUS_SERVICE_PATH "/api/ntpStatus"
|
|
||||||
|
|
||||||
class NTPStatus {
|
|
||||||
public:
|
|
||||||
NTPStatus(PsychicHttpServer *server);
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
esp_err_t ntpStatus(PsychicRequest *request);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end NTPStatus_h
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <state_result.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#ifndef FACTORY_NTP_ENABLED
|
||||||
|
#define FACTORY_NTP_ENABLED true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FACTORY_NTP_TIME_ZONE_LABEL
|
||||||
|
#define FACTORY_NTP_TIME_ZONE_LABEL "Europe/London"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FACTORY_NTP_TIME_ZONE_FORMAT
|
||||||
|
#define FACTORY_NTP_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FACTORY_NTP_SERVER
|
||||||
|
#define FACTORY_NTP_SERVER "time.google.com"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class NTPSettings {
|
||||||
|
public:
|
||||||
|
bool enabled;
|
||||||
|
String tzLabel;
|
||||||
|
String tzFormat;
|
||||||
|
String server;
|
||||||
|
|
||||||
|
static void read(NTPSettings &settings, JsonObject &root) {
|
||||||
|
root["enabled"] = settings.enabled;
|
||||||
|
root["server"] = settings.server;
|
||||||
|
root["tz_label"] = settings.tzLabel;
|
||||||
|
root["tz_format"] = settings.tzFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StateUpdateResult update(JsonObject &root, NTPSettings &settings) {
|
||||||
|
settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED;
|
||||||
|
settings.server = root["server"] | FACTORY_NTP_SERVER;
|
||||||
|
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
|
||||||
|
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#include <ntp_service.h>
|
||||||
|
|
||||||
|
static const char *TAG = "NPT Service";
|
||||||
|
|
||||||
|
NTPService::NTPService()
|
||||||
|
: endpoint(NTPSettings::read, NTPSettings::update, this),
|
||||||
|
_persistence(NTPSettings::read, NTPSettings::update, this, &ESPFS, NTP_SETTINGS_FILE) {
|
||||||
|
addUpdateHandler([&](const String &originId) { configureNTP(); }, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTPService::begin() {
|
||||||
|
WiFi.onEvent(std::bind(&NTPService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
|
||||||
|
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
||||||
|
WiFi.onEvent(std::bind(&NTPService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2),
|
||||||
|
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
|
||||||
|
|
||||||
|
configureNTP();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Formats the time using the format provided.
|
||||||
|
*
|
||||||
|
* Uses a 25 byte buffer, large enough to fit an ISO time string with offset.
|
||||||
|
*/
|
||||||
|
const char *formatTime(const tm *time, const char *format) {
|
||||||
|
static char time_string[25];
|
||||||
|
strftime(time_string, sizeof(time_string), format, time);
|
||||||
|
return time_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *toUTCTimeString(const tm *time) { return formatTime(time, "%FT%TZ"); }
|
||||||
|
|
||||||
|
const char *toLocalTimeString(const tm *time) { return formatTime(time, "%FT%T"); }
|
||||||
|
|
||||||
|
esp_err_t NTPService::getStatus(PsychicRequest *request) {
|
||||||
|
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||||
|
JsonObject root = response.getRoot();
|
||||||
|
|
||||||
|
// grab the current instant in unix seconds
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
|
||||||
|
// only provide enabled/disabled status for now
|
||||||
|
root["status"] = sntp_enabled() ? 1 : 0;
|
||||||
|
|
||||||
|
// the current time in UTC
|
||||||
|
root["utc_time"] = toUTCTimeString(gmtime(&now));
|
||||||
|
|
||||||
|
// local time with offset
|
||||||
|
root["local_time"] = toLocalTimeString(localtime(&now));
|
||||||
|
|
||||||
|
// the sntp server name
|
||||||
|
root["server"] = sntp_getservername(0);
|
||||||
|
|
||||||
|
// device uptime in seconds
|
||||||
|
root["uptime"] = millis() / 1000;
|
||||||
|
|
||||||
|
return response.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTPService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
|
ESP_LOGI(TAG, "Got IP address, starting NTP Synchronization");
|
||||||
|
configureNTP();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTPService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||||
|
ESP_LOGD(TAG, "WiFi connection dropped, stopping NTP.");
|
||||||
|
configureNTP();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTPService::configureNTP() {
|
||||||
|
if (WiFi.isConnected() && _state.enabled) {
|
||||||
|
ESP_LOGI(TAG, "Starting NTP...");
|
||||||
|
configTzTime(_state.tzFormat.c_str(), _state.server.c_str());
|
||||||
|
} else {
|
||||||
|
setenv("TZ", _state.tzFormat.c_str(), 1);
|
||||||
|
tzset();
|
||||||
|
sntp_stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t NTPService::handleTime(PsychicRequest *request, JsonVariant &json) {
|
||||||
|
if (!sntp_enabled() && json.is<JsonObject>()) {
|
||||||
|
struct tm tm = {0};
|
||||||
|
String timeLocal = json["local_time"];
|
||||||
|
char *s = strptime(timeLocal.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
|
||||||
|
if (s != nullptr) {
|
||||||
|
time_t time = mktime(&tm);
|
||||||
|
struct timeval now = {.tv_sec = time};
|
||||||
|
settimeofday(&now, nullptr);
|
||||||
|
return request->reply(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request->reply(400);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef NTPService_h
|
||||||
|
#define NTPService_h
|
||||||
|
|
||||||
|
#include <ESPFS.h>
|
||||||
|
#include <FSPersistence.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <stateful_service_endpoint.h>
|
||||||
|
#include <domain/ntp_settings.h>
|
||||||
|
|
||||||
|
#include <lwip/apps/sntp.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
class NTPService : public StatefulService<NTPSettings> {
|
||||||
|
public:
|
||||||
|
NTPService();
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
static esp_err_t getStatus(PsychicRequest *request);
|
||||||
|
static esp_err_t handleTime(PsychicRequest *request, JsonVariant &json);
|
||||||
|
|
||||||
|
StatefulHttpEndpoint<NTPSettings> endpoint;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FSPersistence<NTPSettings> _persistence;
|
||||||
|
|
||||||
|
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
void configureNTP();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // end NTPService_h
|
||||||
Reference in New Issue
Block a user