ESPHome 2026.3.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
19namespace esphome {
20namespace esp32_ble_server {
21
22static const char *const TAG = "esp32_ble_server";
23
25 if (this->parent_->is_failed()) {
26 this->mark_failed();
27 ESP_LOGE(TAG, "BLE Server was marked failed by ESP32BLE");
28 return;
29 }
30 global_ble_server = this;
31}
32
34 if (!this->parent_->is_active()) {
35 return;
36 }
37 switch (this->state_) {
38 case RUNNING: {
39 // Start all services that are pending to start
40 if (!this->services_to_start_.empty()) {
41 uint16_t index_to_remove = 0;
42 // Iterate over the services to start
43 for (unsigned i = 0; i < this->services_to_start_.size(); i++) {
44 BLEService *service = this->services_to_start_[i];
45 if (service->is_created()) {
46 service->start(); // Needs to be called once per characteristic in the service
47 } else {
48 index_to_remove = i + 1;
49 }
50 }
51 // Remove the services that have been started
52 if (index_to_remove > 0) {
53 this->services_to_start_.erase(this->services_to_start_.begin(),
54 this->services_to_start_.begin() + index_to_remove - 1);
55 }
56 }
57 break;
58 }
59 case INIT: {
60 esp_err_t err = esp_ble_gatts_app_register(0);
61 if (err != ESP_OK) {
62 ESP_LOGE(TAG, "esp_ble_gatts_app_register failed: %d", err);
63 this->mark_failed();
64 return;
65 }
66 this->state_ = REGISTERING;
67 break;
68 }
69 case REGISTERING: {
70 if (this->registered_) {
71 // Create the device information service first so
72 // it is at the top of the GATT table
74 // Create all services previously created
75 for (auto &entry : this->services_) {
76 if (entry.service == this->device_information_service_) {
77 continue;
78 }
79 entry.service->do_create(this);
80 }
81 this->state_ = STARTING_SERVICE;
82 }
83 break;
84 }
85 case STARTING_SERVICE: {
87 this->state_ = RUNNING;
89 ESP_LOGD(TAG, "BLE server setup successfully");
90 } else if (this->device_information_service_->is_created()) {
92 }
93 break;
94 }
95 }
96}
97
98bool BLEServer::is_running() { return this->parent_->is_active() && this->state_ == RUNNING; }
99
100bool BLEServer::can_proceed() { return this->is_running() || !this->parent_->is_active(); }
101
103 if (this->is_running()) {
104 this->parent_->advertising_set_manufacturer_data(this->manufacturer_data_);
105 }
106}
107
108BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles) {
109#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
110 char uuid_buf[esp32_ble::UUID_STR_LEN];
111 uuid.to_str(uuid_buf);
112 ESP_LOGV(TAG, "Creating BLE service - %s", uuid_buf);
113#endif
114 // Calculate the inst_id for the service
115 uint8_t inst_id = 0;
116 for (; inst_id < 0xFF; inst_id++) {
117 if (this->get_service(uuid, inst_id) == nullptr) {
118 break;
119 }
120 }
121 if (inst_id == 0xFF) {
122 char warn_uuid_buf[esp32_ble::UUID_STR_LEN];
123 uuid.to_str(warn_uuid_buf);
124 ESP_LOGW(TAG, "Could not create BLE service %s, too many instances", warn_uuid_buf);
125 return nullptr;
126 }
127 BLEService *service = // NOLINT(cppcoreguidelines-owning-memory)
128 new BLEService(uuid, num_handles, inst_id, advertise);
129 this->services_.push_back({uuid, inst_id, service});
130 if (this->parent_->is_active() && this->registered_) {
131 service->do_create(this);
132 }
133 return service;
134}
135
136void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
137#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
138 char uuid_buf[esp32_ble::UUID_STR_LEN];
139 uuid.to_str(uuid_buf);
140 ESP_LOGV(TAG, "Removing BLE service - %s %d", uuid_buf, inst_id);
141#endif
142 for (auto it = this->services_.begin(); it != this->services_.end(); ++it) {
143 if (it->uuid == uuid && it->inst_id == inst_id) {
144 it->service->do_delete();
145 delete it->service; // NOLINT(cppcoreguidelines-owning-memory)
146 this->services_.erase(it);
147 return;
148 }
149 }
150 char warn_uuid_buf[esp32_ble::UUID_STR_LEN];
151 uuid.to_str(warn_uuid_buf);
152 ESP_LOGW(TAG, "BLE service %s %d does not exist", warn_uuid_buf, inst_id);
153}
154
156 for (auto &entry : this->services_) {
157 if (entry.uuid == uuid && entry.inst_id == inst_id) {
158 return entry.service;
159 }
160 }
161 return nullptr;
162}
163
165 for (auto &entry : this->callbacks_) {
166 if (entry.type == type) {
167 entry.callback(conn_id);
168 }
169 }
170}
171
172void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
173 esp_ble_gatts_cb_param_t *param) {
174 switch (event) {
175 case ESP_GATTS_CONNECT_EVT: {
176 ESP_LOGD(TAG, "BLE Client connected");
177 this->add_client_(param->connect.conn_id);
178 // Resume advertising so additional clients can discover and connect
180 this->parent_->advertising_start();
181 }
182 this->dispatch_callbacks_(CallbackType::ON_CONNECT, param->connect.conn_id);
183 break;
184 }
185 case ESP_GATTS_DISCONNECT_EVT: {
186 ESP_LOGD(TAG, "BLE Client disconnected");
187 this->remove_client_(param->disconnect.conn_id);
188 this->parent_->advertising_start();
189 this->dispatch_callbacks_(CallbackType::ON_DISCONNECT, param->disconnect.conn_id);
190 break;
191 }
192 case ESP_GATTS_REG_EVT: {
193 this->gatts_if_ = gatts_if;
194 this->registered_ = true;
195 break;
196 }
197 default:
198 break;
199 }
200
201 for (auto &entry : this->services_) {
202 entry.service->gatts_event_handler(event, gatts_if, param);
203 }
204}
205
206int8_t BLEServer::find_client_index_(uint16_t conn_id) const {
207 for (uint8_t i = 0; i < this->client_count_; i++) {
208 if (this->clients_[i] == conn_id)
209 return i;
210 }
211 return -1;
212}
213
214void BLEServer::add_client_(uint16_t conn_id) {
215 // Check if already in list
216 if (this->find_client_index_(conn_id) >= 0)
217 return;
218 // Add if there's space
219 if (this->client_count_ < USE_ESP32_BLE_MAX_CONNECTIONS) {
220 this->clients_[this->client_count_++] = conn_id;
221 } else {
222 // This should never happen since max clients is known at compile time
223 ESP_LOGE(TAG, "Client array full");
224 }
225}
226
227void BLEServer::remove_client_(uint16_t conn_id) {
228 int8_t index = this->find_client_index_(conn_id);
229 if (index >= 0) {
230 // Replace with last element and decrement count (client order not preserved)
231 this->clients_[index] = this->clients_[--this->client_count_];
232 }
233}
234
236 // Delete all clients
237 this->client_count_ = 0;
238 // Delete all services
239 for (auto &entry : this->services_) {
240 entry.service->do_delete();
241 }
242 this->registered_ = false;
243 this->state_ = INIT;
244}
245
247
249 ESP_LOGCONFIG(TAG,
250 "ESP32 BLE Server:\n"
251 " Max clients: %u",
252 this->max_clients_);
253}
254
255BLEServer *global_ble_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
256
257} // namespace esp32_ble_server
258} // namespace esphome
259
260#endif
void mark_failed()
Mark this component as failed.
ESPDEPRECATED("Use to_str() instead. Removed in 2026.8.0", "2026.2.0") std const char * to_str(std::span< char, UUID_STR_LEN > output) const
Definition ble_uuid.cpp:146
std::vector< CallbackEntry > callbacks_
Definition ble_server.h:93
void ble_before_disabled_event_handler() override
std::vector< uint8_t > manufacturer_data_
Definition ble_server.h:95
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)
BLEService * get_service(ESPBTUUID uuid, uint8_t inst_id=0)
std::vector< BLEService * > services_to_start_
Definition ble_server.h:103
BLEService * create_service(ESPBTUUID uuid, bool advertise=false, uint16_t num_handles=15)
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) override
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:102
uint16_t clients_[USE_ESP32_BLE_MAX_CONNECTIONS]
Definition ble_server.h:99
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:35
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7