ESPHome 2026.8.0b4
Loading...
Searching...
No Matches
ble_gatt_client.h
Go to the documentation of this file.
1// ble_gatt_client.h
2//
3// Platform-neutral GATT client connection contract.
4//
5// Exactly one GATT backend exists per build, so BLEGattConnection is a
6// compile-time alias (bluetooth_connection_gatt_backend.h), not an abstract
7// interface.
8// A consumer - the hub wrapper streaming the raw database, or a direct
9// consumer owning a dedicated backend and resolving handles by UUID -
10// drives it and receives completions through the GattClientListener
11// interface. All listener calls are delivered on the ESPHome main loop;
12// borrowed data pointers are valid only for the duration of the call.
13//
14// Error domain (plain int, forwarded to the API without translation):
15// 0 success
16// 1..0x11 ATT error codes (Bluetooth spec; BTstack and Bluedroid agree)
17// GATT_ERR_NOT_CONNECTED (-1) no connection to the peer (on esp32 a raw
18// ESP_FAIL from the stack shares this value; both read as a
19// failed, unusable connection on the client side)
20// GATT_ERR_NO_MEMORY (-2) backend storage exhausted
21// anything else: platform stack error/status code, surfaced opaquely.
22// Connection events carry HCI status/disconnect reason codes (same code
23// space on every controller).
24
25#pragma once
26
28
29#ifdef USE_BLE_GATT_CLIENT
30
31#include "ble_client_state.h"
32#include "ble_device.h"
33
34#include <concepts>
35#include <cstdint>
36
38
39// Materialized GATT database of a connected peer, discovered by the backend
40// and streamed to the API by the consumer. Flat arrays with index ranges
41// (not pointers): a service owns characteristics
42// [first_characteristic, first_characteristic + characteristic_count) and a
43// characteristic owns descriptors [first_descriptor, ...) — discovery is
44// depth-first, so the ranges are naturally contiguous.
47 uint16_t handle;
48};
49
52 uint16_t value_handle;
53 // Needed to rebuild the stack's characteristic object for CCCD operations.
54 uint16_t end_handle;
55 uint8_t properties; // Bluetooth spec property bitfield
58};
59
67
74 const GattService *services{nullptr};
76 const GattDescriptor *descriptors{nullptr};
77 uint16_t service_count{0};
79 uint16_t descriptor_count{0};
80};
81
89 public:
90 virtual void on_connection_state(bool connected, uint16_t mtu, int error) {}
91 virtual void on_service_discovery_done(int error) {}
92 virtual void on_read_result(uint16_t handle, const uint8_t *data, uint16_t len, int error) {}
93 virtual void on_write_result(uint16_t handle, int error) {}
94 virtual void on_notify_state(uint16_t handle, bool enabled, int error) {}
95 virtual void on_notify_data(uint16_t handle, const uint8_t *data, uint16_t len) {}
96 virtual void on_pairing_result(int status) {}
97};
98
99// The BLEGattConnection op surface, asserted where the alias binds
100// (bluetooth_connection_gatt_backend.h). Operations return 0 when accepted (completion arrives
101// through the listener) or a synchronous error (busy, not connected, stack
102// rejection); one operation may be outstanding at a time. Semantics beyond
103// the signatures:
104// - connect: addr_type is a BLE_ADDR_TYPE_* constant (ble_device.h).
105// - gatt_disconnect: also cancels a connect in progress (named to coexist
106// with a platform stack's own void disconnect() on one backend class).
107// Nonzero means nothing to tear down and no completion will follow; an
108// accepted teardown (0) always reaches a terminal on_connection_state.
109// - cancel_gatt_disconnect: true cancels a scheduled teardown that has not
110// started closing - the in-flight connect resumes and completes normally.
111// False once the teardown owns the link (or nothing was scheduled).
112// - notify_characteristic: local registration only; the CCCD write is the
113// API client's responsibility (a plain write_descriptor).
114// - get_service_table/release_services: backend-owned transient storage,
115// released after streaming (release is idempotent). A backend may
116// additionally provide its own service streamer (stream_service_batch on
117// the concrete type, detected by the consumer at compile time) for
118// arbitrary-size databases; the table then materializes only for consumers
119// that ask for it.
120// - completions: connect and gatt_disconnect land in on_connection_state,
121// discover_services in on_service_discovery_done, pair in
122// on_pairing_result, reads in on_read_result, notify_characteristic in
123// on_notify_state, characteristic writes (with and without response) and
124// descriptor writes in on_write_result.
125template<typename T>
126concept BLEGattConnectionContract = requires(T conn, GattClientListener *listener, const uint8_t *data) {
127 conn.set_listener(listener);
128 { conn.connect(uint64_t{}, uint8_t{}) } -> std::same_as<int>;
129 { conn.gatt_disconnect() } -> std::same_as<int>;
130 { conn.cancel_gatt_disconnect() } -> std::same_as<bool>;
131 { conn.discover_services() } -> std::same_as<int>;
132 { conn.read_characteristic(uint16_t{}) } -> std::same_as<int>;
133 { conn.write_characteristic(uint16_t{}, data, uint16_t{}, true) } -> std::same_as<int>;
134 { conn.read_descriptor(uint16_t{}) } -> std::same_as<int>;
135 { conn.write_descriptor(uint16_t{}, data, uint16_t{}) } -> std::same_as<int>;
136 { conn.notify_characteristic(uint16_t{}, true) } -> std::same_as<int>;
137 { conn.pair() } -> std::same_as<int>;
138 { conn.update_connection_params(uint16_t{}, uint16_t{}, uint16_t{}, uint16_t{}) } -> std::same_as<int>;
139 { conn.get_service_table() } -> std::same_as<GattServiceTable>;
140 { conn.release_services() } -> std::same_as<void>;
141 // Connection-type hint for backends that tune parameters by it; others
142 // carry an inline no-op.
143 { conn.set_connection_type(ConnectionType{}) } -> std::same_as<void>;
144};
145
146} // namespace esphome::ble_device_base
147
148#endif // USE_BLE_GATT_CLIENT
The event surface a backend delivers completions through - the one place with genuine runtime polymor...
virtual void on_notify_state(uint16_t handle, bool enabled, int error)
virtual void on_notify_data(uint16_t handle, const uint8_t *data, uint16_t len)
virtual void on_write_result(uint16_t handle, int error)
virtual void on_connection_state(bool connected, uint16_t mtu, int error)
virtual void on_read_result(uint16_t handle, const uint8_t *data, uint16_t len, int error)
const void size_t len
Definition hal.h:64
Borrowed view of the backend-owned service table.
const GattCharacteristic * characteristics
spi_device_handle_t handle