14static const char *
const TAG =
"bluetooth_proxy";
20static_assert(
sizeof(((api::BluetoothLERawAdvertisement *)
nullptr)->data) == 62,
21 "BLE advertisement data array size mismatch");
41 if (connection->get_address() != 0 && !connection->disconnect_pending()) {
42 connection->disconnect();
66 ESP_LOGW(TAG,
"[%d] [%s] Connection request ignored, state: %s", connection->
get_connection_index(),
75 ESP_LOGW(TAG,
"Cannot %s GATT %s, not connected", action,
type);
84#ifdef USE_ESP32_BLE_DEVICE
98 for (
size_t i = 0; i < count; i++) {
99 auto &result = scan_results[i];
100 uint8_t
length = result.adv_data_len + result.scan_rsp_len;
105 adv.rssi = result.rssi;
106 adv.address_type = result.ble_addr_type;
108 std::memcpy(adv.data, result.ble_adv,
length);
112 ESP_LOGV(TAG,
"Queuing raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0],
113 result.bda[1], result.bda[2], result.bda[3], result.bda[4], result.bda[5],
length, result.rssi);
143 uint64_t conn_addr = connection->get_address();
148 if (reserve && conn_addr == 0) {
149 connection->send_service_ = INIT_SENDING_SERVICES;
150 connection->set_address(
address);
155 connection->set_state(espbt::ClientState::INIT);
167 if (connection ==
nullptr) {
168 ESP_LOGW(TAG,
"No free connections available");
173 ESP_LOGE(TAG,
"[%d] [%s] Missing address type in connect request", connection->get_connection_index(),
174 connection->address_str());
178 if (connection->state() == espbt::ClientState::CONNECTED ||
179 connection->state() == espbt::ClientState::ESTABLISHED) {
184 }
else if (connection->state() == espbt::ClientState::CONNECTING) {
185 if (connection->disconnect_pending()) {
186 ESP_LOGW(TAG,
"[%d] [%s] Connection request while pending disconnect, cancelling pending disconnect",
187 connection->get_connection_index(), connection->address_str());
188 connection->cancel_pending_disconnect();
193 }
else if (connection->state() != espbt::ClientState::INIT) {
198 connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
201 connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
205 connection->set_remote_addr_type(
static_cast<esp_ble_addr_type_t
>(msg.
address_type));
206 connection->set_state(espbt::ClientState::DISCOVERED);
212 if (connection ==
nullptr) {
217 if (connection->state() != espbt::ClientState::IDLE) {
218 connection->disconnect();
220 connection->set_address(0);
228 if (connection !=
nullptr) {
229 if (!connection->is_paired()) {
230 auto err = connection->pair();
243 esp_err_t ret = esp_ble_remove_bond_device(
address);
250 esp_err_t ret = esp_ble_gattc_cache_clean(
address);
253 call.success = ret == ESP_OK;
261 ESP_LOGE(TAG,
"V1 connections removed");
270 if (connection ==
nullptr) {
275 auto err = connection->read_characteristic(msg.
handle);
283 if (connection ==
nullptr) {
296 if (connection ==
nullptr) {
301 auto err = connection->read_descriptor(msg.
handle);
309 if (connection ==
nullptr) {
322 if (connection ==
nullptr || !connection->connected()) {
326 if (!connection->service_count_) {
327 ESP_LOGW(TAG,
"[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str());
331 if (connection->send_service_ == INIT_SENDING_SERVICES)
332 connection->send_service_ = 0;
337 if (connection ==
nullptr) {
342 auto err = connection->notify_characteristic(msg.
handle, msg.
enable);
356 if (connection ==
nullptr || !connection->connected()) {
357 ESP_LOGW(TAG,
"[%d] [%s] Cannot set connection params, not connected",
358 connection ?
static_cast<int>(connection->connection_index_) : -1,
359 connection ? connection->address_str() :
"unknown");
360 resp.
error = ESP_GATT_NOT_CONNECTED;
367 constexpr uint32_t max_val = std::numeric_limits<uint16_t>::max();
368 resp.
error = connection->update_connection_params(
static_cast<uint16_t
>(std::min(msg.
min_interval, max_val)),
369 static_cast<uint16_t
>(std::min(msg.
max_interval, max_val)),
370 static_cast<uint16_t
>(std::min(msg.
latency, max_val)),
371 static_cast<uint16_t
>(std::min(msg.
timeout, max_val)));
377 ESP_LOGE(TAG,
"Only one API subscription is allowed at a time");
388 ESP_LOGV(TAG,
"API connection is not subscribed");
400 call.connected = connected;
428 call.handle = handle;
438 call.paired = paired;
449 call.success = success;
459 ESP_LOGD(TAG,
"Setting scanner mode to %s", active ?
"active" :
"passive");
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_interval(const std voi set_interval)(const char *name, uint32_t interval, std::function< void()> &&f)
Set an interval function with a unique name.
bool send_message(const T &msg)
enums::BluetoothDeviceRequestType request_type
std::array< BluetoothLERawAdvertisement, BLUETOOTH_PROXY_ADVERTISEMENT_BATCH_SIZE > advertisements
uint16_t advertisements_len
enums::BluetoothScannerMode mode
enums::BluetoothScannerState state
enums::BluetoothScannerMode configured_mode
void send_gatt_services_done(uint64_t address)
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg)
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg)
void handle_gatt_not_connected_(uint64_t address, uint16_t handle, const char *action, const char *type)
bool configured_scan_active_
esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override
void send_device_connection(uint64_t address, bool connected, uint16_t mtu=0, esp_err_t error=ESP_OK)
void send_device_unpairing(uint64_t address, bool success, esp_err_t error=ESP_OK)
void send_device_pairing(uint64_t address, bool paired, esp_err_t error=ESP_OK)
bool parse_devices(const esp32_ble::BLEScanResult *scan_results, size_t count) override
void log_not_connected_gatt_(const char *action, const char *type)
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg)
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override
void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg)
void send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerState state)
void bluetooth_scanner_set_mode(bool active)
void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags)
void send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error)
void dump_config() override
void send_connections_free()
void unsubscribe_api_connection(api::APIConnection *api_connection)
api::BluetoothLERawAdvertisementsResponse response_
void log_connection_info_(BluetoothConnection *connection, const char *message)
void log_advertisement_flush_()
BluetoothConnection * get_connection_(uint64_t address, bool reserve)
void bluetooth_set_connection_params(const api::BluetoothSetConnectionParamsRequest &msg)
void bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg)
void bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg)
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg)
void on_scanner_state(esp32_ble_tracker::ScannerState state) override
BLEScannerStateListener interface.
void flush_pending_advertisements_()
Caller must ensure api_connection_ is non-null and API server is connected.
static void uint64_to_bd_addr(uint64_t address, esp_bd_addr_t bd_addr)
api::APIConnection * api_connection_
std::array< BluetoothConnection *, BLUETOOTH_PROXY_MAX_CONNECTIONS > connections_
api::BluetoothConnectionsFreeResponse connections_free_response_
uint8_t connection_count_
void log_connection_request_ignored_(BluetoothConnection *connection, espbt::ClientState state)
const char * address_str() const
uint8_t get_connection_index() const
void set_scan_active(bool scan_active)
bool get_scan_active() const
void recalculate_advertisement_parser_types()
ScannerState get_scanner_state() const
void set_scan_continuous(bool scan_continuous)
void add_scanner_state_listener(BLEScannerStateListener *listener)
Add a listener for scanner state changes.
ESP32BLETracker * parent_
@ BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT
@ BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE
@ BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE
@ BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT
@ BLUETOOTH_SCANNER_MODE_PASSIVE
@ BLUETOOTH_SCANNER_MODE_ACTIVE
APIServer * global_api_server
BluetoothProxy * global_bluetooth_proxy
const char * client_state_to_string(ClientState state)
uint64_t ble_addr_to_uint64(const esp_bd_addr_t address)