From 45beea68eb5c8c5b663b979515e37a0cffedc65c Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Mon, 23 Dec 2024 06:49:04 +0100 Subject: [PATCH 1/2] [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 From 387bde665e3ae5d4b8d5a68299abd6032c4291b8 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Tue, 24 Dec 2024 04:15:40 -0500 Subject: [PATCH 2/2] [esp32_rmt] IDF 5+ update fixes (#8002) Co-authored-by: Jonathan Swoboda Co-authored-by: Keith Burzinski --- .../remote_receiver/remote_receiver_esp32.cpp | 8 ++--- .../components/remote_transmitter/__init__.py | 9 +++++ .../remote_transmitter/remote_transmitter.h | 3 ++ .../remote_transmitter_esp32.cpp | 34 ++++++++++++++++--- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index 48b84d61d4..8a36971e36 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -154,16 +154,16 @@ void RemoteReceiverComponent::setup() { void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, "Remote Receiver:"); LOG_PIN(" Pin: ", this->pin_); - if (this->pin_->digital_read()) { - ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " - "invert the signal using 'inverted: True' in the pin schema!"); - } #if ESP_IDF_VERSION_MAJOR >= 5 ESP_LOGCONFIG(TAG, " Clock resolution: %" PRIu32 " hz", this->clock_resolution_); ESP_LOGCONFIG(TAG, " RMT symbols: %" PRIu32, this->rmt_symbols_); ESP_LOGCONFIG(TAG, " Filter symbols: %" PRIu32, this->filter_symbols_); ESP_LOGCONFIG(TAG, " Receive symbols: %" PRIu32, this->receive_symbols_); #else + if (this->pin_->digital_read()) { + ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " + "invert the signal using 'inverted: True' in the pin schema!"); + } ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_); ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); diff --git a/esphome/components/remote_transmitter/__init__.py b/esphome/components/remote_transmitter/__init__.py index ea29751671..e3462fb246 100644 --- a/esphome/components/remote_transmitter/__init__.py +++ b/esphome/components/remote_transmitter/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_CLOCK_DIVIDER, CONF_CLOCK_RESOLUTION, CONF_ID, + CONF_INVERTED, CONF_PIN, CONF_RMT_CHANNEL, CONF_RMT_SYMBOLS, @@ -16,6 +17,7 @@ from esphome.core import CORE AUTO_LOAD = ["remote_base"] +CONF_EOT_LEVEL = "eot_level" CONF_ON_TRANSMIT = "on_transmit" CONF_ON_COMPLETE = "on_complete" CONF_ONE_WIRE = "one_wire" @@ -41,6 +43,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_CLOCK_DIVIDER): cv.All( cv.only_on_esp32, cv.only_with_arduino, cv.int_range(min=1, max=255) ), + cv.Optional(CONF_EOT_LEVEL): cv.All(cv.only_with_esp_idf, cv.boolean), cv.Optional(CONF_ONE_WIRE): cv.All(cv.only_with_esp_idf, cv.boolean), cv.Optional(CONF_USE_DMA): cv.All(cv.only_with_esp_idf, cv.boolean), cv.SplitDefault( @@ -73,6 +76,12 @@ async def to_code(config): cg.add(var.set_with_dma(config[CONF_USE_DMA])) if CONF_ONE_WIRE in config: cg.add(var.set_one_wire(config[CONF_ONE_WIRE])) + if CONF_EOT_LEVEL in config: + cg.add(var.set_eot_level(config[CONF_EOT_LEVEL])) + elif CONF_ONE_WIRE in config and config[CONF_ONE_WIRE]: + cg.add(var.set_eot_level(True)) + elif CONF_INVERTED in config[CONF_PIN] and config[CONF_PIN][CONF_INVERTED]: + cg.add(var.set_eot_level(True)) else: if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None: var = cg.new_Pvariable(config[CONF_ID], pin, rmt_channel) diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index 20b98d5488..fd1d182063 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -41,6 +41,8 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, #if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR >= 5 void set_with_dma(bool with_dma) { this->with_dma_ = with_dma; } void set_one_wire(bool one_wire) { this->one_wire_ = one_wire; } + void set_eot_level(bool eot_level) { this->eot_level_ = eot_level; } + void digital_write(bool value); #endif Trigger<> *get_transmit_trigger() const { return this->transmit_trigger_; }; @@ -68,6 +70,7 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, std::vector rmt_temp_; bool with_dma_{false}; bool one_wire_{false}; + bool eot_level_{false}; rmt_channel_handle_t channel_{NULL}; rmt_encoder_handle_t encoder_{NULL}; #else diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp index efb1735bfd..cd7f366373 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp @@ -11,6 +11,7 @@ static const char *const TAG = "remote_transmitter"; void RemoteTransmitterComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up Remote Transmitter..."); + this->inverted_ = this->pin_->is_inverted(); this->configure_rmt_(); } @@ -37,6 +38,31 @@ void RemoteTransmitterComponent::dump_config() { } } +#if ESP_IDF_VERSION_MAJOR >= 5 +void RemoteTransmitterComponent::digital_write(bool value) { + rmt_symbol_word_t symbol = { + .duration0 = 1, + .level0 = value, + .duration1 = 0, + .level1 = value, + }; + rmt_transmit_config_t config; + memset(&config, 0, sizeof(config)); + config.loop_count = 0; + config.flags.eot_level = value; + esp_err_t error = rmt_transmit(this->channel_, this->encoder_, &symbol, sizeof(symbol), &config); + if (error != ESP_OK) { + ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error)); + this->status_set_warning(); + } + error = rmt_tx_wait_all_done(this->channel_, -1); + if (error != ESP_OK) { + ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error)); + this->status_set_warning(); + } +} +#endif + void RemoteTransmitterComponent::configure_rmt_() { #if ESP_IDF_VERSION_MAJOR >= 5 esp_err_t error; @@ -83,6 +109,7 @@ void RemoteTransmitterComponent::configure_rmt_() { this->mark_failed(); return; } + this->digital_write(this->one_wire_ || this->inverted_); this->initialized_ = true; } @@ -120,13 +147,12 @@ void RemoteTransmitterComponent::configure_rmt_() { } c.tx_config.idle_output_en = true; - if (!this->pin_->is_inverted()) { + if (!this->inverted_) { c.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH; c.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; } else { c.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; c.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH; - this->inverted_ = true; } esp_err_t error = rmt_config(&c); @@ -210,7 +236,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen rmt_transmit_config_t config; memset(&config, 0, sizeof(config)); config.loop_count = 0; - config.flags.eot_level = this->inverted_; + config.flags.eot_level = this->eot_level_; esp_err_t error = rmt_transmit(this->channel_, this->encoder_, this->rmt_temp_.data(), this->rmt_temp_.size() * sizeof(rmt_symbol_word_t), &config); if (error != ESP_OK) { @@ -223,8 +249,6 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen if (error != ESP_OK) { ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error)); this->status_set_warning(); - } else { - this->status_clear_warning(); } if (i + 1 < send_times) delayMicroseconds(send_wait);