Skip to content

Commit 9b0ae39

Browse files
committed
feature: Support NTP server for time consumption.
1 parent b92eb58 commit 9b0ae39

14 files changed

Lines changed: 47892 additions & 47124 deletions
6.88 KB
Binary file not shown.
58.8 KB
Binary file not shown.

webscreen/build/esp32.esp32.esp32s3/webscreen.ino.map

Lines changed: 47539 additions & 47118 deletions
Large diffs are not rendered by default.
0 Bytes
Binary file not shown.

webscreen/lvgl_elk.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <WiFiClientSecure.h>
1212
#include <ArduinoJson.h>
1313
#include <PubSubClient.h> // For MQTT
14+
#include <time.h>
1415

1516
#include <vector>
1617
#include <utility> // for std::pair
@@ -3295,6 +3296,67 @@ static jsval_t js_get_brightness(struct js *js, jsval_t *args, int nargs) {
32953296
return js_mknum((double)webscreen_display_get_brightness());
32963297
}
32973298

3299+
/******************************************************************************
3300+
* H3) NTP Time API
3301+
******************************************************************************/
3302+
3303+
static jsval_t js_get_hours(struct js *js, jsval_t *args, int nargs) {
3304+
struct tm timeinfo;
3305+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3306+
return js_mknum((double)timeinfo.tm_hour);
3307+
}
3308+
3309+
static jsval_t js_get_minutes(struct js *js, jsval_t *args, int nargs) {
3310+
struct tm timeinfo;
3311+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3312+
return js_mknum((double)timeinfo.tm_min);
3313+
}
3314+
3315+
static jsval_t js_get_seconds(struct js *js, jsval_t *args, int nargs) {
3316+
struct tm timeinfo;
3317+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3318+
return js_mknum((double)timeinfo.tm_sec);
3319+
}
3320+
3321+
static jsval_t js_get_year(struct js *js, jsval_t *args, int nargs) {
3322+
struct tm timeinfo;
3323+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3324+
return js_mknum((double)(timeinfo.tm_year + 1900));
3325+
}
3326+
3327+
static jsval_t js_get_month(struct js *js, jsval_t *args, int nargs) {
3328+
struct tm timeinfo;
3329+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3330+
return js_mknum((double)(timeinfo.tm_mon + 1)); // 1-12
3331+
}
3332+
3333+
static jsval_t js_get_day(struct js *js, jsval_t *args, int nargs) {
3334+
struct tm timeinfo;
3335+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3336+
return js_mknum((double)timeinfo.tm_mday);
3337+
}
3338+
3339+
static jsval_t js_get_weekday(struct js *js, jsval_t *args, int nargs) {
3340+
struct tm timeinfo;
3341+
if (!getLocalTime(&timeinfo, 10)) return js_mknum(-1);
3342+
return js_mknum((double)timeinfo.tm_wday); // 0=Sunday, 6=Saturday
3343+
}
3344+
3345+
static jsval_t js_get_epoch(struct js *js, jsval_t *args, int nargs) {
3346+
time_t now;
3347+
time(&now);
3348+
if (now < 1609459200) return js_mknum(-1); // Before 2021-01-01
3349+
return js_mknum((double)now);
3350+
}
3351+
3352+
static jsval_t js_ntp_synced(struct js *js, jsval_t *args, int nargs) {
3353+
struct tm timeinfo;
3354+
if (getLocalTime(&timeinfo, 10) && timeinfo.tm_year > (2020 - 1900)) {
3355+
return js_mktrue();
3356+
}
3357+
return js_mkfalse();
3358+
}
3359+
32983360
/******************************************************************************
32993361
* I) Register All JS Functions
33003362
******************************************************************************/
@@ -3311,6 +3373,18 @@ void register_js_functions() {
33113373
js_set(js, global, "delay", js_mkfun(js_delay));
33123374
js_set(js, global, "set_brightness", js_mkfun(js_set_brightness));
33133375
js_set(js, global, "get_brightness", js_mkfun(js_get_brightness));
3376+
3377+
// NTP Time functions
3378+
js_set(js, global, "get_hours", js_mkfun(js_get_hours));
3379+
js_set(js, global, "get_minutes", js_mkfun(js_get_minutes));
3380+
js_set(js, global, "get_seconds", js_mkfun(js_get_seconds));
3381+
js_set(js, global, "get_year", js_mkfun(js_get_year));
3382+
js_set(js, global, "get_month", js_mkfun(js_get_month));
3383+
js_set(js, global, "get_day", js_mkfun(js_get_day));
3384+
js_set(js, global, "get_weekday", js_mkfun(js_get_weekday));
3385+
js_set(js, global, "get_epoch", js_mkfun(js_get_epoch));
3386+
js_set(js, global, "ntp_synced", js_mkfun(js_ntp_synced));
3387+
33143388
js_set(js, global, "create_timer", js_mkfun(js_create_timer));
33153389
js_set(js, global, "toNumber", js_mkfun(js_to_number));
33163390
js_set(js, global, "numberToString", js_mkfun(js_number_to_string));

webscreen/serial_commands.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "webscreen_config.h"
44
#include "webscreen_hardware.h"
55
#include <WiFi.h>
6+
#include <time.h>
7+
#include <sys/time.h>
68
#include <esp_system.h>
79
#include <freertos/FreeRTOS.h>
810
#include <freertos/task.h>
@@ -89,6 +91,12 @@ void SerialCommands::processCommand(const String& command) {
8991
else if (baseCmd == "brightness") {
9092
setBrightness(args);
9193
}
94+
else if (baseCmd == "time") {
95+
showTime();
96+
}
97+
else if (baseCmd == "settime") {
98+
setTime(args);
99+
}
92100
else {
93101
printError("Unknown command: " + baseCmd + ". Type /help for available commands.");
94102
}
@@ -114,6 +122,8 @@ void SerialCommands::showHelp() {
114122
Serial.println("/backup [save|restore] - Backup/restore configuration");
115123
Serial.println("/monitor [cpu|mem|net] - Live system monitoring");
116124
Serial.println("/brightness <0-255> - Set display brightness");
125+
Serial.println("/time - Show current device time");
126+
Serial.println("/settime <epoch> [tz] - Set device time from epoch");
117127
Serial.println("/reboot - Restart the device");
118128
Serial.println("\nExamples:");
119129
Serial.println("/write hello.js");
@@ -1055,4 +1065,57 @@ void SerialCommands::setBrightness(const String& args) {
10551065

10561066
webscreen_display_set_brightness((uint8_t)brightness);
10571067
printSuccess("Brightness set to " + String(brightness));
1068+
}
1069+
1070+
void SerialCommands::showTime() {
1071+
struct tm timeinfo;
1072+
if (!getLocalTime(&timeinfo, 100)) {
1073+
printError("Time not available (NTP not synced)");
1074+
return;
1075+
}
1076+
1077+
Serial.printf("Current time: %04d-%02d-%02d %02d:%02d:%02d\n",
1078+
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
1079+
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
1080+
Serial.printf("Epoch: %lu\n", (unsigned long)mktime(&timeinfo));
1081+
Serial.printf("Day of week: %d (0=Sun)\n", timeinfo.tm_wday);
1082+
}
1083+
1084+
void SerialCommands::setTime(const String& args) {
1085+
String val = args;
1086+
val.trim();
1087+
1088+
if (val.length() == 0) {
1089+
printError("Usage: /settime <epoch> [timezone]");
1090+
return;
1091+
}
1092+
1093+
int spaceIndex = val.indexOf(' ');
1094+
String epochStr = (spaceIndex > 0) ? val.substring(0, spaceIndex) : val;
1095+
String tz = (spaceIndex > 0) ? val.substring(spaceIndex + 1) : "";
1096+
tz.trim();
1097+
1098+
unsigned long epoch = strtoul(epochStr.c_str(), NULL, 10);
1099+
if (epoch < 1609459200) { // Before 2021-01-01
1100+
printError("Invalid epoch value");
1101+
return;
1102+
}
1103+
1104+
struct timeval tv;
1105+
tv.tv_sec = epoch;
1106+
tv.tv_usec = 0;
1107+
settimeofday(&tv, NULL);
1108+
1109+
if (tz.length() > 0) {
1110+
setenv("TZ", tz.c_str(), 1);
1111+
tzset();
1112+
}
1113+
1114+
struct tm timeinfo;
1115+
getLocalTime(&timeinfo);
1116+
1117+
Serial.printf("Time set: %04d-%02d-%02d %02d:%02d:%02d\n",
1118+
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
1119+
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
1120+
printSuccess("Device time synchronized");
10581121
}

webscreen/serial_commands.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class SerialCommands {
2929
static void backup(const String& args);
3030
static void monitor(const String& args);
3131
static void setBrightness(const String& args);
32+
static void showTime();
33+
static void setTime(const String& args);
3234

3335
static void printPrompt();
3436
static String formatBytes(size_t bytes);

webscreen/webscreen.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ void setup() {
5757
// Don't return here - continue to check if script exists
5858
} else {
5959
LOG("Wi-Fi connected successfully.");
60+
webscreen_ntp_setup_from_config();
6061
}
6162
} else {
6263
LOG("No WiFi configured, running in offline mode.");

webscreen/webscreen_config.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#define WEBSCREEN_VERSION_MAJOR 2
1717
#define WEBSCREEN_VERSION_MINOR 0
1818
#define WEBSCREEN_VERSION_PATCH 0
19-
#define WEBSCREEN_VERSION_STRING "2.0.6"
19+
#define WEBSCREEN_VERSION_STRING "2.0.7"
2020

2121
// ============================================================================
2222
// HARDWARE CONFIGURATION
@@ -82,6 +82,10 @@
8282
#define WEBSCREEN_MQTT_KEEPALIVE_SEC 60
8383
#define WEBSCREEN_MQTT_MAX_PACKET_SIZE 1024
8484

85+
// NTP Configuration
86+
#define WEBSCREEN_NTP_SERVER_DEFAULT "pool.ntp.org"
87+
#define WEBSCREEN_NTP_SYNC_TIMEOUT_MS 10000
88+
8589
// ============================================================================
8690
// SYSTEM CONFIGURATION
8791
// ============================================================================

webscreen/webscreen_main.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ webscreen_config_t g_webscreen_config = { .wifi = {
3131
.auto_reconnect = true },
3232
.mqtt = { .broker = "", .port = 1883, .username = "", .password = "", .client_id = "webscreen_001", .enabled = false, .keepalive = WEBSCREEN_MQTT_KEEPALIVE_SEC },
3333
.display = { .brightness = 200, .rotation = WEBSCREEN_DISPLAY_ROTATION, .background_color = 0x000000, .foreground_color = 0xFFFFFF, .auto_brightness = false, .screen_timeout = 0 },
34-
.system = { .device_name = "WebScreen", .timezone = "UTC", .log_level = 2, .performance_mode = false, .watchdog_timeout = WEBSCREEN_WATCHDOG_TIMEOUT_SEC * 1000 },
34+
.system = { .device_name = "WebScreen", .timezone = "UTC", .ntp_server = "pool.ntp.org", .log_level = 2, .performance_mode = false, .watchdog_timeout = WEBSCREEN_WATCHDOG_TIMEOUT_SEC * 1000 },
3535
.script_file = "/app.js",
3636
.config_version = 2,
3737
.last_modified = 0 };
@@ -186,6 +186,23 @@ static bool load_configuration(void) {
186186
WEBSCREEN_DEBUG_PRINTF("Config: display.brightness = %d\n", g_webscreen_config.display.brightness);
187187
g_webscreen_config.system.log_level = doc["system"]["log_level"] | g_webscreen_config.system.log_level;
188188

189+
// Load timezone (check both system.timezone and top-level timezone for backward compat)
190+
if (doc["system"]["timezone"]) {
191+
WEBSCREEN_STR_COPY(g_webscreen_config.system.timezone,
192+
doc["system"]["timezone"], sizeof(g_webscreen_config.system.timezone));
193+
} else if (doc["timezone"]) {
194+
WEBSCREEN_STR_COPY(g_webscreen_config.system.timezone,
195+
doc["timezone"], sizeof(g_webscreen_config.system.timezone));
196+
}
197+
198+
// Load NTP server
199+
if (doc["system"]["ntp_server"]) {
200+
WEBSCREEN_STR_COPY(g_webscreen_config.system.ntp_server,
201+
doc["system"]["ntp_server"], sizeof(g_webscreen_config.system.ntp_server));
202+
}
203+
WEBSCREEN_DEBUG_PRINTF("Config: timezone=%s, ntp_server=%s\n",
204+
g_webscreen_config.system.timezone, g_webscreen_config.system.ntp_server);
205+
189206
if (doc["script_file"]) {
190207
WEBSCREEN_STR_COPY(g_webscreen_config.script_file,
191208
doc["script_file"], sizeof(g_webscreen_config.script_file));
@@ -326,9 +343,23 @@ bool webscreen_load_config(const char *path,
326343

327344
// Load display brightness into global config so init_lvgl_display() can apply it
328345
g_webscreen_config.display.brightness = doc["display"]["brightness"] | g_webscreen_config.display.brightness;
329-
WEBSCREEN_DEBUG_PRINTF("Config loaded - SSID: %s, Script: %s, MQTT: %s, Brightness: %d\n",
346+
347+
// Load timezone (check top-level first, then system.timezone)
348+
const char* tz = doc["timezone"] | (const char*)nullptr;
349+
if (!tz) tz = doc["system"]["timezone"] | (const char*)nullptr;
350+
if (tz) {
351+
WEBSCREEN_STR_COPY(g_webscreen_config.system.timezone, tz, sizeof(g_webscreen_config.system.timezone));
352+
}
353+
354+
// Load NTP server
355+
const char* ntp = doc["system"]["ntp_server"] | (const char*)nullptr;
356+
if (ntp) {
357+
WEBSCREEN_STR_COPY(g_webscreen_config.system.ntp_server, ntp, sizeof(g_webscreen_config.system.ntp_server));
358+
}
359+
360+
WEBSCREEN_DEBUG_PRINTF("Config loaded - SSID: %s, Script: %s, MQTT: %s, Brightness: %d, TZ: %s\n",
330361
outSSID.c_str(), outScript.c_str(), outMqttEnabled ? "enabled" : "disabled",
331-
g_webscreen_config.display.brightness);
362+
g_webscreen_config.display.brightness, g_webscreen_config.system.timezone);
332363

333364
return true;
334365
}

0 commit comments

Comments
 (0)