[Telink] SNTP get time from openthread network. (Auto-merged by platform-bot)
diff --git a/config/telink/chip-module/Kconfig.defaults b/config/telink/chip-module/Kconfig.defaults
index bd2f846..378a71c 100644
--- a/config/telink/chip-module/Kconfig.defaults
+++ b/config/telink/chip-module/Kconfig.defaults
@@ -386,6 +386,9 @@
 config CHIP_OPENTHREAD_NETWORK_SWITCH_PATH
     default y
 
+config OPENTHREAD_SNTP_CLIENT
+    default y if OPENTHREAD_SOURCES
+
 endif # NET_L2_OPENTHREAD
 
 config NET_TX_STACK_SIZE
diff --git a/examples/air-quality-sensor-app/telink/CMakeLists.txt b/examples/air-quality-sensor-app/telink/CMakeLists.txt
index f2d7d12..d521969 100644
--- a/examples/air-quality-sensor-app/telink/CMakeLists.txt
+++ b/examples/air-quality-sensor-app/telink/CMakeLists.txt
@@ -60,3 +60,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/all-clusters-app/telink/CMakeLists.txt b/examples/all-clusters-app/telink/CMakeLists.txt
index 6e290ff..3894d85 100644
--- a/examples/all-clusters-app/telink/CMakeLists.txt
+++ b/examples/all-clusters-app/telink/CMakeLists.txt
@@ -81,3 +81,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/all-clusters-minimal-app/telink/CMakeLists.txt b/examples/all-clusters-minimal-app/telink/CMakeLists.txt
index 5f47464..3577915 100644
--- a/examples/all-clusters-minimal-app/telink/CMakeLists.txt
+++ b/examples/all-clusters-minimal-app/telink/CMakeLists.txt
@@ -61,3 +61,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/all-devices-app/telink/CMakeLists.txt b/examples/all-devices-app/telink/CMakeLists.txt
index 7b9262b..65cc027 100644
--- a/examples/all-devices-app/telink/CMakeLists.txt
+++ b/examples/all-devices-app/telink/CMakeLists.txt
@@ -98,3 +98,8 @@
 if (CONFIG_CHIP_PW_RPC)
   include(${TELINK_COMMON}/Rpc.cmake)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/bridge-app/telink/CMakeLists.txt b/examples/bridge-app/telink/CMakeLists.txt
