mirror of
https://github.com/esphome/esphome.git
synced 2025-10-04 19:03:47 +01:00
[esp32_ble_server] Create custom services, characteristics and descriptors (#7009)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
This commit is contained in:
@@ -32,70 +32,36 @@ BLECharacteristic::BLECharacteristic(const ESPBTUUID uuid, uint32_t properties)
|
||||
this->set_write_no_response_property((properties & PROPERTY_WRITE_NR) != 0);
|
||||
}
|
||||
|
||||
void BLECharacteristic::set_value(std::vector<uint8_t> value) {
|
||||
void BLECharacteristic::set_value(ByteBuffer buffer) { this->set_value(buffer.get_data()); }
|
||||
|
||||
void BLECharacteristic::set_value(const std::vector<uint8_t> &buffer) {
|
||||
xSemaphoreTake(this->set_value_lock_, 0L);
|
||||
this->value_ = std::move(value);
|
||||
this->value_ = buffer;
|
||||
xSemaphoreGive(this->set_value_lock_);
|
||||
}
|
||||
void BLECharacteristic::set_value(const std::string &value) {
|
||||
this->set_value(std::vector<uint8_t>(value.begin(), value.end()));
|
||||
}
|
||||
void BLECharacteristic::set_value(const uint8_t *data, size_t length) {
|
||||
this->set_value(std::vector<uint8_t>(data, data + length));
|
||||
}
|
||||
void BLECharacteristic::set_value(uint8_t &data) {
|
||||
uint8_t temp[1];
|
||||
temp[0] = data;
|
||||
this->set_value(temp, 1);
|
||||
}
|
||||
void BLECharacteristic::set_value(uint16_t &data) {
|
||||
uint8_t temp[2];
|
||||
temp[0] = data;
|
||||
temp[1] = data >> 8;
|
||||
this->set_value(temp, 2);
|
||||
}
|
||||
void BLECharacteristic::set_value(uint32_t &data) {
|
||||
uint8_t temp[4];
|
||||
temp[0] = data;
|
||||
temp[1] = data >> 8;
|
||||
temp[2] = data >> 16;
|
||||
temp[3] = data >> 24;
|
||||
this->set_value(temp, 4);
|
||||
}
|
||||
void BLECharacteristic::set_value(int &data) {
|
||||
uint8_t temp[4];
|
||||
temp[0] = data;
|
||||
temp[1] = data >> 8;
|
||||
temp[2] = data >> 16;
|
||||
temp[3] = data >> 24;
|
||||
this->set_value(temp, 4);
|
||||
}
|
||||
void BLECharacteristic::set_value(float &data) {
|
||||
float temp = data;
|
||||
this->set_value((uint8_t *) &temp, 4);
|
||||
}
|
||||
void BLECharacteristic::set_value(double &data) {
|
||||
double temp = data;
|
||||
this->set_value((uint8_t *) &temp, 8);
|
||||
}
|
||||
void BLECharacteristic::set_value(bool &data) {
|
||||
uint8_t temp[1];
|
||||
temp[0] = data;
|
||||
this->set_value(temp, 1);
|
||||
void BLECharacteristic::set_value(const std::string &buffer) {
|
||||
this->set_value(std::vector<uint8_t>(buffer.begin(), buffer.end()));
|
||||
}
|
||||
|
||||
void BLECharacteristic::notify(bool notification) {
|
||||
if (!notification) {
|
||||
ESP_LOGW(TAG, "notification=false is not yet supported");
|
||||
// TODO: Handle when notification=false
|
||||
}
|
||||
if (this->service_->get_server()->get_connected_client_count() == 0)
|
||||
void BLECharacteristic::notify() {
|
||||
if (this->service_ == nullptr || this->service_->get_server() == nullptr ||
|
||||
this->service_->get_server()->get_connected_client_count() == 0)
|
||||
return;
|
||||
|
||||
for (auto &client : this->service_->get_server()->get_clients()) {
|
||||
size_t length = this->value_.size();
|
||||
esp_err_t err = esp_ble_gatts_send_indicate(this->service_->get_server()->get_gatts_if(), client.first,
|
||||
this->handle_, length, this->value_.data(), false);
|
||||
// If the client is not in the list of clients to notify, skip it
|
||||
if (this->clients_to_notify_.count(client) == 0)
|
||||
continue;
|
||||
// If the client is in the list of clients to notify, check if it requires an ack (i.e. INDICATE)
|
||||
bool require_ack = this->clients_to_notify_[client];
|
||||
// TODO: Remove this block when INDICATE acknowledgment is supported
|
||||
if (require_ack) {
|
||||
ESP_LOGW(TAG, "INDICATE acknowledgment is not yet supported (i.e. it works as a NOTIFY)");
|
||||
require_ack = false;
|
||||
}
|
||||
esp_err_t err = esp_ble_gatts_send_indicate(this->service_->get_server()->get_gatts_if(), client, this->handle_,
|
||||
length, this->value_.data(), require_ack);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gatts_send_indicate failed %d", err);
|
||||
return;
|
||||
@@ -103,7 +69,24 @@ void BLECharacteristic::notify(bool notification) {
|
||||
}
|
||||
}
|
||||
|
||||
void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) { this->descriptors_.push_back(descriptor); }
|
||||
void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) {
|
||||
// If the descriptor is the CCCD descriptor, listen to its write event to know if the client wants to be notified
|
||||
if (descriptor->get_uuid() == ESPBTUUID::from_uint16(ESP_GATT_UUID_CHAR_CLIENT_CONFIG)) {
|
||||
descriptor->on(BLEDescriptorEvt::VectorEvt::ON_WRITE, [this](const std::vector<uint8_t> &value, uint16_t conn_id) {
|
||||
if (value.size() != 2)
|
||||
return;
|
||||
uint16_t cccd = encode_uint16(value[1], value[0]);
|
||||
bool notify = (cccd & 1) != 0;
|
||||
bool indicate = (cccd & 2) != 0;
|
||||
if (notify || indicate) {
|
||||
this->clients_to_notify_[conn_id] = indicate;
|
||||
} else {
|
||||
this->clients_to_notify_.erase(conn_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
this->descriptors_.push_back(descriptor);
|
||||
}
|
||||
|
||||
void BLECharacteristic::remove_descriptor(BLEDescriptor *descriptor) {
|
||||
this->descriptors_.erase(std::remove(this->descriptors_.begin(), this->descriptors_.end(), descriptor),
|
||||
@@ -223,6 +206,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
||||
if (!param->read.need_rsp)
|
||||
break; // For some reason you can request a read but not want a response
|
||||
|
||||
this->EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t>::emit_(BLECharacteristicEvt::EmptyEvt::ON_READ,
|
||||
param->read.conn_id);
|
||||
|
||||
uint16_t max_offset = 22;
|
||||
|
||||
esp_gatt_rsp_t response;
|
||||
@@ -262,13 +248,13 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
||||
}
|
||||
case ESP_GATTS_WRITE_EVT: {
|
||||
if (this->handle_ != param->write.handle)
|
||||
return;
|
||||
break;
|
||||
|
||||
if (param->write.is_prep) {
|
||||
this->value_.insert(this->value_.end(), param->write.value, param->write.value + param->write.len);
|
||||
this->write_event_ = true;
|
||||
} else {
|
||||
this->set_value(param->write.value, param->write.len);
|
||||
this->set_value(ByteBuffer::wrap(param->write.value, param->write.len));
|
||||
}
|
||||
|
||||
if (param->write.need_rsp) {
|
||||
@@ -289,7 +275,8 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
||||
}
|
||||
|
||||
if (!param->write.is_prep) {
|
||||
this->on_write_(this->value_);
|
||||
this->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::emit_(
|
||||
BLECharacteristicEvt::VectorEvt::ON_WRITE, this->value_, param->write.conn_id);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -300,7 +287,8 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
|
||||
break;
|
||||
this->write_event_ = false;
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
||||
this->on_write_(this->value_);
|
||||
this->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::emit_(
|
||||
BLECharacteristicEvt::VectorEvt::ON_WRITE, this->value_, param->exec_write.conn_id);
|
||||
}
|
||||
esp_err_t err =
|
||||
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr);
|
||||
|
Reference in New Issue
Block a user