ESPHome 2026.10.2
Loading...
Searching...
No Matches
zigbee_time_zephyr.cpp
Go to the documentation of this file.
2#if defined(USE_ZIGBEE) && defined(USE_NRF52) && defined(USE_TIME)
3#include "esphome/core/log.h"
5#include <limits>
6
7namespace esphome::zigbee {
8
9static const char *const TAG = "zigbee.time";
10
11// This time standard is the number of
12// seconds since 0 hrs 0 mins 0 sec on 1st January 2000 UTC (Universal Coordinated Time).
13constexpr time_t EPOCH_2000 = 946684800;
14// Largest ZCL time that still fits the 32-bit epoch. Also rejects ZB_ZCL_TIME_TIME_INVALID_VALUE.
15constexpr uint32_t MAX_ZCL_TIME = std::numeric_limits<uint32_t>::max() - EPOCH_2000;
16
17ZigbeeTime *global_time = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
18
19void ZigbeeTime::sync_time(zb_ret_t status, zb_uint32_t auth_level, zb_uint16_t short_addr, zb_uint8_t endpoint,
20 zb_uint32_t nw_time) {
21 if (status == RET_OK && auth_level >= ZB_ZCL_TIME_HAS_SYNCHRONIZED_BIT && nw_time <= MAX_ZCL_TIME) {
22 global_time->set_epoch_time(nw_time + EPOCH_2000);
23 } else if (status != RET_TIMEOUT || !global_time->has_time_) {
24 ESP_LOGE(TAG, "Status: %d, auth_level: %u, short_addr: %d, endpoint: %d, nw_time: %u", status, auth_level,
25 short_addr, endpoint, nw_time);
26 }
27}
28
29void ZigbeeTime::setup() {
30 global_time = this;
31 this->parent_->add_callback(this->endpoint_, [this](zb_bufid_t bufid) { this->zcl_device_cb_(bufid); });
32 this->parent_->add_on_join_callback([this](bool x) { zb_zcl_time_server_synchronize(this->endpoint_, sync_time); });
33}
34
36 ESP_LOGCONFIG(TAG,
37 "Zigbee Time\n"
38 " Endpoint: %d",
39 this->endpoint_);
40 RealTimeClock::dump_config();
41}
42
43void ZigbeeTime::update() {
44 const time_t now = this->timestamp_now();
45 if (now < EPOCH_2000) {
46 this->cluster_attributes_->time = ZB_ZCL_TIME_TIME_INVALID_VALUE;
47 } else {
48 this->cluster_attributes_->time = static_cast<uint32_t>(now - EPOCH_2000);
49 }
50}
51
53 this->defer([this, epoch]() {
54 this->synchronize_epoch_(epoch);
55 this->has_time_ = true;
56 });
58}
59
60void ZigbeeTime::zcl_device_cb_(zb_bufid_t bufid) {
61 zb_zcl_device_callback_param_t *p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
62 zb_zcl_device_callback_id_t device_cb_id = p_device_cb_param->device_cb_id;
63 zb_uint16_t cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
64 zb_uint16_t attr_id = p_device_cb_param->cb_param.set_attr_value_param.attr_id;
65
66 switch (device_cb_id) {
67 /* ZCL set attribute value */
68 case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
69 if (cluster_id == ZB_ZCL_CLUSTER_ID_TIME) {
70 if (attr_id == ZB_ZCL_ATTR_TIME_TIME_ID) {
71 zb_uint32_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data32;
72 if (value <= MAX_ZCL_TIME) {
73 ESP_LOGI(TAG, "Synchronize time to %u", value);
74 this->defer([this, value]() { this->synchronize_epoch_(value + EPOCH_2000); });
75 } else {
76 ESP_LOGW(TAG, "Ignoring invalid time %u", value);
77 }
78 } else if (attr_id == ZB_ZCL_ATTR_TIME_TIME_STATUS_ID) {
79 zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
80 ESP_LOGI(TAG, "Time status %hd", value);
81 this->defer([this, value]() { this->has_time_ = ZB_ZCL_TIME_TIME_STATUS_SYNCHRONIZED_BIT_IS_SET(value); });
82 }
83 } else {
84 /* other clusters attribute handled here */
85 ESP_LOGI(TAG, "Unhandled cluster attribute id: %d", cluster_id);
86 p_device_cb_param->status = RET_NOT_IMPLEMENTED;
87 }
88 break;
89 default:
90 p_device_cb_param->status = RET_NOT_IMPLEMENTED;
91 break;
92 }
93
94 ESP_LOGD(TAG, "Zcl_device_cb_ status: %hd", p_device_cb_param->status);
95}
96
97} // namespace esphome::zigbee
98
99#endif
uint8_t status
Definition bl0942.h:8
void wake_loop_threadsafe()
Wake the main event loop from another thread or callback.
void defer(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call with a const char* name.
ESPTime now()
Get the time in the currently defined timezone.
virtual time_t timestamp_now()
Get the current time as the UTC epoch since January 1st 1970.
void synchronize_epoch_(uint32_t epoch)
Report a unix epoch as current time.
void add_callback(zb_uint8_t endpoint, std::function< void(zb_bufid_t bufid)> &&cb)
static void sync_time(zb_ret_t status, zb_uint32_t auth_level, zb_uint16_t short_addr, zb_uint8_t endpoint, zb_uint32_t nw_time)
void zcl_device_cb_(zb_bufid_t bufid)
zb_zcl_time_attrs_t * cluster_attributes_
const char *const TAG
Definition spi.cpp:7
constexpr time_t EPOCH_2000
constexpr uint32_t MAX_ZCL_TIME
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t
uint16_t x
Definition tt21100.cpp:5