@@ -238,4 +238,129 @@ void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) {
238238 }
239239}
240240
241+ void ZigbeeEP::addTimeCluster (tm time, int32_t gmt_offset) {
242+ time_t utc_time = 0 ;
243+
244+ // Check if time is set
245+ if (time.tm_year > 0 ) {
246+ // Convert time to UTC
247+ utc_time = mktime (&time);
248+ }
249+
250+ // Create time cluster server attributes
251+ esp_zb_attribute_list_t *time_cluster_server = esp_zb_zcl_attr_list_create (ESP_ZB_ZCL_CLUSTER_ID_TIME);
252+ esp_zb_time_cluster_add_attr (time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, (void *)&gmt_offset);
253+ esp_zb_time_cluster_add_attr (time_cluster_server, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, (void *)&utc_time);
254+ // Create time cluster client attributes
255+ esp_zb_attribute_list_t *time_cluster_client = esp_zb_zcl_attr_list_create (ESP_ZB_ZCL_CLUSTER_ID_TIME);
256+ // Add time clusters to cluster list
257+ esp_zb_cluster_list_add_time_cluster (_cluster_list, time_cluster_server, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
258+ esp_zb_cluster_list_add_time_cluster (_cluster_list, time_cluster_client, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
259+ }
260+
261+ void ZigbeeEP::setTime (tm time) {
262+ time_t utc_time = mktime (&time);
263+ esp_zb_lock_acquire (portMAX_DELAY);
264+ esp_zb_zcl_set_attribute_val (_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, &utc_time, false );
265+ esp_zb_lock_release ();
266+ }
267+
268+ void ZigbeeEP::setTimezone (int32_t gmt_offset) {
269+ esp_zb_lock_acquire (portMAX_DELAY);
270+ esp_zb_zcl_set_attribute_val (_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, &gmt_offset, false );
271+ esp_zb_lock_release ();
272+ }
273+
274+ tm ZigbeeEP::getTime (uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
275+ /* Read peer time */
276+ esp_zb_zcl_read_attr_cmd_t read_req;
277+
278+ if (short_addr >= 0 ) {
279+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
280+ read_req.zcl_basic_cmd .dst_addr_u .addr_short = (uint16_t )short_addr;
281+ } else {
282+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
283+ memcpy (read_req.zcl_basic_cmd .dst_addr_u .addr_long , ieee_addr, sizeof (esp_zb_ieee_addr_t ));
284+ }
285+
286+ uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_TIME_ID};
287+ read_req.attr_number = ZB_ARRAY_LENTH (attributes);
288+ read_req.attr_field = attributes;
289+
290+ read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME;
291+
292+ read_req.zcl_basic_cmd .dst_endpoint = endpoint;
293+ read_req.zcl_basic_cmd .src_endpoint = _endpoint;
294+
295+ // clear read time
296+ _read_time = 0 ;
297+
298+ log_v (" Reading time from endpoint %d" , endpoint);
299+ esp_zb_zcl_read_attr_cmd_req (&read_req);
300+
301+ // Wait for response or timeout
302+ if (xSemaphoreTake (lock, ZB_CMD_TIMEOUT) != pdTRUE) {
303+ log_e (" Error while reading time" );
304+ return tm ();
305+ }
306+
307+ struct tm *timeinfo = localtime (&_read_time);
308+ if (timeinfo) {
309+ return *timeinfo;
310+ } else {
311+ log_e (" Error while converting time" );
312+ return tm ();
313+ }
314+ }
315+
316+ int32_t ZigbeeEP::getTimezone (uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
317+ /* Read peer timezone */
318+ esp_zb_zcl_read_attr_cmd_t read_req;
319+
320+ if (short_addr >= 0 ) {
321+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
322+ read_req.zcl_basic_cmd .dst_addr_u .addr_short = (uint16_t )short_addr;
323+ } else {
324+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
325+ memcpy (read_req.zcl_basic_cmd .dst_addr_u .addr_long , ieee_addr, sizeof (esp_zb_ieee_addr_t ));
326+ }
327+
328+ uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID};
329+ read_req.attr_number = ZB_ARRAY_LENTH (attributes);
330+ read_req.attr_field = attributes;
331+
332+ read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME;
333+
334+ read_req.zcl_basic_cmd .dst_endpoint = endpoint;
335+ read_req.zcl_basic_cmd .src_endpoint = _endpoint;
336+
337+ // clear read timezone
338+ _read_timezone = 0 ;
339+
340+ log_v (" Reading timezone from endpoint %d" , endpoint);
341+ esp_zb_zcl_read_attr_cmd_req (&read_req);
342+
343+ // Wait for response or timeout
344+ if (xSemaphoreTake (lock, ZB_CMD_TIMEOUT) != pdTRUE) {
345+ log_e (" Error while reading timezone" );
346+ }
347+
348+ return _read_timezone;
349+ }
350+
351+ void ZigbeeEP::zbReadTimeCluster (const esp_zb_zcl_attribute_t *attribute) {
352+ /* Time cluster attributes */
353+ if (attribute->id == ESP_ZB_ZCL_ATTR_TIME_TIME_ID && attribute->data .type == ESP_ZB_ZCL_ATTR_TYPE_UTC_TIME) {
354+ log_v (" Time attribute received" );
355+ log_v (" Time: %lld" , *(uint32_t *)attribute->data .value );
356+ _read_time = *(uint32_t *)attribute->data .value ;
357+ xSemaphoreGive (lock);
358+ } else if (attribute->id == ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID && attribute->data .type == ESP_ZB_ZCL_ATTR_TYPE_S32) {
359+ log_v (" Timezone attribute received" );
360+ log_v (" Timezone: %d" , *(int32_t *)attribute->data .value );
361+ _read_timezone = *(int32_t *)attribute->data .value ;
362+ xSemaphoreGive (lock);
363+ }
364+ }
365+
241366#endif // SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
0 commit comments