diff --git a/esphome/components/zigbee/zigbee_esp32.cpp b/esphome/components/zigbee/zigbee_esp32.cpp index 29bbdc2b0b5..35f12b3a4e3 100644 --- a/esphome/components/zigbee/zigbee_esp32.cpp +++ b/esphome/components/zigbee/zigbee_esp32.cpp @@ -388,15 +388,6 @@ void ZigbeeComponent::setup() { }; ezb_af_set_node_power_desc(&desc); - // Finish zigbee data model - for (auto &attr_value : this->attr_values_) { - ezb_zcl_attr_desc_t attr_desc = attr_value.attr_desc; - void *value_p = &attr_value.value; - ezb_zcl_attr_desc_set_value(attr_desc, value_p); - } - // free memory - std::vector().swap(this->attr_values_); - // Start the Zigbee task with priority 1 to ensure main loop can still run even if Zigbee is busy xTaskCreate(ezb_task, "Zigbee_main", 4096, NULL, 1, NULL); this->disable_loop(); // loop is only needed for processing events, so disable until we join a network @@ -470,23 +461,6 @@ void ZigbeeComponent::dump_config() { esp_zigbee_lock_release(); } } - -bool ZigbeeComponent::string_attr_exists_(uint8_t endpoint_id, uint16_t cluster_id, uint8_t role, uint16_t attr_id) { - ezb_af_ep_desc_t ep_desc = ezb_af_device_get_endpoint_desc(this->dev_desc_, endpoint_id); - if (ep_desc == NULL) { - return false; - } - ezb_zcl_cluster_desc_t cluster_desc = ezb_af_endpoint_get_cluster_desc(ep_desc, cluster_id, role); - if (cluster_desc == NULL) { - return false; - } - if (ezb_zcl_cluster_get_attr_desc(cluster_desc, attr_id, EZB_ZCL_STD_MANUF_CODE) == NULL) { - return false; - } - ESP_LOGW(TAG, "Attribute 0x%04X already exists in endpoint %u cluster 0x%04X. Can't add new value", attr_id, - endpoint_id, cluster_id); - return true; -} } // namespace esphome::zigbee #endif diff --git a/esphome/components/zigbee/zigbee_esp32.h b/esphome/components/zigbee/zigbee_esp32.h index d5ed7439bd2..93a4f1ba780 100644 --- a/esphome/components/zigbee/zigbee_esp32.h +++ b/esphome/components/zigbee/zigbee_esp32.h @@ -29,11 +29,6 @@ static constexpr uint8_t MAX_ZB_QUEUE_SIZE = 32; uint8_t *get_zcl_string(const char *str, uint8_t max_size, bool use_max_size = false); -struct AttrValue { - ezb_zcl_attr_desc_t attr_desc; - uint8_t value[4]; -}; - class ZigbeeAttribute; class ZigbeeComponent final : public Component { @@ -101,7 +96,6 @@ class ZigbeeComponent final : public Component { // automations // key tuple could be replaced by single 64 (48) bit int with bit fields for endpoint, cluster, role and attr_id std::map, ZigbeeAttribute *> attributes_; - std::vector attr_values_; ezb_af_device_desc_t dev_desc_ = ezb_af_create_device_desc(); CallbackManager join_cb_{}; template friend void enqueue_zb_event(Args... args); @@ -119,8 +113,6 @@ class ZigbeeComponent final : public Component { std::atomic joined_ = false; std::atomic join_pending_ = false; std::atomic factory_new_ = false; - // TODO: remove when esp-zigbee-lib fixes set_value before init - bool string_attr_exists_(uint8_t endpoint_id, uint16_t cluster_id, uint8_t role, uint16_t attr_id); }; template @@ -135,22 +127,10 @@ void ZigbeeComponent::add_attr(ZigbeeAttribute *attr, uint8_t endpoint_id, uint1 // The size byte of the zcl_str must be set to the maximum value, // even though the initial string may be shorter. if constexpr (std::is_same::value) { - if (this->string_attr_exists_(endpoint_id, cluster_id, role, attr_id)) { - if (attr != nullptr) { - this->attributes_[{endpoint_id, cluster_id, role, attr_id}] = attr; - } - return; - } auto zcl_str = get_zcl_string(value.c_str(), max_size, true); add_attr_(attr, endpoint_id, cluster_id, role, attr_id, zcl_str); delete[] zcl_str; } else if constexpr (std::is_convertible::value) { - if (this->string_attr_exists_(endpoint_id, cluster_id, role, attr_id)) { - if (attr != nullptr) { - this->attributes_[{endpoint_id, cluster_id, role, attr_id}] = attr; - } - return; - } auto zcl_str = get_zcl_string(value, max_size, true); add_attr_(attr, endpoint_id, cluster_id, role, attr_id, zcl_str); delete[] zcl_str; @@ -170,18 +150,7 @@ void ZigbeeComponent::add_attr_(ZigbeeAttribute *attr, uint8_t endpoint_id, uint if (cluster_desc == NULL) { return; } - // TODO: revert when esp-zigbee-lib fixes set_value before init - ezb_zcl_attr_desc_t attr_desc = ezb_zcl_cluster_get_attr_desc(cluster_desc, attr_id, EZB_ZCL_STD_MANUF_CODE); - - if (attr_desc != NULL) { - static_assert(sizeof(*value_p) <= 4); - AttrValue attr_value; - attr_value.attr_desc = attr_desc; - memcpy(&attr_value.value, value_p, sizeof(*value_p)); - attr_values_.push_back(attr_value); - } else { - esphome_zb_cluster_add_attr(cluster_id, cluster_desc, attr_id, value_p); - } + esphome_zb_cluster_add_or_update_attr(cluster_id, cluster_desc, attr_id, value_p); if (attr != nullptr) { this->attributes_[{endpoint_id, cluster_id, role, attr_id}] = attr; diff --git a/esphome/components/zigbee/zigbee_esp32.py b/esphome/components/zigbee/zigbee_esp32.py index 99f075ecb2f..30c94cde6cb 100644 --- a/esphome/components/zigbee/zigbee_esp32.py +++ b/esphome/components/zigbee/zigbee_esp32.py @@ -13,7 +13,6 @@ from esphome.components.esp32 import ( add_idf_sdkconfig_option, add_partition, include_builtin_idf_component, - require_mbedtls_ecp, require_mbedtls_tls_extras, require_vfs_select, ) @@ -395,17 +394,12 @@ async def attributes_to_code( async def esp32_to_code(config: ConfigType) -> "MockObj": add_idf_component( name="espressif/esp-zigbee-lib", - ref="2.0.4", + ref="2.0.5", ) - # The esp-zigbee-lib blobs reference mbedtls_ecp_* (Zigbee Direct, install - # code ECDH); keep ECP without relying on esp_wifi's Kconfig select. - require_mbedtls_ecp() - # Zigbee's crypto platform uses AES-CCM and deterministic ECDSA directly. + # Zigbee's crypto platform uses AES-CCM directly. # Keep the esp32 component from trimming them out of mbedTLS. - require_mbedtls_tls_extras( - ("CONFIG_MBEDTLS_CCM_C", "CONFIG_MBEDTLS_ECDSA_DETERMINISTIC") - ) + require_mbedtls_tls_extras({"CONFIG_MBEDTLS_CCM_C"}) if CONF_WIFI in CORE.config: # zigbee_esp32.cpp uses esp_coexist.h when WiFi is present diff --git a/esphome/idf_component.yml b/esphome/idf_component.yml index 5ed84fa2a3a..dd837d61632 100644 --- a/esphome/idf_component.yml +++ b/esphome/idf_component.yml @@ -54,7 +54,7 @@ dependencies: rules: - if: "target in [esp32, esp32p4]" espressif/esp-zigbee-lib: - version: 2.0.4 + version: 2.0.5 rules: - if: "target in [esp32h2, esp32c5, esp32c6]" espressif/lan87xx: diff --git a/tests/component_tests/esp32/test_esp32.py b/tests/component_tests/esp32/test_esp32.py index 3cde877f7ad..86b27776dc6 100644 --- a/tests/component_tests/esp32/test_esp32.py +++ b/tests/component_tests/esp32/test_esp32.py @@ -1016,8 +1016,8 @@ def _tls_compiled_out(sdkconfig: dict[str, Any]) -> bool: "exclusion_reincludes_nextion.yaml", False, False, False, id="nextion" ), pytest.param("mbedtls_tls_wifi_eap.yaml", False, False, True, id="wifi_eap"), - # zigbee requests ECP for the esp-zigbee-lib blobs, without TLS. - pytest.param("tls_zigbee_c6.yaml", True, False, True, id="zigbee"), + # zigbee needs neither TLS nor ECP + pytest.param("tls_zigbee_c6.yaml", True, True, True, id="zigbee"), # A raw bundle keeps the TLS role but no longer compiles esp-tls. pytest.param( "certificate_bundle_sdkconfig.yaml", False, False, True, id="raw_bundle" @@ -2188,19 +2188,21 @@ def test_mbedtls_tls_openthread_keeps_only_what_it_uses( assert sdkconfig.get(name) is (None if name in _CCM_ECDSA_EXTRAS else False) +_CCM_EXTRAS = {"CONFIG_MBEDTLS_CCM_C"} + + def test_mbedtls_tls_zigbee_keeps_only_what_it_uses( generate_main: Callable[[str | Path], str], component_config_path: Callable[[str], Path], ) -> None: """Nothing in the Zigbee config links TLS, so the stack is compiled out and - no role is written; the extras trim still runs and Zigbee keeps CCM and - deterministic ECDSA.""" + no role is written; the extras trim still runs and Zigbee keeps CCM.""" generate_main(component_config_path("tls_zigbee_c6.yaml")) sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS] assert _tls_compiled_out(sdkconfig) assert tuple(sdkconfig.get(name) for name in _TLS_SERVER_OPTIONS) == (None, None) for name in MBEDTLS_TLS_EXTRA_OPTIONS: - assert sdkconfig.get(name) is (None if name in _CCM_ECDSA_EXTRAS else False) + assert sdkconfig.get(name) is (None if name in _CCM_EXTRAS else False) def test_mbedtls_tls_opt_out_keeps_stack_and_trims_role( @@ -2252,10 +2254,10 @@ def test_mbedtls_tls_zigbee_requires_extras( generate_main: Callable[[str | Path], str], component_config_path: Callable[[str], Path], ) -> None: - """The Zigbee hooks mark the CCM/deterministic ECDSA as required.""" + """The Zigbee hooks mark the CCM as required.""" generate_main(component_config_path("tls_zigbee_c6.yaml")) mbedtls = CORE.data[KEY_ESP32][KEY_MBEDTLS_SDKCONFIG] - assert mbedtls.tls_extras_required == _CCM_ECDSA_EXTRAS + assert mbedtls.tls_extras_required == _CCM_EXTRAS _VASPRINTF_STUB_FLAGS = {"-Wl,--wrap=vasprintf", "-Wl,--undefined=__wrap_vasprintf"}