index 12a4712..4c16e8d 100644
--- a/examples/bridge-app/telink/CMakeLists.txt
+++ b/examples/bridge-app/telink/CMakeLists.txt
@@ -60,3 +60,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/chef/telink/CMakeLists.txt b/examples/chef/telink/CMakeLists.txt
index 1199843..8eed61d 100755
--- a/examples/chef/telink/CMakeLists.txt
+++ b/examples/chef/telink/CMakeLists.txt
@@ -90,3 +90,8 @@
 if (CONFIG_CHIP_PW_RPC)
   include(${TELINK_COMMON}/Rpc.cmake)
 endif(CONFIG_CHIP_PW_RPC)
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/contact-sensor-app/telink/CMakeLists.txt b/examples/contact-sensor-app/telink/CMakeLists.txt
index 9889215..68c69a4 100755
--- a/examples/contact-sensor-app/telink/CMakeLists.txt
+++ b/examples/contact-sensor-app/telink/CMakeLists.txt
@@ -58,3 +58,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/light-switch-app/telink/CMakeLists.txt b/examples/light-switch-app/telink/CMakeLists.txt
index 3f252b9..776eb12 100755
--- a/examples/light-switch-app/telink/CMakeLists.txt
+++ b/examples/light-switch-app/telink/CMakeLists.txt
@@ -68,3 +68,8 @@
 if (CONFIG_CHIP_PW_RPC)
   include(${TELINK_COMMON}/Rpc.cmake)
 endif(CONFIG_CHIP_PW_RPC)
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/lighting-app/telink/CMakeLists.txt b/examples/lighting-app/telink/CMakeLists.txt
index 8ffe1e4..f150610 100644
--- a/examples/lighting-app/telink/CMakeLists.txt
+++ b/examples/lighting-app/telink/CMakeLists.txt
@@ -100,3 +100,8 @@
 if (CONFIG_CHIP_PW_RPC)
   include(${TELINK_COMMON}/Rpc.cmake)
 endif(CONFIG_CHIP_PW_RPC)
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/lock-app/telink/CMakeLists.txt b/examples/lock-app/telink/CMakeLists.txt
index 1fc084e..c418ef4 100755
--- a/examples/lock-app/telink/CMakeLists.txt
+++ b/examples/lock-app/telink/CMakeLists.txt
@@ -66,3 +66,8 @@
     zephyr_library_link_libraries(MCUBOOT_BOOTUTIL)
     target_sources(app PRIVATE ${TELINK_COMMON}/util/src/DFUOverSMP.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/ota-requestor-app/telink/CMakeLists.txt b/examples/ota-requestor-app/telink/CMakeLists.txt
index 9eec996..cad9e1e 100644
--- a/examples/ota-requestor-app/telink/CMakeLists.txt
+++ b/examples/ota-requestor-app/telink/CMakeLists.txt
@@ -58,3 +58,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/platform/telink/common/src/AppTaskCommon.cpp b/examples/platform/telink/common/src/AppTaskCommon.cpp
index 7743fa8..ad8df84 100644
--- a/examples/platform/telink/common/src/AppTaskCommon.cpp
+++ b/examples/platform/telink/common/src/AppTaskCommon.cpp
@@ -27,6 +27,9 @@
 
 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
 #include "ThreadUtil.h"
+#if CONFIG_OPENTHREAD_SNTP_CLIENT
+#include "ThreadTimeSync.h"
+#endif
 #elif CHIP_DEVICE_CONFIG_ENABLE_WIFI
 #include <platform/Zephyr/InetUtils.h>
 #include <platform/telink/wifi/TelinkWiFiDriver.h>
@@ -812,6 +815,12 @@
 #endif
         break;
     case DeviceEventType::kThreadStateChange:
+#if CONFIG_OPENTHREAD_SNTP_CLIENT
+        if (ConnectivityMgr().IsThreadAttached())
+        {
+            ThreadTimeSync::getInstance().sync_dns("pool.ntp.org");
+        }
+#endif
         sIsNetworkProvisioned = ConnectivityMgr().IsThreadProvisioned();
         sIsNetworkEnabled     = ConnectivityMgr().IsThreadEnabled();
         sIsNetworkAttached    = ConnectivityMgr().IsThreadAttached();
diff --git a/examples/platform/telink/util/include/ThreadTimeSync.h b/examples/platform/telink/util/include/ThreadTimeSync.h
new file mode 100644
index 0000000..399f402
--- /dev/null
+++ b/examples/platform/telink/util/include/ThreadTimeSync.h
@@ -0,0 +1,50 @@
+/*
+ *    Copyright (c) 2026 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <openthread/dns_client.h>
+#include <openthread/ip6.h>
+#include <openthread/sntp.h>
+
+class ThreadTimeSync
+{
+public:
+    static ThreadTimeSync & getInstance();
+
+    bool has_been_sync() { return static_cast<bool>(m_already_sync.load()); }
+    void sync_ip(const otIp6Address * server_ipv6, bool force = false);
+    void sync_dns(const char * server_name, bool force = false);
+
+    ThreadTimeSync(ThreadTimeSync const &) = delete;
+    void operator=(ThreadTimeSync const &) = delete;
+
+private:
+    static void on_ntp_ip_response_wrap(otError error, const otDnsAddressResponse * resp, void * ctx);
+    static void on_ntp_time_response_wrap(void * ctx, uint64_t time, otError error);
+
+    ThreadTimeSync() : m_in_progress(false), m_already_sync(false) {}
+    void sync_ip_internal(const otIp6Address * server_ipv6);
+
+    constexpr static const char * m_unit_name = "ThreadTimeSync";
+
+    std::atomic<int> m_in_progress;
+    std::atomic<int> m_already_sync;
+    otMessageInfo m_sntp_msg_info;
+    const otSntpQuery m_sntp_query = { .mMessageInfo = &m_sntp_msg_info };
+};
diff --git a/examples/platform/telink/util/src/ThreadTimeSync.cpp b/examples/platform/telink/util/src/ThreadTimeSync.cpp
new file mode 100644
index 0000000..858f3d8
--- /dev/null
+++ b/examples/platform/telink/util/src/ThreadTimeSync.cpp
@@ -0,0 +1,150 @@
+/*
+ *
+ *    Copyright (c) 2026 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "ThreadTimeSync.h"
+#include <ctime>
+#include <system/SystemClock.h>
+#include <zephyr/net/openthread.h>
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(ThreadTimeSync, CONFIG_CHIP_APP_LOG_LEVEL);
+
+ThreadTimeSync & ThreadTimeSync::getInstance()
+{
+    static ThreadTimeSync instance;
+
+    return instance;
+}
+
+void ThreadTimeSync::sync_ip(const otIp6Address * server_ipv6, bool force)
+{
+    if (m_already_sync.load() && !force)
+    {
+        return;
+    }
+
+    int expected_in_process = false;
+
+    if (!m_in_progress.compare_exchange_strong(expected_in_process, true))
+    {
+        LOG_DBG("[%s] operation in process", m_unit_name);
+        return;
+    }
+
+    sync_ip_internal(server_ipv6);
+}
+
+void ThreadTimeSync::sync_dns(const char * server_name, bool force)
+{
+    if (m_already_sync.load() && !force)
+    {
+        return;
+    }
+
+    int expected_in_process = false;
+
+    if (!m_in_progress.compare_exchange_strong(expected_in_process, true))
+    {
+        LOG_DBG("[%s] operation in process", m_unit_name);
+        return;
+    }
+
+    LOG_DBG("[%s] sync_dns %s", m_unit_name, server_name);
+    otError error =
+        otDnsClientResolveIp4Address(openthread_get_default_instance(), server_name, on_ntp_ip_response_wrap, this, nullptr);
+
+    if (error != OT_ERROR_NONE)
+    {
+        m_in_progress.store(false);
+        LOG_WRN("[%s] otDnsClientResolveIp4Address request failed %u", m_unit_name, error);
+    }
+}
+
+void ThreadTimeSync::sync_ip_internal(const otIp6Address * server_ipv6)
+{
+    char server_ipv6_str[OT_IP6_ADDRESS_STRING_SIZE];
+
+    otIp6AddressToString(server_ipv6, server_ipv6_str, sizeof(server_ipv6_str));
+    LOG_DBG("[%s] sync_ip %s", m_unit_name, server_ipv6_str);
+    memset(&m_sntp_msg_info, 0, sizeof(m_sntp_msg_info));
+    m_sntp_msg_info.mPeerAddr = *server_ipv6;
+    m_sntp_msg_info.mPeerPort = 123;
+
+    otError error = otSntpClientQuery(openthread_get_default_instance(), &m_sntp_query, on_ntp_time_response_wrap, this);
+
+    if (error != OT_ERROR_NONE)
+    {
+        m_in_progress.store(false);
+        LOG_WRN("[%s] otSntpClientQuery request failed %u", m_unit_name, error);
+    }
+}
+
+void ThreadTimeSync::on_ntp_ip_response_wrap(otError error, const otDnsAddressResponse * resp, void * ctx)
+{
+    ThreadTimeSync * thread_time_sync = static_cast<ThreadTimeSync *>(ctx);
+
+    if (error == OT_ERROR_NONE)
+    {
+        otIp6Address addr;
+        if (otDnsAddressResponseGetAddress(resp, 0, &addr, nullptr) == OT_ERROR_NONE)
+        {
+            thread_time_sync->sync_ip_internal(&addr);
+        }
+        else
+        {
+            thread_time_sync->m_in_progress.store(false);
+            LOG_WRN("[%s] otDnsClientResolveIp4Address response no address", m_unit_name);
+        }
+    }
+    else
+    {
+        thread_time_sync->m_in_progress.store(false);
+        LOG_WRN("[%s] otDnsClientResolveIp4Address response failed %u", m_unit_name, error);
+    }
+}
+
+void ThreadTimeSync::on_ntp_time_response_wrap(void * ctx, uint64_t time, otError error)
+{
+    ThreadTimeSync * thread_time_sync = static_cast<ThreadTimeSync *>(ctx);
+
+    if (error == OT_ERROR_NONE)
+    {
+        chip::System::Clock::Microseconds64 chip_time = chip::System::Clock::Seconds64(time);
+
+        if (chip::System::SystemClock().SetClock_RealTime(chip_time) != CHIP_NO_ERROR)
+        {
+            LOG_ERR("[%s] SetClock_RealTime failed", m_unit_name);
+        }
+        thread_time_sync->m_already_sync.store(true);
+        thread_time_sync->m_in_progress.store(false);
+        LOG_INF("[%s] SNTP time sync timestamp %llu", m_unit_name, time);
+
+        time_t ts = time;
+        struct tm info;
+        char tm_str[40];
+
+        localtime_r(&ts, &info);
+        strftime(tm_str, sizeof(tm_str), "%A %d %B %Y %H:%M:%S", &info);
+        LOG_INF("[%s] SNTP sync at %s", m_unit_name, tm_str);
+    }
+    else
+    {
+        thread_time_sync->m_in_progress.store(false);
+        LOG_WRN("[%s] otSntpClientQuery response failed %u", m_unit_name, error);
+    }
+}
diff --git a/examples/pump-app/telink/CMakeLists.txt b/examples/pump-app/telink/CMakeLists.txt
index 32d5a65..7f8900b 100755
--- a/examples/pump-app/telink/CMakeLists.txt
+++ b/examples/pump-app/telink/CMakeLists.txt
@@ -57,3 +57,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/pump-controller-app/telink/CMakeLists.txt b/examples/pump-controller-app/telink/CMakeLists.txt
index 136e14d..f5662e8 100755
--- a/examples/pump-controller-app/telink/CMakeLists.txt
+++ b/examples/pump-controller-app/telink/CMakeLists.txt
@@ -57,3 +57,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/smoke-co-alarm-app/telink/CMakeLists.txt b/examples/smoke-co-alarm-app/telink/CMakeLists.txt
index 6d11f0f..7622edb 100755
--- a/examples/smoke-co-alarm-app/telink/CMakeLists.txt
+++ b/examples/smoke-co-alarm-app/telink/CMakeLists.txt
@@ -58,3 +58,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/temperature-measurement-app/telink/CMakeLists.txt b/examples/temperature-measurement-app/telink/CMakeLists.txt
index 44e6655..0e1b90e 100644
--- a/examples/temperature-measurement-app/telink/CMakeLists.txt
+++ b/examples/temperature-measurement-app/telink/CMakeLists.txt
@@ -60,3 +60,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/thermostat/telink/CMakeLists.txt b/examples/thermostat/telink/CMakeLists.txt
index 114163f..262dbed 100755
--- a/examples/thermostat/telink/CMakeLists.txt
+++ b/examples/thermostat/telink/CMakeLists.txt
@@ -60,3 +60,8 @@
 if(CONFIG_BOOTLOADER_MCUBOOT)
   target_sources(app PRIVATE ${TELINK_COMMON}/util/src/OTAUtil.cpp)
 endif()
+
+if(CONFIG_OPENTHREAD_SNTP_CLIENT)
+  target_sources(app PRIVATE
+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)
+endif()
diff --git a/examples/window-app/telink/CMakeLists.txt b/examples/window-app/telink/CMakeLists.txt
index 8752594..ed8eb7d 100644
--- a/examples/window-app/telink/CMakeLists.txt
+++ b/examples/window-app/telink/CMakeLists.txt
@@ -67,3 +67,8 @@
 if (CONFIG_CHIP_PW_RPC)

   include(${TELINK_COMMON}/Rpc.cmake)

 endif(CONFIG_CHIP_PW_RPC)

+

+if(CONFIG_OPENTHREAD_SNTP_CLIENT)

+  target_sources(app PRIVATE

+                   ${TELINK_COMMON}/util/src/ThreadTimeSync.cpp)

+endif()