From 4c47051da984ebcbe0eb0e2a1f862cb49fae6b6f Mon Sep 17 00:00:00 2001 From: luar123 <49960470+luar123@users.noreply.github.com> Date: Fri, 7 Aug 2026 01:45:44 +0200 Subject: [PATCH] [zigbee] Add on_start automation (3/3) (#18009) Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> --- esphome/components/zigbee/__init__.py | 4 +++- esphome/components/zigbee/zigbee_esp32.cpp | 5 +++++ esphome/components/zigbee/zigbee_esp32.h | 3 +++ esphome/components/zigbee/zigbee_zephyr.cpp | 10 ++++++++++ esphome/components/zigbee/zigbee_zephyr.h | 3 +++ tests/components/zigbee/common_esp32.yaml | 3 +++ tests/components/zigbee/common_nrf52.yaml | 3 +++ 7 files changed, 30 insertions(+), 1 deletion(-) diff --git a/esphome/components/zigbee/__init__.py b/esphome/components/zigbee/__init__.py index 775fb35140..47913b34d7 100644 --- a/esphome/components/zigbee/__init__.py +++ b/esphome/components/zigbee/__init__.py @@ -13,7 +13,7 @@ from esphome.components.esp32.const import ( VARIANT_ESP32S31, ) import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_INTERNAL, CONF_MODEL, CONF_NAME +from esphome.const import CONF_ID, CONF_INTERNAL, CONF_MODEL, CONF_NAME, CONF_ON_START from esphome.core import CORE, CoroPriority, coroutine_with_priority from esphome.types import ConfigType @@ -108,6 +108,7 @@ CONFIG_SCHEMA = cv.All( ), cv.Optional(CONF_ROUTER, default=False): cv.boolean, cv.Optional(CONF_ON_JOIN): automation.validate_automation({}), + cv.Optional(CONF_ON_START): automation.validate_automation({}), cv.OnlyWith(CONF_WIPE_ON_BOOT, "nrf52", default=False): cv.All( cv.Any( cv.boolean, @@ -175,6 +176,7 @@ FINAL_VALIDATE_SCHEMA = cv.All( _CALLBACK_AUTOMATIONS = [ automation.CallbackAutomation(CONF_ON_JOIN, "add_on_join_callback", [(bool, "x")]), + automation.CallbackAutomation(CONF_ON_START, "add_on_start_callback", []), ] diff --git a/esphome/components/zigbee/zigbee_esp32.cpp b/esphome/components/zigbee/zigbee_esp32.cpp index 3500aa3382..482995e2c5 100644 --- a/esphome/components/zigbee/zigbee_esp32.cpp +++ b/esphome/components/zigbee/zigbee_esp32.cpp @@ -65,6 +65,7 @@ bool ZigbeeComponent::app_signal_handler(const ezb_app_signal_t *app_signal) { case EZB_ZDO_SIGNAL_SKIP_STARTUP: ESP_LOGD(TAG, "Zigbee stack initialized"); global_zigbee->started_ = true; + global_zigbee->enable_loop_soon_any_context(); ezb_bdb_start_top_level_commissioning(EZB_BDB_MODE_INITIALIZATION); break; case EZB_BDB_SIGNAL_DEVICE_FIRST_START: @@ -338,6 +339,10 @@ void ZigbeeComponent::setup() { } void ZigbeeComponent::loop() { + if (!this->start_reported_ && this->started_) { + this->start_cb_.call(); + this->start_reported_ = true; + } if (this->join_pending_.exchange(false)) { this->join_cb_.call(this->factory_new_); this->factory_new_ = false; diff --git a/esphome/components/zigbee/zigbee_esp32.h b/esphome/components/zigbee/zigbee_esp32.h index 412b7ac4da..c19fc3ad63 100644 --- a/esphome/components/zigbee/zigbee_esp32.h +++ b/esphome/components/zigbee/zigbee_esp32.h @@ -57,6 +57,7 @@ class ZigbeeComponent final : public Component { void factory_reset(); template void add_on_join_callback(F &&cb) { this->join_cb_.add(std::forward(cb)); } + template void add_on_start_callback(F &&cb) { this->start_cb_.add(std::forward(cb)); } bool is_battery_powered() { return this->basic_cluster_data_.power_source == EZB_ZCL_BASIC_POWER_SOURCE_BATTERY; } @@ -89,6 +90,8 @@ class ZigbeeComponent final : public Component { std::map, ZigbeeAttribute *> attributes_; ezb_af_device_desc_t dev_desc_; CallbackManager join_cb_{}; + LazyCallbackManager start_cb_{}; + bool start_reported_{false}; std::atomic started_ = false; std::atomic joined_ = false; std::atomic join_pending_ = false; diff --git a/esphome/components/zigbee/zigbee_zephyr.cpp b/esphome/components/zigbee/zigbee_zephyr.cpp index fedcb4a9c2..b8bb0a2036 100644 --- a/esphome/components/zigbee/zigbee_zephyr.cpp +++ b/esphome/components/zigbee/zigbee_zephyr.cpp @@ -30,6 +30,9 @@ void ZigbeeComponent::zboss_signal_handler_esphome(zb_bufid_t bufid) { switch (sig) { case ZB_ZDO_SIGNAL_SKIP_STARTUP: ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_SKIP_STARTUP, status: %d", status); + if (status == RET_OK) { + on_start_(); + } break; case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY: ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY, status: %d", status); @@ -137,6 +140,13 @@ void ZigbeeComponent::on_join_(bool factory_new) { }); } +void ZigbeeComponent::on_start_() { + this->defer([this]() { + ESP_LOGD(TAG, "Started zigbee stack"); + this->start_cb_.call(); + }); +} + #ifdef USE_ZIGBEE_WIPE_ON_BOOT void ZigbeeComponent::erase_flash_(int area) { const struct flash_area *fap; diff --git a/esphome/components/zigbee/zigbee_zephyr.h b/esphome/components/zigbee/zigbee_zephyr.h index 8528aebff8..cd6deb0e95 100644 --- a/esphome/components/zigbee/zigbee_zephyr.h +++ b/esphome/components/zigbee/zigbee_zephyr.h @@ -75,6 +75,7 @@ class ZigbeeComponent final : public Component { this->callbacks_[endpoint - 1] = std::move(cb); } template void add_on_join_callback(F &&cb) { this->join_cb_.add(std::forward(cb)); } + template void add_on_start_callback(F &&cb) { this->start_cb_.add(std::forward(cb)); } void zboss_signal_handler_esphome(zb_bufid_t bufid); void after_reporting_info(zb_zcl_configure_reporting_req_t *config_rep_req, zb_zcl_attr_addr_info_t *attr_addr_info); void factory_reset(); @@ -86,12 +87,14 @@ class ZigbeeComponent final : public Component { protected: static void zcl_device_cb(zb_bufid_t bufid); void on_join_(bool factory_new); + void on_start_(); #ifdef USE_ZIGBEE_WIPE_ON_BOOT void erase_flash_(int area); #endif void dump_reporting_(); std::array, ZIGBEE_ENDPOINTS_COUNT> callbacks_{}; CallbackManager join_cb_; + LazyCallbackManager start_cb_; bool force_report_{false}; uint32_t sleep_time_{}; uint32_t sleep_remainder_{}; diff --git a/tests/components/zigbee/common_esp32.yaml b/tests/components/zigbee/common_esp32.yaml index 6cac9c9e2a..ac25fb8faf 100644 --- a/tests/components/zigbee/common_esp32.yaml +++ b/tests/components/zigbee/common_esp32.yaml @@ -27,3 +27,6 @@ zigbee: on_join: then: - logger.log: "Joined network" + on_start: + then: + - logger.log: "Started zigbee stack" diff --git a/tests/components/zigbee/common_nrf52.yaml b/tests/components/zigbee/common_nrf52.yaml index bc39b371f5..c05c4053a5 100644 --- a/tests/components/zigbee/common_nrf52.yaml +++ b/tests/components/zigbee/common_nrf52.yaml @@ -7,6 +7,9 @@ zigbee: on_join: then: - logger.log: "Joined network" + on_start: + then: + - logger.log: "Started zigbee stack" time: - platform: zigbee