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