diff --git a/include/WebApi_ntp.h b/include/WebApi_ntp.h index f1d80f6..fae8781 100644 --- a/include/WebApi_ntp.h +++ b/include/WebApi_ntp.h @@ -12,6 +12,8 @@ private: void onNtpStatus(AsyncWebServerRequest* request); void onNtpAdminGet(AsyncWebServerRequest* request); void onNtpAdminPost(AsyncWebServerRequest* request); + void onNtpTimeGet(AsyncWebServerRequest* request); + void onNtpTimePost(AsyncWebServerRequest* request); AsyncWebServer* _server; }; \ No newline at end of file diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 828693f..47726d6 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -6,8 +6,8 @@ #include "ArduinoJson.h" #include "AsyncJson.h" #include "Configuration.h" -#include "helper.h" #include "NtpSettings.h" +#include "helper.h" void WebApiNtpClass::init(AsyncWebServer* server) { @@ -18,6 +18,8 @@ void WebApiNtpClass::init(AsyncWebServer* server) _server->on("/api/ntp/status", HTTP_GET, std::bind(&WebApiNtpClass::onNtpStatus, this, _1)); _server->on("/api/ntp/config", HTTP_GET, std::bind(&WebApiNtpClass::onNtpAdminGet, this, _1)); _server->on("/api/ntp/config", HTTP_POST, std::bind(&WebApiNtpClass::onNtpAdminPost, this, _1)); + _server->on("/api/ntp/time", HTTP_GET, std::bind(&WebApiNtpClass::onNtpTimeGet, this, _1)); + _server->on("/api/ntp/time", HTTP_POST, std::bind(&WebApiNtpClass::onNtpTimePost, this, _1)); } void WebApiNtpClass::loop() @@ -136,4 +138,132 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) NtpSettings.setServer(); NtpSettings.setTimezone(); +} + +void WebApiNtpClass::onNtpTimeGet(AsyncWebServerRequest* request) +{ + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject root = response->getRoot(); + + struct tm timeinfo; + if (!getLocalTime(&timeinfo, 0)) { + root[F("ntp_status")] = false; + } else { + root[F("ntp_status")] = true; + } + + root[F("year")] = timeinfo.tm_year + 1900; + root[F("month")] = timeinfo.tm_mon + 1; + root[F("day")] = timeinfo.tm_mday; + root[F("hour")] = timeinfo.tm_hour; + root[F("minute")] = timeinfo.tm_min; + root[F("second")] = timeinfo.tm_sec; + + response->setLength(); + request->send(response); +} + +void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) +{ + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject retMsg = response->getRoot(); + retMsg[F("type")] = F("warning"); + + if (!request->hasParam("data", true)) { + retMsg[F("message")] = F("No values found!"); + response->setLength(); + request->send(response); + return; + } + + String json = request->getParam("data", true)->value(); + + if (json.length() > 1024) { + retMsg[F("message")] = F("Data too large!"); + response->setLength(); + request->send(response); + return; + } + + DynamicJsonDocument root(1024); + DeserializationError error = deserializeJson(root, json); + + if (error) { + retMsg[F("message")] = F("Failed to parse data!"); + response->setLength(); + request->send(response); + return; + } + + if (!(root.containsKey("year") + && root.containsKey("month") + && root.containsKey("day") + && root.containsKey("hour") + && root.containsKey("minute") + && root.containsKey("second"))) { + retMsg[F("message")] = F("Values are missing!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("year")].as() < 2022 || root[F("year")].as() > 2100) { + retMsg[F("message")] = F("Year must be a number between 1 and 2100!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("month")].as() < 1 || root[F("month")].as() > 12) { + retMsg[F("message")] = F("Month must be a number between 1 and 12!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("day")].as() < 1 || root[F("day")].as() > 31) { + retMsg[F("message")] = F("Day must be a number between 1 and 31!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("hour")].as() < 0 || root[F("hour")].as() > 23) { + retMsg[F("message")] = F("Hour must be a number between 0 and 23!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("minute")].as() < 0 || root[F("minute")].as() > 59) { + retMsg[F("message")] = F("Minute must be a number between 0 and 59!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("second")].as() < 0 || root[F("second")].as() > 59) { + retMsg[F("message")] = F("Second must be a number between 0 and 59!"); + response->setLength(); + request->send(response); + return; + } + + tm local; + local.tm_sec = root[F("second")].as(); // seconds after the minute - [ 0 to 59 ] + local.tm_min = root[F("minute")].as(); // minutes after the hour - [ 0 to 59 ] + local.tm_hour = root[F("hour")].as(); // hours since midnight - [ 0 to 23 ] + local.tm_mday = root[F("day")].as(); // day of the month - [ 1 to 31 ] + local.tm_mon = root[F("month")].as() - 1; // months since January - [ 0 to 11 ] + local.tm_year = root[F("year")].as() - 1900; // years since 1900 + + time_t t = mktime(&local); + struct timeval now = { .tv_sec = t }; + settimeofday(&now, NULL); + + retMsg[F("type")] = F("success"); + retMsg[F("message")] = F("Time updated!"); + + response->setLength(); + request->send(response); } \ No newline at end of file