ESPHome 2025.12.4
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
14static const std::string EMPTY = "";
15
17 // Parent BLEClientNode has a loop() method, but this component uses
18 // polling via update() and BLE callbacks so loop isn't needed
19 this->disable_loop();
20}
21
23 LOG_TEXT_SENSOR("", "BLE Text Sensor", this);
24 ESP_LOGCONFIG(TAG,
25 " MAC address : %s\n"
26 " Service UUID : %s\n"
27 " Characteristic UUID: %s\n"
28 " Descriptor UUID : %s\n"
29 " Notifications : %s",
30 this->parent()->address_str(), this->service_uuid_.to_string().c_str(),
31 this->char_uuid_.to_string().c_str(), this->descr_uuid_.to_string().c_str(), YESNO(this->notify_));
32 LOG_UPDATE_INTERVAL(this);
33}
34
35void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
36 esp_ble_gattc_cb_param_t *param) {
37 switch (event) {
38 case ESP_GATTC_OPEN_EVT: {
39 if (param->open.status == ESP_GATT_OK) {
40 ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
41 break;
42 }
43 break;
44 }
45 case ESP_GATTC_CLOSE_EVT: {
46 this->status_set_warning();
47 this->publish_state(EMPTY);
48 break;
49 }
50 case ESP_GATTC_SEARCH_CMPL_EVT: {
51 this->handle = 0;
52 auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->char_uuid_);
53 if (chr == nullptr) {
54 this->status_set_warning();
55 this->publish_state(EMPTY);
56 ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(),
57 this->char_uuid_.to_string().c_str());
58 break;
59 }
60 this->handle = chr->handle;
61 if (this->descr_uuid_.get_uuid().len > 0) {
62 auto *descr = chr->get_descriptor(this->descr_uuid_);
63 if (descr == nullptr) {
64 this->status_set_warning();
65 this->publish_state(EMPTY);
66 ESP_LOGW(TAG, "No sensor descriptor found at service %s char %s descr %s",
67 this->service_uuid_.to_string().c_str(), this->char_uuid_.to_string().c_str(),
68 this->descr_uuid_.to_string().c_str());
69 break;
70 }
71 this->handle = descr->handle;
72 }
73 if (this->notify_) {
74 auto status = esp_ble_gattc_register_for_notify(this->parent()->get_gattc_if(),
75 this->parent()->get_remote_bda(), chr->handle);
76 if (status) {
77 ESP_LOGW(TAG, "esp_ble_gattc_register_for_notify failed, status=%d", status);
78 }
79 } else {
80 this->node_state = espbt::ClientState::ESTABLISHED;
81 // For non-notify characteristics, trigger an immediate read after service discovery
82 // to avoid peripherals disconnecting due to inactivity
83 this->update();
84 }
85 break;
86 }
87 case ESP_GATTC_READ_CHAR_EVT: {
88 if (param->read.handle == this->handle) {
89 if (param->read.status != ESP_GATT_OK) {
90 ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status);
91 break;
92 }
94 this->publish_state(this->parse_data(param->read.value, param->read.value_len));
95 }
96 break;
97 }
98 case ESP_GATTC_NOTIFY_EVT: {
99 if (param->notify.handle != this->handle)
100 break;
101 ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
102 param->notify.handle, param->notify.value[0]);
103 this->publish_state(this->parse_data(param->notify.value, param->notify.value_len));
104 break;
105 }
106 case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
107 if (param->reg_for_notify.status == ESP_GATT_OK && param->reg_for_notify.handle == this->handle)
108 this->node_state = espbt::ClientState::ESTABLISHED;
109 break;
110 }
111 default:
112 break;
113 }
114}
115
116std::string BLETextSensor::parse_data(uint8_t *value, uint16_t value_len) {
117 std::string text(value, value + value_len);
118 return text;
119}
120
122 if (this->node_state != espbt::ClientState::ESTABLISHED) {
123 ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
124 return;
125 }
126 if (this->handle == 0) {
127 ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", this->get_name().c_str());
128 return;
129 }
130
131 auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle,
132 ESP_GATT_AUTH_REQ_NONE);
133 if (status) {
134 this->status_set_warning();
135 this->publish_state(EMPTY);
136 ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", this->get_name().c_str(), status);
137 }
138}
139
140} // namespace esphome::ble_client
141#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
std::string parse_data(uint8_t *value, uint16_t value_len)
std::string to_string() 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)