From 45beea68eb5c8c5b663b979515e37a0cffedc65c Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 23 Dec 2024 06:49:04 +0100 Subject: [PATCH] [ble_client, bluetooth_proxy, esp32_ble_client, esp32_ble_tracker] fix ble proxy stop working (#7901) Co-authored-by: J. Nick Koston --- esphome/components/ble_client/ble_client.cpp | 3 +- .../bluetooth_proxy/bluetooth_connection.cpp | 5 ++ .../bluetooth_proxy/bluetooth_connection.h | 1 + .../esp32_ble_client/ble_client_base.cpp | 46 +++++++++++++++++++ .../esp32_ble_client/ble_client_base.h | 2 + .../esp32_ble_tracker/esp32_ble_tracker.cpp | 43 +++++++++++++---- .../esp32_ble_tracker/esp32_ble_tracker.h | 12 +++-- 7 files changed, 96 insertions(+), 16 deletions(-) diff --git a/esphome/components/ble_client/ble_client.cpp b/esphome/components/ble_client/ble_client.cpp index 19cf2bc1f3..5cf096c9d4 100644 --- a/esphome/components/ble_client/ble_client.cpp +++ b/esphome/components/ble_client/ble_client.cpp @@ -25,8 +25,7 @@ void BLEClient::loop() { void BLEClient::dump_config() { ESP_LOGCONFIG(TAG, "BLE Client:"); - ESP_LOGCONFIG(TAG, " Address: %s", this->address_str().c_str()); - ESP_LOGCONFIG(TAG, " Auto-Connect: %s", TRUEFALSE(this->auto_connect_)); + BLEClientBase::dump_config(); } bool BLEClient::parse_device(const espbt::ESPBTDevice &device) { diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 543752853e..b63f7ccde9 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -13,6 +13,11 @@ namespace bluetooth_proxy { static const char *const TAG = "bluetooth_proxy.connection"; +void BluetoothConnection::dump_config() { + ESP_LOGCONFIG(TAG, "BLE Connection:"); + BLEClientBase::dump_config(); +} + bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { if (!BLEClientBase::gattc_event_handler(event, gattc_if, param)) diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.h b/esphome/components/bluetooth_proxy/bluetooth_connection.h index e6ab3cbccc..fd83f8dd00 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.h +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.h @@ -11,6 +11,7 @@ class BluetoothProxy; class BluetoothConnection : public esp32_ble_client::BLEClientBase { public: + void dump_config() override; bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override; void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override; diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index 98e7792792..53c430350c 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -44,6 +44,50 @@ void BLEClientBase::loop() { float BLEClientBase::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; } +void BLEClientBase::dump_config() { + ESP_LOGCONFIG(TAG, " Address: %s", this->address_str().c_str()); + ESP_LOGCONFIG(TAG, " Auto-Connect: %s", TRUEFALSE(this->auto_connect_)); + std::string state_name; + switch (this->state()) { + case espbt::ClientState::INIT: + state_name = "INIT"; + break; + case espbt::ClientState::DISCONNECTING: + state_name = "DISCONNECTING"; + break; + case espbt::ClientState::IDLE: + state_name = "IDLE"; + break; + case espbt::ClientState::SEARCHING: + state_name = "SEARCHING"; + break; + case espbt::ClientState::DISCOVERED: + state_name = "DISCOVERED"; + break; + case espbt::ClientState::READY_TO_CONNECT: + state_name = "READY_TO_CONNECT"; + break; + case espbt::ClientState::CONNECTING: + state_name = "CONNECTING"; + break; + case espbt::ClientState::CONNECTED: + state_name = "CONNECTED"; + break; + case espbt::ClientState::ESTABLISHED: + state_name = "ESTABLISHED"; + break; + default: + state_name = "UNKNOWN_STATE"; + break; + } + ESP_LOGCONFIG(TAG, " State: %s", state_name.c_str()); + if (this->status_ == ESP_GATT_NO_RESOURCES) { + ESP_LOGE(TAG, " Failed due to no resources. Try to reduce number of BLE clients in config."); + } else if (this->status_ != ESP_GATT_OK) { + ESP_LOGW(TAG, " Failed due to error code %d", this->status_); + } +} + bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) { if (!this->auto_connect_) return false; @@ -129,6 +173,8 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_ } else { ESP_LOGE(TAG, "[%d] [%s] gattc app registration failed id=%d code=%d", this->connection_index_, this->address_str_.c_str(), param->reg.app_id, param->reg.status); + this->status_ = param->reg.status; + this->mark_failed(); } break; } diff --git a/esphome/components/esp32_ble_client/ble_client_base.h b/esphome/components/esp32_ble_client/ble_client_base.h index fca66c0b3c..84c35c4633 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.h +++ b/esphome/components/esp32_ble_client/ble_client_base.h @@ -26,6 +26,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { void setup() override; void loop() override; float get_setup_priority() const override; + void dump_config() override; void run_later(std::function &&f); // NOLINT bool parse_device(const espbt::ESPBTDevice &device) override; @@ -103,6 +104,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { bool paired_{false}; espbt::ConnectionType connection_type_{espbt::ConnectionType::V1}; std::vector services_; + esp_gatt_status_t status_{ESP_GATT_OK}; void log_event_(const char *name); }; diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp index 6d051e3d4a..5fff9dbcad 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp @@ -58,7 +58,6 @@ void ESP32BLETracker::setup() { global_esp32_ble_tracker = this; this->scan_result_lock_ = xSemaphoreCreateMutex(); this->scan_end_lock_ = xSemaphoreCreateMutex(); - this->scanner_idle_ = true; #ifdef USE_OTA ota::get_global_ota_callback()->add_on_state_callback( @@ -107,6 +106,15 @@ void ESP32BLETracker::loop() { break; } } + if (connecting != connecting_ || discovered != discovered_ || searching != searching_ || + disconnecting != disconnecting_) { + connecting_ = connecting; + discovered_ = discovered; + searching_ = searching; + disconnecting_ = disconnecting; + ESP_LOGD(TAG, "connecting: %d, discovered: %d, searching: %d, disconnecting: %d", connecting_, discovered_, + searching_, disconnecting_); + } bool promote_to_connecting = discovered && !searching && !connecting; if (!this->scanner_idle_) { @@ -183,8 +191,9 @@ void ESP32BLETracker::loop() { } if (this->scan_start_failed_ || this->scan_set_param_failed_) { - if (this->scan_start_fail_count_ == 255) { - ESP_LOGE(TAG, "ESP-IDF BLE scan could not restart after 255 attempts, rebooting to restore BLE stack..."); + if (this->scan_start_fail_count_ == std::numeric_limits::max()) { + ESP_LOGE(TAG, "ESP-IDF BLE scan could not restart after %d attempts, rebooting to restore BLE stack...", + std::numeric_limits::max()); App.reboot(); } if (xSemaphoreTake(this->scan_end_lock_, 0L)) { @@ -282,6 +291,12 @@ void ESP32BLETracker::start_scan_(bool first) { this->scan_params_.scan_interval = this->scan_interval_; this->scan_params_.scan_window = this->scan_window_; + // Start timeout before scan is started. Otherwise scan never starts if any error. + this->set_timeout("scan", this->scan_duration_ * 2000, []() { + ESP_LOGE(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); + App.reboot(); + }); + esp_err_t err = esp_ble_gap_set_scan_params(&this->scan_params_); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gap_set_scan_params failed: %d", err); @@ -293,11 +308,6 @@ void ESP32BLETracker::start_scan_(bool first) { return; } this->scanner_idle_ = false; - - this->set_timeout("scan", this->scan_duration_ * 2000, []() { - ESP_LOGE(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); - App.reboot(); - }); } void ESP32BLETracker::end_of_scan_() { @@ -371,6 +381,7 @@ void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_ga } void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param ¶m) { + ESP_LOGV(TAG, "gap_scan_set_param_complete - status %d", param.status); if (param.status == ESP_BT_STATUS_DONE) { this->scan_set_param_failed_ = ESP_BT_STATUS_SUCCESS; } else { @@ -379,20 +390,25 @@ void ESP32BLETracker::gap_scan_set_param_complete_(const esp_ble_gap_cb_param_t: } void ESP32BLETracker::gap_scan_start_complete_(const esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param ¶m) { + ESP_LOGV(TAG, "gap_scan_start_complete - status %d", param.status); this->scan_start_failed_ = param.status; if (param.status == ESP_BT_STATUS_SUCCESS) { this->scan_start_fail_count_ = 0; } else { - this->scan_start_fail_count_++; + if (this->scan_start_fail_count_ != std::numeric_limits::max()) { + this->scan_start_fail_count_++; + } xSemaphoreGive(this->scan_end_lock_); } } void ESP32BLETracker::gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m) { + ESP_LOGV(TAG, "gap_scan_stop_complete - status %d", param.status); xSemaphoreGive(this->scan_end_lock_); } void ESP32BLETracker::gap_scan_result_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) { + ESP_LOGV(TAG, "gap_scan_result - event %d", param.search_evt); if (param.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) { if (xSemaphoreTake(this->scan_result_lock_, 0L)) { if (this->scan_result_index_ < ESP32BLETracker::SCAN_RESULT_BUFFER_SIZE) { @@ -663,7 +679,14 @@ void ESP32BLETracker::dump_config() { ESP_LOGCONFIG(TAG, " Scan Interval: %.1f ms", this->scan_interval_ * 0.625f); ESP_LOGCONFIG(TAG, " Scan Window: %.1f ms", this->scan_window_ * 0.625f); ESP_LOGCONFIG(TAG, " Scan Type: %s", this->scan_active_ ? "ACTIVE" : "PASSIVE"); - ESP_LOGCONFIG(TAG, " Continuous Scanning: %s", this->scan_continuous_ ? "True" : "False"); + ESP_LOGCONFIG(TAG, " Continuous Scanning: %s", YESNO(this->scan_continuous_)); + ESP_LOGCONFIG(TAG, " Scanner Idle: %s", YESNO(this->scanner_idle_)); + ESP_LOGCONFIG(TAG, " Scan End: %s", YESNO(xSemaphoreGetMutexHolder(this->scan_end_lock_) == nullptr)); + ESP_LOGCONFIG(TAG, " Connecting: %d, discovered: %d, searching: %d, disconnecting: %d", connecting_, discovered_, + searching_, disconnecting_); + if (this->scan_start_fail_count_) { + ESP_LOGCONFIG(TAG, " Scan Start Fail Count: %d", this->scan_start_fail_count_); + } } void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) { diff --git a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h index 2fc5da829d..52b091619e 100644 --- a/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +++ b/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h @@ -178,7 +178,7 @@ class ESPBTClient : public ESPBTDeviceListener { int app_id; protected: - ClientState state_; + ClientState state_{ClientState::INIT}; }; class ESP32BLETracker : public Component, @@ -229,7 +229,7 @@ class ESP32BLETracker : public Component, /// Called when a `ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT` event is received. void gap_scan_stop_complete_(const esp_ble_gap_cb_param_t::ble_scan_stop_cmpl_evt_param ¶m); - int app_id_; + int app_id_{0}; /// Vector of addresses that have already been printed in print_bt_device_info std::vector already_discovered_; @@ -242,10 +242,10 @@ class ESP32BLETracker : public Component, uint32_t scan_duration_; uint32_t scan_interval_; uint32_t scan_window_; - uint8_t scan_start_fail_count_; + uint8_t scan_start_fail_count_{0}; bool scan_continuous_; bool scan_active_; - bool scanner_idle_; + bool scanner_idle_{true}; bool ble_was_disabled_{true}; bool raw_advertisements_{false}; bool parse_advertisements_{false}; @@ -260,6 +260,10 @@ class ESP32BLETracker : public Component, esp_ble_gap_cb_param_t::ble_scan_result_evt_param *scan_result_buffer_; esp_bt_status_t scan_start_failed_{ESP_BT_STATUS_SUCCESS}; esp_bt_status_t scan_set_param_failed_{ESP_BT_STATUS_SUCCESS}; + int connecting_{0}; + int discovered_{0}; + int searching_{0}; + int disconnecting_{0}; }; // NOLINTNEXTLINE