ESPHome 2026.10.0-dev
Loading...
Searching...
No Matches
ble_server.cpp
Go to the documentation of this file.
1#include "ble_server.h"
2
4#include "esphome/core/log.h"
7
8#ifdef USE_ESP32
9
10#include <nvs_flash.h>
11#include <freertos/FreeRTOSConfig.h>
12#include <esp_bt_main.h>
13#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
14#include <esp_bt.h>
15#endif
16#include <freertos/task.h>
17#include <esp_gap_ble_api.h>
18
20
21static const char *const TAG = "esp32_ble_server";
22
24 if (this->parent_->is_failed()) {
25 this->mark_failed();
26 ESP_LOGE(TAG, "BLE Server was marked failed by ESP32BLE");
27 return;
28 }
29 global_ble_server = this;
30}
31
33 if (!this->parent_->is_active()) {
34 return;
35 }
36 switch (this->state_) {
37 case RUNNING: {
38 // Start all services that are pending to start
39 if (!this->services_to_start_.empty()) {
40 size_t write_idx = 0;
41 for (auto *service : this->services_to_start_) {
42 if (service->is_created()) {
43 service->start(); // Needs to be called once per characteristic in the service
44 }
45 // Remove services that have started or are starting
46 if (!service->is_starting() && !service->is_running()) {
47 this->services_to_start_[write_idx++] = service;
48 }
49 }
50 this->services_to_start_.erase(this->services_to_start_.begin() + write_idx, this->services_to_start_.end());
51 }
52 break;
53 }
54 case INIT: {
55 esp_err_t err = esp_ble_gatts_app_register(0);
56 if (err != ESP_OK) {
57 ESP_LOGE(TAG, "esp_ble_gatts_app_register failed: %d", err);
58 this->mark_failed();
59 return;
60 }
61 this->state_ = REGISTERING;
62 break;
63 }
64 case REGISTERING: {
65 if (this->registered_) {
66 // Create the device information service first so
67 // it is at the top of the GATT table
69 // Create all services previously created
70 for (auto &entry : this->services_) {
71 if (entry.service == this->device_information_service_) {
72 continue;
73 }
74 entry.service->do_create(this);
75 }
76 this->state_ = STARTING_SERVICE;
77 }
78 break;
79 }
80 case STARTING_SERVICE: {
82 this->state_ = RUNNING;
85 ESP_LOGD(TAG, "BLE server setup successfully");
86 } else if (this->device_information_service_->is_created()) {
88 }
89 break;
90 }
91 }
92}
93
94bool BLEServer::can_proceed() { return this->is_running() || !this->parent_->is_active(); }
95
97 if (this->is_running()) {
98 this->parent_->advertising_set_manufacturer_data(this->manufacturer_data_);
99 }
100}
101
104 return;
105 this->advertising_requested_ = true;
106 this->parent_->advertising_start();
107}
108
110 if (!this->advertising_requested_)
111 return;
112 this->advertising_requested_ = false;
113 this->parent_->advertising_stop();
114}
115
116BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles) {
117#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
118 char uuid_buf[esp32_ble::UUID_STR_LEN];
119 uuid.to_str(uuid_buf);
120 ESP_LOGV(TAG, "Creating BLE service - %s", uuid_buf);
121#endif
122 // Calculate the inst_id for the service
123 uint8_t inst_id = 0;
124 for (; inst_id < 0xFF; inst_id++) {
125 if (this->get_service(uuid, inst_id) == nullptr) {
126 break;
127 }
128 }
129 if (inst_id == 0xFF) {
130 char warn_uuid_buf[esp32_ble::UUID_STR_LEN];
131 uuid.to_str(warn_uuid_buf);
132 ESP_LOGW(TAG, "Could not create BLE service %s, too many instances", warn_uuid_buf);
133 return nullptr;
134 }
135 BLEService *service = // NOLINT(cppcoreguidelines-owning-memory)
136 new BLEService(uuid, num_handles, inst_id, advertise);
137 this->services_.push_back({uuid, inst_id, service});
138 if (this->parent_->is_active() && this->registered_) {
139 service->do_create(this);
140 }
141 return service;
142}
143
144void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
145#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
146 char uuid_buf[esp32_ble::UUID_STR_LEN];
147 uuid.to_str(uuid_buf);
148 ESP_LOGV(TAG, "Removing BLE service - %s %d", uuid_buf, inst_id);
149#endif
150 for (auto it = this->services_.begin(); it != this->services_.end(); ++it) {
151 if (it->uuid == uuid && it->inst_id == inst_id) {
152 it->service->do_delete();
153 delete it->service; // NOLINT(cppcoreguidelines-owning-memory)
154 this->services_.erase(it);
155 return;
156 }
157 }
158 char warn_uuid_buf[esp32_ble::UUID_STR_LEN];
159 uuid.to_str(warn_uuid_buf);
160 ESP_LOGW(TAG, "BLE service %s %d does not exist", warn_uuid_buf, inst_id);
161}
162
164 for (auto &entry : this->services_) {
165 if (entry.uuid == uuid && entry.inst_id == inst_id) {
166 return entry.service;
167 }
168 }
169 return nullptr;
170}
171
173 for (auto &entry : this->callbacks_) {
174 if (entry.type == type) {
175 entry.callback(conn_id);
176 }
177 }
178}
179
180void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
181 esp_ble_gatts_cb_param_t *param) {
182 switch (event) {
183 case ESP_GATTS_CONNECT_EVT: {
184 ESP_LOGD(TAG, "BLE Client connected");
185 this->add_client_(param->connect.conn_id);
186 // Resume advertising so additional clients can discover and connect
188 this->parent_->advertising_refresh();
189 }
190 this->dispatch_callbacks_(CallbackType::ON_CONNECT, param->connect.conn_id);
191 break;
192 }
193 case ESP_GATTS_DISCONNECT_EVT: {
194 ESP_LOGD(TAG, "BLE Client disconnected");
195 this->remove_client_(param->disconnect.conn_id);
196 this->parent_->advertising_refresh();
197 this->dispatch_callbacks_(CallbackType::ON_DISCONNECT, param->disconnect.conn_id);
198 break;
199 }
200 case ESP_GATTS_REG_EVT: {
201 this->gatts_if_ = gatts_if;
202 this->registered_ = true;
203 break;
204 }
205 default:
206 break;
207 }
208
209 for (auto &entry : this->services_) {
210 entry.service->gatts_event_handler(event, gatts_if, param);
211 }
212}
213
214int8_t BLEServer::find_client_index_(uint16_t conn_id) const {
215 for (uint8_t i = 0; i < this->client_count_; i++) {
216 if (this->clients_[i] == conn_id)
217 return i;
218 }
219 return -1;
220}
221
222void BLEServer::add_client_(uint16_t conn_id) {
223 // Check if already in list
224 if (this->find_client_index_(conn_id) >= 0)
225 return;
226 // Add if there's space
227 if (this->client_count_ < USE_ESP32_BLE_MAX_CONNECTIONS) {
228 this->clients_[this->client_count_++] = conn_id;
229 } else {
230 // This should never happen since max clients is known at compile time
231 ESP_LOGE(TAG, "Client array full");
232 }
233}
234
235void BLEServer::remove_client_(uint16_t conn_id) {
236 int8_t index = this->find_client_index_(conn_id);
237 if (index >= 0) {
238 // Replace with last element and decrement count (client order not preserved)
239 this->clients_[index] = this->clients_[--this->client_count_];
240 }
241}
242
244 // Advertising is re-requested once the server is running again after BLE is re-enabled
245 this->release_advertising_();
246 // Delete all clients
247 this->client_count_ = 0;
248 // Delete all services
249 for (auto &entry : this->services_) {
250 entry.service->do_delete();
251 }
252 this->registered_ = false;
253 this->state_ = INIT;
254}
255
257
259 ESP_LOGCONFIG(TAG,
260 "ESP32 BLE Server:\n"
261 " Max clients: %u",
262 this->max_clients_);
263}
264
265BLEServer *global_ble_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
266
267} // namespace esphome::esp32_ble_server
268
269#endif
void mark_failed()
Mark this component as failed.
const char * to_str(char *buf) const
Write "0xABCD" / "0xABCDEF01" / the dashed 128-bit form, or "None" for an unset UUID,...
std::vector< CallbackEntry > callbacks_
Definition ble_server.h:100
std::vector< uint8_t > manufacturer_data_
Definition ble_server.h:102
void remove_client_(uint16_t conn_id)
float get_setup_priority() const override
enum esphome::esp32_ble_server::BLEServer::State INIT
void dispatch_callbacks_(CallbackType type, uint16_t conn_id)
ESPHOME_ALWAYS_INLINE bool is_running()
Definition ble_server.h:34
BLEService * get_service(ESPBTUUID uuid, uint8_t inst_id=0)
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
std::vector< BLEService * > services_to_start_
Definition ble_server.h:112
BLEService * create_service(ESPBTUUID uuid, bool advertise=false, uint16_t num_handles=15)
void remove_service(ESPBTUUID uuid, uint8_t inst_id=0)
void add_client_(uint16_t conn_id)
std::vector< ServiceEntry > services_
Definition ble_server.h:111
uint16_t clients_[USE_ESP32_BLE_MAX_CONNECTIONS]
Definition ble_server.h:108
int8_t find_client_index_(uint16_t conn_id) const
void do_create(BLEServer *server)
uint16_t type
constexpr float AFTER_BLUETOOTH
Definition component.h:49