From 4eda9e965f9bb444bbfd82e624fd1b551e111837 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 15 Jan 2026 16:49:01 -1000 Subject: [PATCH] [api] Fix clock conflicts when multiple clients connected to homeassistant time (#13253) --- esphome/components/api/api_server.cpp | 4 +++- esphome/components/time/real_time_clock.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index a63d33f73b..ed97c3b9a2 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -558,8 +558,10 @@ bool APIServer::clear_noise_psk(bool make_active) { #ifdef USE_HOMEASSISTANT_TIME void APIServer::request_time() { for (auto &client : this->clients_) { - if (!client->flags_.remove && client->is_authenticated()) + if (!client->flags_.remove && client->is_authenticated()) { client->send_time_request(); + return; // Only request from one client to avoid clock conflicts + } } } #endif diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp index 639af4457f..f217d14c55 100644 --- a/esphome/components/time/real_time_clock.cpp +++ b/esphome/components/time/real_time_clock.cpp @@ -31,6 +31,18 @@ void RealTimeClock::dump_config() { void RealTimeClock::synchronize_epoch_(uint32_t epoch) { ESP_LOGVV(TAG, "Got epoch %" PRIu32, epoch); + // Skip if time is already synchronized to avoid unnecessary writes, log spam, + // and prevent clock jumping backwards due to network latency + constexpr time_t min_valid_epoch = 1546300800; // January 1, 2019 + time_t current_time = this->timestamp_now(); + // Check if time is valid (year >= 2019) before comparing + if (current_time >= min_valid_epoch) { + // Unsigned subtraction handles wraparound correctly, then cast to signed + int32_t diff = static_cast(epoch - static_cast(current_time)); + if (diff >= -1 && diff <= 1) { + return; + } + } // Update UTC epoch time. #ifdef USE_ZEPHYR struct timespec ts;