5#include "freertos/FreeRTOS.h"
6#include "freertos/task.h"
14#include "esp_coexist.h"
21static constexpr uint32_t COMMISSIONING_RETRY_TIMEOUT_ID = 0;
25uint8_t *
get_zcl_string(
const char *str, uint8_t max_size,
bool use_max_size) {
26 uint8_t str_len =
static_cast<uint8_t
>(strlen(str));
27 uint8_t zcl_str_size = use_max_size ? max_size : std::min(max_size, str_len);
28 uint8_t *zcl_str =
new uint8_t[zcl_str_size + 1];
29 zcl_str[0] = zcl_str_size;
32 memset(zcl_str + 1, 0, zcl_str_size);
33 uint8_t copy_len = std::min(zcl_str_size, str_len);
35 memcpy(zcl_str + 1, str, copy_len);
41 esp_zigbee_lock_acquire(portMAX_DELAY);
44 ezb_bdb_reset_via_local_action();
46 esp_zigbee_factory_reset();
48 esp_zigbee_lock_release();
52 for (
const auto &[_, attribute] : this->
attributes_) {
58 if (!esp_zigbee_lock_acquire(10 / portTICK_PERIOD_MS)) {
59 global_zigbee->
set_timeout(COMMISSIONING_RETRY_TIMEOUT_ID, 100,
63 if (ezb_bdb_start_top_level_commissioning(
mode) != EZB_ERR_NONE) {
64 ESP_LOGE(TAG,
"Start top level commissioning failed!");
66 esp_zigbee_lock_release();
70 static uint8_t steering_retry_count = 0;
71 ezb_app_signal_type_t signal_type = ezb_app_signal_get_type(app_signal);
72 switch (signal_type) {
73 case EZB_ZDO_SIGNAL_SKIP_STARTUP:
74 ESP_LOGD(TAG,
"Zigbee stack initialized");
77 ezb_bdb_start_top_level_commissioning(EZB_BDB_MODE_INITIALIZATION);
79 case EZB_BDB_SIGNAL_DEVICE_FIRST_START:
80 case EZB_BDB_SIGNAL_DEVICE_REBOOT: {
81 ezb_bdb_comm_status_t
status = *((ezb_bdb_comm_status_t *) ezb_app_signal_get_params(app_signal));
82 if (
status == EZB_BDB_STATUS_SUCCESS) {
83 ESP_LOGD(TAG,
"Device started up in %sfactory-reset mode", ezb_bdb_is_factory_new() ?
"" :
"non ");
84 if (ezb_bdb_is_factory_new()) {
86 ESP_LOGD(TAG,
"Start network steering");
87 ezb_bdb_start_top_level_commissioning(EZB_BDB_MODE_NETWORK_STEERING);
89 ESP_LOGD(TAG,
"Device rebooted");
95 ESP_LOGW(TAG,
"The %s failed with status(0x%02x), please retry", ezb_app_signal_to_string(signal_type),
status);
96 global_zigbee->
set_timeout(COMMISSIONING_RETRY_TIMEOUT_ID, 1000, []() {
101 case EZB_BDB_SIGNAL_STEERING: {
102 ezb_bdb_comm_status_t
status = *((ezb_bdb_comm_status_t *) ezb_app_signal_get_params(app_signal));
103 if (
status == EZB_BDB_STATUS_SUCCESS) {
104 steering_retry_count = 0;
105 ezb_extpanid_t extended_pan_id;
106 ezb_nwk_get_extended_panid(&extended_pan_id);
107 ESP_LOGD(TAG,
"Joined network successfully: PAN ID(0x%04hx, EXT: 0x%llx), Channel(%d), Short Address(0x%04hx)",
108 ezb_nwk_get_panid(), extended_pan_id.u64, ezb_nwk_get_current_channel(), ezb_nwk_get_short_address());
113 ESP_LOGD(TAG,
"Failed to join network with status(0x%02x)",
status);
114 if (steering_retry_count < 10) {
115 steering_retry_count++;
116 global_zigbee->
set_timeout(COMMISSIONING_RETRY_TIMEOUT_ID, 1000, []() {
120 global_zigbee->
set_timeout(COMMISSIONING_RETRY_TIMEOUT_ID, 600 * 1000, []() {
126 case EZB_ZDO_SIGNAL_LEAVE: {
127 const ezb_zdo_signal_leave_params_t *leave_params =
128 (
const ezb_zdo_signal_leave_params_t *) ezb_app_signal_get_params(app_signal);
129 if (leave_params->leave_type == EZB_ZDO_LEAVE_TYPE_RESET) {
130 esp_zigbee_factory_reset();
132 global_zigbee->
joined_ =
false;
134 case EZB_NWK_SIGNAL_NETWORK_STATUS: {
135 const ezb_nwk_signal_network_status_params_t *network_status_params =
136 (
const ezb_nwk_signal_network_status_params_t *) ezb_app_signal_get_params(app_signal);
137 if (network_status_params->status == EZB_NWK_NETWORK_STATUS_PARENT_LINK_FAILURE) {
138 global_zigbee->
joined_ =
false;
139 ESP_LOGW(TAG,
"Parent link failure, attempting rejoin");
140 ezb_zdo_nwk_mgmt_leave_req_t leave_req = {
141 .dst_nwk_addr = ezb_nwk_get_short_address(),
144 .remove_children =
false,
150 ezb_zdo_nwk_mgmt_leave_req(&leave_req);
152 ESP_LOGD(TAG,
"Zigbee APP Signal NETWORK_STATUS: 0x%02x", network_status_params->status);
156 ESP_LOGD(TAG,
"Zigbee APP Signal: %s(type: 0x%02x)", ezb_app_signal_to_string(signal_type), signal_type);
163 event->load_set_attr_value_event(info, attribute);
169 if (event ==
nullptr) {
171 global_zigbee->
zb_events_.increment_dropped_count();
187static void zb_attribute_handler(ezb_zcl_set_attr_value_message_t *
message) {
188 ESP_RETURN_ON_FALSE(
message, , TAG,
"Empty message");
189 ESP_RETURN_ON_FALSE(
message->info.status == EZB_ZCL_STATUS_SUCCESS, , TAG,
"Received message: error status(%d)",
191 ESP_LOGD(TAG,
"ZCL SetAttributeValue message for endpoint(%d) cluster(0x%04x) %s with status(0x%02x)",
193 message->info.cluster_role == EZB_ZCL_CLUSTER_SERVER ?
"server" :
"client",
message->info.status);
197static void zb_action_handler(ezb_zcl_core_action_callback_id_t callback_id,
void *
message) {
198 switch (callback_id) {
199 case EZB_ZCL_CORE_SET_ATTR_VALUE_CB_ID:
200 zb_attribute_handler((ezb_zcl_set_attr_value_message_t *)
message);
202 case EZB_ZCL_CORE_DEFAULT_RSP_CB_ID: {
203#ifdef ESPHOME_LOG_HAS_VERBOSE
204 ezb_zcl_cmd_default_rsp_message_t *default_rsp = (ezb_zcl_cmd_default_rsp_message_t *)
message;
205 ESP_LOGV(TAG,
"Received ZCL Default Response: 0x%02x", default_rsp->in.status_code);
209 ESP_LOGD(TAG,
"Receive Zigbee action(0x%04x) callback",
static_cast<unsigned>(callback_id));
215 auto it = this->
attributes_.find({info.dst_ep, info.cluster_id, info.cluster_role, attribute.id});
217 it->second->on_value(attribute);
222 ezb_af_ep_desc_t ep_desc =
224 if (ezb_af_device_add_endpoint_desc(this->
dev_desc_, ep_desc) != EZB_ERR_NONE) {
225 ESP_LOGE(TAG,
"Could not create endpoint %u", endpoint_id);
230 this->
add_cluster(endpoint_id, EZB_ZCL_CLUSTER_ID_IDENTIFY, EZB_ZCL_CLUSTER_SERVER);
234 if (cluster_id == EZB_ZCL_CLUSTER_ID_BASIC) {
237 ezb_af_ep_desc_t ep_desc = ezb_af_device_get_endpoint_desc(this->
dev_desc_, endpoint_id);
238 if (ep_desc == NULL) {
239 ESP_LOGE(TAG,
"Endpoint %u does not exist, cannot add cluster 0x%04X", endpoint_id, cluster_id);
243 ESP_LOGD(TAG,
"Endpoint %u: Added cluster 0x%04X with role %u", endpoint_id, cluster_id, role);
247 const char *sw_build_id, uint8_t power_source, uint8_t app_version) {
250 struct tm *timeinfo =
localtime(&time_val);
251 strftime(date_buf,
sizeof(date_buf),
"%Y%m%d %H%M%S", timeinfo);
264 ezb_zcl_cluster_desc_t cluster_desc =
265 ezb_af_endpoint_get_cluster_desc(ep_desc, EZB_ZCL_CLUSTER_ID_BASIC, EZB_ZCL_CLUSTER_SERVER);
266 if (cluster_desc == NULL) {
267 ezb_zcl_basic_cluster_config_t basic_cluster_cfg = {
268 .zcl_version = EZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE,
271 cluster_desc = ezb_zcl_basic_create_cluster_desc(&basic_cluster_cfg, EZB_ZCL_CLUSTER_SERVER);
272 ezb_af_endpoint_add_cluster_desc(ep_desc, cluster_desc);
274 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID,
276 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID,
278 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_DATE_CODE_ID, this->
basic_cluster_data_.date);
279 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID,
281 uint8_t stack_version = 0;
282 uint8_t hw_version = 0;
283 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, &stack_version);
284 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_HW_VERSION_ID, &hw_version);
285 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_LOCATION_DESCRIPTION_ID,
287 ezb_zcl_basic_cluster_desc_add_attr(cluster_desc, EZB_ZCL_ATTR_BASIC_SW_BUILD_ID_ID,
292 if (ezb_af_device_desc_register(this->
dev_desc_) != EZB_ERR_NONE) {
293 ESP_LOGE(TAG,
"Could not register the endpoint list");
300static void ezb_task(
void *pv_parameters) {
305 if (esp_zigbee_start(
false) != ESP_OK) {
306 ESP_LOGE(TAG,
"Could not setup Zigbee");
313 vTaskPrioritySet(NULL, 5);
315 esp_zigbee_launch_mainloop();
323 global_zigbee =
this;
325 esp_zigbee_platform_config_t platform_config = {
326 .storage_partition_name =
"nvs",
327 .radio_config = EZB_DEFAULT_RADIO_CONFIG(),
329 esp_zigbee_device_config_t device_config = {
331 .install_code_policy =
false,
334 esp_zigbee_zczr_config_s zb_zczr_cfg = {
335 .max_children = MAX_CHILDREN,
337 device_config.zczr_config = zb_zczr_cfg;
339 esp_zigbee_zed_config_s zb_zed_cfg = {
340 .ed_timeout = EZB_NWK_ED_TIMEOUT_64MIN,
343 device_config.zed_config = zb_zed_cfg;
345 esp_zigbee_config_t config = {.device_config = device_config, .platform_config = platform_config};
346 if (esp_zigbee_init(&config) != ESP_OK) {
347 ESP_LOGE(TAG,
"Could not initialize Zigbee");
353 if (esp_coex_wifi_i154_enable() != ESP_OK) {
360 ezb_bdb_set_router_rejoin_required(
true);
362 ezb_nwk_set_rx_on_when_idle(!this->
sleepy_);
365 ezb_aps_secur_enable_distributed_security(
false);
366 ezb_nwk_set_min_join_lqi(32);
368 ESP_LOGE(TAG,
"Could not set application signal handler");
373 ezb_zcl_core_action_handler_register(zb_action_handler);
375 if (ezb_bdb_set_primary_channel_set(EZB_PRIMARY_CHANNEL_MASK) != ESP_OK) {
376 ESP_LOGE(TAG,
"Could not setup Zigbee");
382 : EZB_AF_NODE_POWER_SOURCE_CONSTANT_POWER);
383 ezb_af_node_power_desc_t desc = {
384 .current_power_mode = EZB_AF_NODE_POWER_MODE_SYNC_ON_WHEN_IDLE,
387 .current_power_source_level = EZB_AF_NODE_POWER_SOURCE_LEVEL_100_PERCENT,
389 ezb_af_set_node_power_desc(&desc);
393 ezb_zcl_attr_desc_t attr_desc = attr_value.attr_desc;
394 void *value_p = &attr_value.value;
395 ezb_zcl_attr_desc_set_value(attr_desc, value_p);
398 std::vector<AttrValue>().swap(this->attr_values_);
401 xTaskCreate(ezb_task,
"Zigbee_main", 4096, NULL, 1, NULL);
408 while (event !=
nullptr) {
411 case EZB_ZCL_CORE_SET_ATTR_VALUE_CB_ID:
415 ESP_LOGW(TAG,
"Received event with unhandled callback id: 0x%x",
static_cast<unsigned>(event->
callback_id_));
425 uint16_t dropped = this->
zb_events_.get_and_reset_dropped_count();
427 ESP_LOGW(TAG,
"Dropped %u Zigbee events due to buffer overflow", dropped);
445 " Manufacturer: %.*s\n"
449 " Sleepy end device: %s\n"
450 " Poll interval: %" PRIu32
" ms\n"
453 this->
basic_cluster_data_.model[0],
reinterpret_cast<const char *
>(this->basic_cluster_data_.model + 1),
454 this->basic_cluster_data_.manufacturer[0],
455 reinterpret_cast<const char *
>(this->basic_cluster_data_.manufacturer + 1),
457 YESNO(this->
device_role_ == EZB_NWK_DEVICE_TYPE_ROUTER),
462 if (esp_zigbee_lock_acquire(10 / portTICK_PERIOD_MS)) {
464 " Device is joined to the network: %s\n"
465 " Current channel: %d\n"
466 " Short addr: 0x%04X\n"
467 " Short pan id: 0x%04X",
468 YESNO(ezb_bdb_dev_joined()), ezb_nwk_get_current_channel(), ezb_nwk_get_short_address(),
469 ezb_nwk_get_panid());
470 esp_zigbee_lock_release();
475 ezb_af_ep_desc_t ep_desc = ezb_af_device_get_endpoint_desc(this->
dev_desc_, endpoint_id);
476 if (ep_desc == NULL) {
479 ezb_zcl_cluster_desc_t cluster_desc = ezb_af_endpoint_get_cluster_desc(ep_desc, cluster_id, role);
480 if (cluster_desc == NULL) {
483 if (ezb_zcl_cluster_get_attr_desc(cluster_desc, attr_id, EZB_ZCL_STD_MANUF_CODE) == NULL) {
486 ESP_LOGW(TAG,
"Attribute 0x%04X already exists in endpoint %u cluster 0x%04X. Can't add new value", attr_id,
487 endpoint_id, cluster_id);
BedjetMode mode
BedJet operating mode.
time_t get_build_time()
Get the build time as a Unix timestamp.
void mark_failed()
Mark this component as failed.
void enable_loop_soon_any_context()
Thread and ISR-safe version of enable_loop() that can be called from any context.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
void disable_loop()
Disable this component's loop.
ezb_zcl_core_action_callback_id_t callback_id_
struct esphome::zigbee::ZBEvent::@207::set_attr_event set_attr
union esphome::zigbee::ZBEvent::@207 event_
std::vector< AttrValue > attr_values_
CallbackManager< void(bool)> join_cb_
struct esphome::zigbee::ZigbeeComponent::@206 basic_cluster_data_
bool string_attr_exists_(uint8_t endpoint_id, uint16_t cluster_id, uint8_t role, uint16_t attr_id)
bool is_battery_powered()
void create_default_cluster(uint8_t endpoint_id, uint16_t device_id)
std::atomic< bool > factory_new_
void handle_attribute_(ezb_zcl_message_info_t info, ezb_zcl_attribute_t attribute)
esphome::LockFreeQueue< ZBEvent, MAX_ZB_QUEUE_SIZE > zb_events_
std::map< std::tuple< uint8_t, uint16_t, uint8_t, uint16_t >, ZigbeeAttribute * > attributes_
void update_basic_cluster_(ezb_af_ep_desc_t ep_desc)
void add_cluster(uint8_t endpoint_id, uint16_t cluster_id, uint8_t role)
static void esp_zigbee_alarm_bdb_commissioning(ezb_bdb_comm_mode_mask_t mode)
LazyCallbackManager< void()> start_cb_
static bool app_signal_handler(const ezb_app_signal_t *app_signal)
std::atomic< bool > joined_
std::atomic< bool > started_
std::atomic< bool > join_pending_
ezb_nwk_device_type_t device_role_
void set_basic_cluster(const char *model, const char *manufacturer, const char *location, const char *sw_build_id, uint8_t power_source, uint8_t app_version)
void dump_config() override
esphome::EventPool< ZBEvent, MAX_ZB_QUEUE_SIZE - 1 > zb_event_pool_
ezb_af_device_desc_t dev_desc_
const LogString * message
void load_zb_event(ZBEvent *event, ezb_zcl_message_info_t info, ezb_zcl_attribute_t attribute)
uint8_t * get_zcl_string(const char *str, uint8_t max_size, bool use_max_size)
ESPHOME_LOG_TAG(TAG, "zigbee.time")
void enqueue_zb_event(Args... args)
Application App
Global storage of Application pointer - only one Application can exist.
struct tm * localtime(const time_t *timer)
ezb_err_t esphome_zb_add_or_update_cluster(uint16_t cluster_id, ezb_af_ep_desc_t ep_desc, uint8_t role_mask)
ezb_af_ep_desc_t esphome_zb_zha_default_ep_desc_create(uint8_t ep_id, uint16_t device_id, uint8_t power_source)