ESPHome 2025.7.4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
ble_sensor.cpp
Go to the documentation of this file.
1#include "ble_sensor.h"
4#include "esphome/core/log.h"
6
7#ifdef USE_ESP32
8
9namespace esphome {
10namespace ble_client {
11
12static const char *const TAG = "ble_sensor";
13
15 // Parent BLEClientNode has a loop() method, but this component uses
16 // polling via update() and BLE callbacks so loop isn't needed
17 this->disable_loop();
18}
19
21 LOG_SENSOR("", "BLE Sensor", this);
22 ESP_LOGCONFIG(TAG,
23 " MAC address : %s\n"
24 " Service UUID : %s\n"
25 " Characteristic UUID: %s\n"
26 " Descriptor UUID : %s\n"
27 " Notifications : %s",
28 this->parent()->address_str().c_str(), this->service_uuid_.to_string().c_str(),
29 this->char_uuid_.to_string().c_str(), this->descr_uuid_.to_string().c_str(), YESNO(this->notify_));
30 LOG_UPDATE_INTERVAL(this);
31}
32
33void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
34 esp_ble_gattc_cb_param_t *param) {
35 switch (event) {
36 case ESP_GATTC_OPEN_EVT: {
37 if (param->open.status == ESP_GATT_OK) {
38 ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
39 break;
40 }
41 break;
42 }
43 case ESP_GATTC_CLOSE_EVT: {
44 ESP_LOGW(TAG, "[%s] Disconnected!", this->get_name().c_str());
45 this->status_set_warning();
46 this->publish_state(NAN);
47 break;
48 }
49 case ESP_GATTC_SEARCH_CMPL_EVT: {
50 this->handle = 0;
51 auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
52 if (chr == nullptr) {
53 this->status_set_warning();
54 this->publish_state(NAN);
55 ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(),
56 this->char_uuid_.to_string().c_str());
57 break;
58 }
59 this->handle = chr->handle;
60 if (this->descr_uuid_.get_uuid().len > 0) {
61 auto *descr = chr->get_descriptor(this->descr_uuid_);
62 if (descr == nullptr) {
63 this->status_set_warning();
64 this->publish_state(NAN);
65 ESP_LOGW(TAG, "No sensor descriptor found at service %s char %s descr %s",
66 this->service_uuid_.to_string().c_str(), this->char_uuid_.to_string().c_str(),
67 this->descr_uuid_.to_string().c_str());
68 break;
69 }
70 this->handle = descr->handle;
71 }
72 if (this->notify_) {
73 auto status = esp_ble_gattc_register_for_notify(this->parent()->get_gattc_if(),
74 this->parent()->get_remote_bda(), chr->handle);
75 if (status) {
76 ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
77 }
78 } else {
79 this->node_state = espbt::ClientState::ESTABLISHED;
80 }
81 break;
82 }
83 case ESP_GATTC_READ_CHAR_EVT: {
84 if (param->read.status != ESP_GATT_OK) {
85 ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
86 break;
87 }
88 if (param->read.handle == this->handle) {
90 this->publish_state(this->parse_data_(param->read.value, param->read.value_len));
91 }
92 break;
93 }
94 case ESP_GATTC_NOTIFY_EVT: {
95 ESP_LOGD(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
96 param->notify.handle, param->notify.value[0]);
97 if (param->notify.handle != this->handle)
98 break;
99 this->publish_state(this->parse_data_(param->notify.value, param->notify.value_len));
100 break;
101 }
102 case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
103 if (param->reg_for_notify.handle == this->handle) {
104 if (param->reg_for_notify.status != ESP_GATT_OK) {
105 ESP_LOGW(TAG, "Error registering for notifications at handle %d, status=%d", param->reg_for_notify.handle,
106 param->reg_for_notify.status);
107 break;
108 }
109 this->node_state = espbt::ClientState::ESTABLISHED;
110 ESP_LOGD(TAG, "Register for notify on %s complete", this->char_uuid_.to_string().c_str());
111 }
112 break;
113 }
114 default:
115 break;
116 }
117}
118
119float BLESensor::parse_data_(uint8_t *value, uint16_t value_len) {
120 if (this->data_to_value_func_.has_value()) {
121 std::vector<uint8_t> data(value, value + value_len);
122 return (*this->data_to_value_func_)(data);
123 } else {
124 return value[0];
125 }
126}
127
129 if (this->node_state != espbt::ClientState::ESTABLISHED) {
130 ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
131 return;
132 }
133 if (this->handle == 0) {
134 ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", this->get_name().c_str());
135 return;
136 }
137
138 auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle,
139 ESP_GATT_AUTH_REQ_NONE);
140 if (status) {
141 this->status_set_warning();
142 this->publish_state(NAN);
143 ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", this->get_name().c_str(), status);
144 }
145}
146
147} // namespace ble_client
148} // namespace esphome
149#endif
uint8_t status
Definition bl0942.h:8
void disable_loop()
Disable this component's loop.
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
const StringRef & get_name() const
espbt::ESPBTUUID service_uuid_
Definition ble_sensor.h:44
optional< data_to_value_t > data_to_value_func_
Definition ble_sensor.h:42
float parse_data_(uint8_t *value, uint16_t value_len)
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override
espbt::ESPBTUUID descr_uuid_
Definition ble_sensor.h:46
espbt::ESPBTUUID char_uuid_
Definition ble_sensor.h:45
std::string to_string() const
Definition ble_uuid.cpp:171
esp_bt_uuid_t get_uuid() const
Definition ble_uuid.cpp:170
BLECharacteristic * get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr)
bool has_value() const
Definition optional.h:92
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:45
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7