ESPHome 2026.1.0
Loading...
Searching...
No Matches
ble_text_sensor.cpp
Go to the documentation of this file.
1#include "ble_text_sensor.h"
2
6#include "esphome/core/log.h"
7
8#ifdef USE_ESP32
9
10namespace esphome::ble_client {
11
12static const char *const TAG = "ble_text_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_TEXT_SENSOR("", "BLE Text Sensor", this);
22 char service_buf[esp32_ble::UUID_STR_LEN];
23 char char_buf[esp32_ble::UUID_STR_LEN];
24 char descr_buf[esp32_ble::UUID_STR_LEN];
25 ESP_LOGCONFIG(TAG,
26 " MAC address : %s\n"
27 " Service UUID : %s\n"
28 " Characteristic UUID: %s\n"
29 " Descriptor UUID : %s\n"
30 " Notifications : %s",
31 this->parent()->address_str(), this->service_uuid_.to_str(service_buf),
32 this->char_uuid_.to_str(char_buf), this->descr_uuid_.to_str(descr_buf), YESNO(this->notify_));
33 LOG_UPDATE_INTERVAL(this);
34}
35
36void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
37 esp_ble_gattc_cb_param_t *param) {
38 switch (event) {
39 case ESP_GATTC_OPEN_EVT: {
40 if (param->open.status == ESP_GATT_OK) {
41 ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
42 break;
43 }
44 break;
45 }
46 case ESP_GATTC_CLOSE_EVT: {
47 this->status_set_warning();
48 this->publish_state("");
49 break;
50 }
51 case ESP_GATTC_SEARCH_CMPL_EVT: {
52 this->handle = 0;
53 auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
54 if (chr == nullptr) {
55 this->status_set_warning();
56 this->publish_state("");
57 char service_buf[esp32_ble::UUID_STR_LEN];
58 char char_buf[esp32_ble::UUID_STR_LEN];
59 ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_str(service_buf),
60 this->char_uuid_.to_str(char_buf));
61 break;
62 }
63 this->handle = chr->handle;
64 if (this->descr_uuid_.get_uuid().len > 0) {
65 auto *descr = chr->get_descriptor(this->descr_uuid_);
66 if (descr == nullptr) {
67 this->status_set_warning();
68 this->publish_state("");
69 char service_buf[esp32_ble::UUID_STR_LEN];
70 char char_buf[esp32_ble::UUID_STR_LEN];
71 char descr_buf[esp32_ble::UUID_STR_LEN];
72 ESP_LOGW(TAG, "No sensor descriptor found at service %s char %s descr %s",
73 this->service_uuid_.to_str(service_buf), this->char_uuid_.to_str(char_buf),
74 this->descr_uuid_.to_str(descr_buf));
75 break;
76 }
77 this->handle = descr->handle;
78 }
79 if (this->notify_) {
80 auto status = esp_ble_gattc_register_for_notify(this->parent()->get_gattc_if(),
81 this->parent()->get_remote_bda(), chr->handle);
82 if (status) {
83 ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
84 }
85 } else {
86 this->node_state = espbt::ClientState::ESTABLISHED;
87 // For non-notify characteristics, trigger an immediate read after service discovery
88 // to avoid peripherals disconnecting due to inactivity
89 this->update();
90 }
91 break;
92 }
93 case ESP_GATTC_READ_CHAR_EVT: {
94 if (param->read.handle == this->handle) {
95 if (param->read.status != ESP_GATT_OK) {
96 ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
97 break;
98 }
100 this->publish_state(reinterpret_cast<const char *>(param->read.value), param->read.value_len);
101 }
102 break;
103 }
104 case ESP_GATTC_NOTIFY_EVT: {
105 if (param->notify.handle != this->handle)
106 break;
107 ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
108 param->notify.handle, param->notify.value[0]);
109 this->publish_state(reinterpret_cast<const char *>(param->notify.value), param->notify.value_len);
110 break;
111 }
112 case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
113 if (param->reg_for_notify.status == ESP_GATT_OK && param->reg_for_notify.handle == this->handle)
114 this->node_state = espbt::ClientState::ESTABLISHED;
115 break;
116 }
117 default:
118 break;
119 }
120}
121
123 if (this->node_state != espbt::ClientState::ESTABLISHED) {
124 ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
125 return;
126 }
127 if (this->handle == 0) {
128 ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", this->get_name().c_str());
129 return;
130 }
131
132 auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle,
133 ESP_GATT_AUTH_REQ_NONE);
134 if (status) {
135 this->status_set_warning();
136 this->publish_state("");
137 ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", this->get_name().c_str(), status);
138 }
139}
140
141} // namespace esphome::ble_client
142#endif
uint8_t status
Definition bl0942.h:8
void status_set_warning(const char *message=nullptr)
void disable_loop()
Disable this component's loop.
void status_clear_warning()
const StringRef & get_name() const
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) override
const char * to_str(std::span< char, UUID_STR_LEN > output) const
Definition ble_uuid.cpp:146
esp_bt_uuid_t get_uuid() const
Definition ble_uuid.cpp:145
BLECharacteristic * get_characteristic(espbt::ESPBTUUID service, espbt::ESPBTUUID chr)
void publish_state(const std::string &state)