diff --git a/esphome/components/esp32_ble_server/__init__.py b/esphome/components/esp32_ble_server/__init__.py index 109b942750..d0634232d9 100644 --- a/esphome/components/esp32_ble_server/__init__.py +++ b/esphome/components/esp32_ble_server/__init__.py @@ -186,6 +186,7 @@ async def to_code(config): desc_var = cg.new_Pvariable(descriptor[CONF_ID], parse_uuid(descriptor[CONF_UUID]), max_length) if CONF_VALUE in descriptor: cg.add(desc_var.set_value(parse_value(descriptor[CONF_VALUE]))) + cg.add(var.enqueue_start_service(service_var)) cg.add_define("USE_ESP32_BLE_SERVER") if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) diff --git a/esphome/components/esp32_ble_server/ble_characteristic.cpp b/esphome/components/esp32_ble_server/ble_characteristic.cpp index 6ff7d615f9..e66c260938 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_server/ble_characteristic.cpp @@ -289,7 +289,7 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt } if (!param->write.is_prep) { - this->on_write_(this->value_); + if (this->on_write_) this->on_write_(this->value_); } break; @@ -300,7 +300,7 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt break; this->write_event_ = false; if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { - this->on_write_(this->value_); + if (this->on_write_) this->on_write_(this->value_); } esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr); diff --git a/esphome/components/esp32_ble_server/ble_server.cpp b/esphome/components/esp32_ble_server/ble_server.cpp index e5e0ed0fbe..72ee1d744d 100644 --- a/esphome/components/esp32_ble_server/ble_server.cpp +++ b/esphome/components/esp32_ble_server/ble_server.cpp @@ -38,9 +38,25 @@ void BLEServer::loop() { return; } switch (this->state_) { - case RUNNING: - return; - + case RUNNING: { + if (this->services_to_start_.empty()) break; + uint16_t index_to_remove = 0; + // Iterate over the services to start + for (unsigned i = 0; i < this->services_to_start_.size(); i++) { + BLEService *service = this->services_to_start_[i]; + if (service->is_created()) { + service->start(); + } else { + index_to_remove = i + 1; + } + } + // Remove the services that have been started + if (index_to_remove > 0) { + this->services_to_start_.erase(this->services_to_start_.begin(), + this->services_to_start_.begin() + index_to_remove - 1); + } + break; + } case INIT: { esp_err_t err = esp_ble_gatts_app_register(0); if (err != ESP_OK) { @@ -66,14 +82,11 @@ void BLEServer::loop() { break; } case STARTING_SERVICE: { - if (!this->device_information_service_->is_created()) { - break; - } if (this->device_information_service_->is_running()) { this->state_ = RUNNING; this->restart_advertising_(); ESP_LOGD(TAG, "BLE server setup successfully"); - } else if (!this->device_information_service_->is_starting()) { + } else if (this->device_information_service_->is_created()) { this->device_information_service_->start(); } break; diff --git a/esphome/components/esp32_ble_server/ble_server.h b/esphome/components/esp32_ble_server/ble_server.h index 98be1720b1..fa6c8f142a 100644 --- a/esphome/components/esp32_ble_server/ble_server.h +++ b/esphome/components/esp32_ble_server/ble_server.h @@ -46,6 +46,7 @@ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEv BLEService *create_service(ESPBTUUID uuid, bool advertise = false, uint16_t num_handles = 15); void remove_service(ESPBTUUID uuid, uint8_t inst_id = 0); BLEService *get_service(ESPBTUUID uuid, uint8_t inst_id = 0); + void enqueue_start_service(BLEService *service) { this->services_to_start_.push_back(service); } esp_gatt_if_t get_gatts_if() { return this->gatts_if_; } uint32_t get_connected_client_count() { return this->connected_clients_; } @@ -73,6 +74,7 @@ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEv uint32_t connected_clients_{0}; std::unordered_map clients_; std::unordered_map services_; + std::vector services_to_start_; BLEService *device_information_service_; enum State : uint8_t { diff --git a/esphome/components/esp32_ble_server/ble_service.cpp b/esphome/components/esp32_ble_server/ble_service.cpp index 627b17b2ee..69dd8f3b2e 100644 --- a/esphome/components/esp32_ble_server/ble_service.cpp +++ b/esphome/components/esp32_ble_server/ble_service.cpp @@ -52,16 +52,16 @@ void BLEService::do_create(BLEServer *server) { esp_err_t err = esp_ble_gatts_create_service(server->get_gatts_if(), &srvc_id, this->num_handles_); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gatts_create_service failed: %d", err); - this->init_state_ = FAILED; + this->state_ = FAILED; return; } - this->init_state_ = CREATING; + this->state_ = CREATING; } void BLEService::do_delete() { - if (this->init_state_ == DELETING || this->init_state_ == DELETED) + if (this->state_ == DELETING || this->state_ == DELETED) return; - this->init_state_ = DELETING; + this->state_ = DELETING; this->created_characteristic_count_ = 0; this->last_created_characteristic_ = nullptr; this->stop_(); @@ -86,18 +86,12 @@ bool BLEService::do_create_characteristics_() { return true; } -void BLEService::enqueue_start() { - if (this->init_state_ == CREATED) - this->start(); - else - this->should_start_ = true; -} - void BLEService::start() { if (this->do_create_characteristics_()) return; should_start_ = true; + this->state_ = STARTING; esp_err_t err = esp_ble_gatts_start_service(this->handle_); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gatts_start_service failed: %d", err); @@ -105,7 +99,6 @@ void BLEService::start() { } if (this->advertise_) esp32_ble::global_ble->advertising_add_service_uuid(this->uuid_); - this->running_state_ = STARTING; } void BLEService::stop() { @@ -114,9 +107,9 @@ void BLEService::stop() { } void BLEService::stop_() { - if (this->running_state_ == STOPPING || this->running_state_ == STOPPED) + if (this->state_ == STOPPING || this->state_ == STOPPED) return; - this->running_state_ = STOPPING; + this->state_ = STOPPING; esp_err_t err = esp_ble_gatts_stop_service(this->handle_); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err); @@ -126,17 +119,16 @@ void BLEService::stop_() { esp32_ble::global_ble->advertising_remove_service_uuid(this->uuid_); } -bool BLEService::is_created() { return this->init_state_ == CREATED; } bool BLEService::is_failed() { - if (this->init_state_ == FAILED) + if (this->state_ == FAILED) return true; bool failed = false; for (auto *characteristic : this->characteristics_) failed |= characteristic->is_failed(); if (failed) - this->init_state_ = FAILED; - return this->init_state_ == FAILED; + this->state_ = FAILED; + return this->state_ == FAILED; } void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, @@ -146,7 +138,7 @@ void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t g if (this->uuid_ == ESPBTUUID::from_uuid(param->create.service_id.id.uuid) && this->inst_id_ == param->create.service_id.id.inst_id) { this->handle_ = param->create.service_handle; - this->init_state_ = CREATED; + this->state_ = CREATED; if (this->should_start_) this->start(); } @@ -154,18 +146,18 @@ void BLEService::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t g } case ESP_GATTS_DELETE_EVT: if (param->del.service_handle == this->handle_) { - this->init_state_ = DELETED; + this->state_ = DELETED; } break; case ESP_GATTS_START_EVT: { if (param->start.service_handle == this->handle_) { - this->running_state_ = RUNNING; + this->state_ = RUNNING; } break; } case ESP_GATTS_STOP_EVT: { if (param->start.service_handle == this->handle_) { - this->running_state_ = STOPPED; + this->state_ = STOPPED; } break; } diff --git a/esphome/components/esp32_ble_server/ble_service.h b/esphome/components/esp32_ble_server/ble_service.h index f5cff6059e..d63837b39b 100644 --- a/esphome/components/esp32_ble_server/ble_service.h +++ b/esphome/components/esp32_ble_server/ble_service.h @@ -42,20 +42,18 @@ class BLEService { void do_delete(); void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); - void enqueue_start(); void start(); void stop(); - bool is_created(); bool is_failed(); - - bool is_running() { return this->running_state_ == RUNNING; } - bool is_starting() { return this->running_state_ == STARTING; } - bool is_deleted() { return this->init_state_ == DELETED; } + bool is_created() { return this->state_ == CREATED; } + bool is_running() { return this->state_ == RUNNING; } + bool is_starting() { return this->state_ == STARTING; } + bool is_deleted() { return this->state_ == DELETED; } void on_client_connect(const std::function &&func) { this->on_client_connect_ = func; } void on_client_disconnect(const std::function &&func) { this->on_client_disconnect_ = func; } - void emit_client_connect(const uint16_t conn_id) { this->on_client_connect_(conn_id); } - void emit_client_disconnect(const uint16_t conn_id) { this->on_client_disconnect_(conn_id); } + void emit_client_connect(const uint16_t conn_id) { if (this->on_client_connect_ && this->is_running()) this->on_client_connect_(conn_id); } + void emit_client_disconnect(const uint16_t conn_id) { if (this->on_client_disconnect_ && this->is_running()) this->on_client_disconnect_(conn_id); } protected: std::vector characteristics_; @@ -74,22 +72,18 @@ class BLEService { bool do_create_characteristics_(); void stop_(); - enum InitState : uint8_t { + enum State : uint8_t { FAILED = 0x00, INIT, CREATING, - CREATING_DEPENDENTS, CREATED, - DELETING, - DELETED, - } init_state_{INIT}; - - enum RunningState : uint8_t { STARTING, RUNNING, STOPPING, STOPPED, - } running_state_{STOPPED}; + DELETING, + DELETED, + } state_{INIT}; }; } // namespace esp32_ble_server diff --git a/esphome/components/esp32_improv/esp32_improv_component.cpp b/esphome/components/esp32_improv/esp32_improv_component.cpp index b265a08e4b..011ba95da8 100644 --- a/esphome/components/esp32_improv/esp32_improv_component.cpp +++ b/esphome/components/esp32_improv/esp32_improv_component.cpp @@ -88,15 +88,15 @@ void ESP32ImprovComponent::loop() { case improv::STATE_STOPPED: this->set_status_indicator_state_(false); - if (this->service_->is_created() && this->should_start_ && this->setup_complete_) { - if (this->service_->is_running()) { + if (this->should_start_ && this->setup_complete_) { + if (this->service_->is_created()) { + this->service_->start(); + } else if (this->service_->is_running()) { esp32_ble::global_ble->advertising_start(); this->set_state_(improv::STATE_AWAITING_AUTHORIZATION); this->set_error_(improv::ERROR_NONE); ESP_LOGD(TAG, "Service started!"); - } else { - this->service_->start(); } } break;