diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index dea4851493..c2d7b08e59 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -386,6 +386,7 @@ json::SerializationBuffer<> WebServer::get_config_json() { #endif root[ESPHOME_F("log")] = this->expose_log_; root[ESPHOME_F("lang")] = "en"; + root[ESPHOME_F("uptime")] = static_cast(App.scheduler.millis_64() / 1000); return builder.serialize(); } @@ -412,7 +413,12 @@ void WebServer::setup() { // doesn't need defer functionality - if the queue is full, the client JS knows it's alive because it's clearly // getting a lot of events - this->set_interval(10000, [this]() { this->events_.try_send_nodefer("", "ping", millis(), 30000); }); + this->set_interval(10000, [this]() { + char buf[32]; + auto uptime = static_cast(App.scheduler.millis_64() / 1000); + buf_append_printf(buf, sizeof(buf), 0, "{\"uptime\":%u}", uptime); + this->events_.try_send_nodefer(buf, "ping", millis(), 30000); + }); } void WebServer::loop() { this->events_.loop(); } diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index b4227c55b6..36b65f6ff7 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -698,6 +698,8 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, NameType name_type return total_cancelled > 0; } +uint64_t Scheduler::millis_64() { return this->millis_64_(millis()); } + uint64_t Scheduler::millis_64_(uint32_t now) { // THREAD SAFETY NOTE: // This function has three implementations, based on the precompiler flags diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index 2aaa901e46..719633bff1 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -116,6 +116,9 @@ class Scheduler { ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0") bool cancel_retry(Component *component, uint32_t id); + /// Get 64-bit millisecond timestamp (handles 32-bit millis() rollover) + uint64_t millis_64(); + // Calculate when the next scheduled item should run // @param now Fresh timestamp from millis() - must not be stale/cached // Returns the time in milliseconds until the next scheduled item, or nullopt if no items