mirror of
https://github.com/esphome/esphome.git
synced 2025-09-11 15:52:20 +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:
@@ -19,11 +19,6 @@ namespace esp32_ble_server {
|
||||
|
||||
static const char *const TAG = "esp32_ble_server";
|
||||
|
||||
static const uint16_t DEVICE_INFORMATION_SERVICE_UUID = 0x180A;
|
||||
static const uint16_t MODEL_UUID = 0x2A24;
|
||||
static const uint16_t VERSION_UUID = 0x2A26;
|
||||
static const uint16_t MANUFACTURER_UUID = 0x2A29;
|
||||
|
||||
void BLEServer::setup() {
|
||||
if (this->parent_->is_failed()) {
|
||||
this->mark_failed();
|
||||
@@ -38,9 +33,27 @@ void BLEServer::loop() {
|
||||
return;
|
||||
}
|
||||
switch (this->state_) {
|
||||
case RUNNING:
|
||||
return;
|
||||
|
||||
case RUNNING: {
|
||||
// Start all services that are pending to start
|
||||
if (!this->services_to_start_.empty()) {
|
||||
uint16_t index_to_remove = 0;
|
||||
// Iterate over the services to start
|
||||
for (unsigned i = 0; i < this->services_to_start_.size(); i++) {
|
||||
BLEService *service = this->services_to_start_[i];
|
||||
if (service->is_created()) {
|
||||
service->start(); // Needs to be called once per characteristic in the service
|
||||
} else {
|
||||
index_to_remove = i + 1;
|
||||
}
|
||||
}
|
||||
// Remove the services that have been started
|
||||
if (index_to_remove > 0) {
|
||||
this->services_to_start_.erase(this->services_to_start_.begin(),
|
||||
this->services_to_start_.begin() + index_to_remove - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INIT: {
|
||||
esp_err_t err = esp_ble_gatts_app_register(0);
|
||||
if (err != ESP_OK) {
|
||||
@@ -53,29 +66,26 @@ void BLEServer::loop() {
|
||||
}
|
||||
case REGISTERING: {
|
||||
if (this->registered_) {
|
||||
// Create the device information service first so
|
||||
// it is at the top of the GATT table
|
||||
this->device_information_service_->do_create(this);
|
||||
// Create all services previously created
|
||||
for (auto &pair : this->services_) {
|
||||
if (pair.second == this->device_information_service_) {
|
||||
continue;
|
||||
}
|
||||
pair.second->do_create(this);
|
||||
}
|
||||
if (this->device_information_service_ == nullptr) {
|
||||
this->create_service(ESPBTUUID::from_uint16(DEVICE_INFORMATION_SERVICE_UUID));
|
||||
this->device_information_service_ =
|
||||
this->get_service(ESPBTUUID::from_uint16(DEVICE_INFORMATION_SERVICE_UUID));
|
||||
this->create_device_characteristics_();
|
||||
}
|
||||
this->state_ = STARTING_SERVICE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STARTING_SERVICE: {
|
||||
if (!this->device_information_service_->is_created()) {
|
||||
break;
|
||||
}
|
||||
if (this->device_information_service_->is_running()) {
|
||||
this->state_ = RUNNING;
|
||||
this->restart_advertising_();
|
||||
ESP_LOGD(TAG, "BLE server setup successfully");
|
||||
} else if (!this->device_information_service_->is_starting()) {
|
||||
} else if (this->device_information_service_->is_created()) {
|
||||
this->device_information_service_->start();
|
||||
}
|
||||
break;
|
||||
@@ -93,81 +103,66 @@ void BLEServer::restart_advertising_() {
|
||||
}
|
||||
}
|
||||
|
||||
bool BLEServer::create_device_characteristics_() {
|
||||
if (this->model_.has_value()) {
|
||||
BLECharacteristic *model =
|
||||
this->device_information_service_->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ);
|
||||
model->set_value(this->model_.value());
|
||||
} else {
|
||||
BLECharacteristic *model =
|
||||
this->device_information_service_->create_characteristic(MODEL_UUID, BLECharacteristic::PROPERTY_READ);
|
||||
model->set_value(ESPHOME_BOARD);
|
||||
}
|
||||
|
||||
BLECharacteristic *version =
|
||||
this->device_information_service_->create_characteristic(VERSION_UUID, BLECharacteristic::PROPERTY_READ);
|
||||
version->set_value("ESPHome " ESPHOME_VERSION);
|
||||
|
||||
BLECharacteristic *manufacturer =
|
||||
this->device_information_service_->create_characteristic(MANUFACTURER_UUID, BLECharacteristic::PROPERTY_READ);
|
||||
manufacturer->set_value(this->manufacturer_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles, uint8_t inst_id) {
|
||||
BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t num_handles) {
|
||||
ESP_LOGV(TAG, "Creating BLE service - %s", uuid.to_string().c_str());
|
||||
// If the service already exists, do nothing
|
||||
BLEService *service = this->get_service(uuid);
|
||||
if (service != nullptr) {
|
||||
ESP_LOGW(TAG, "BLE service %s already exists", uuid.to_string().c_str());
|
||||
return;
|
||||
// Calculate the inst_id for the service
|
||||
uint8_t inst_id = 0;
|
||||
for (; inst_id < 0xFF; inst_id++) {
|
||||
if (this->get_service(uuid, inst_id) == nullptr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
service = new BLEService(uuid, num_handles, inst_id, advertise); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
this->services_.emplace(uuid.to_string(), service);
|
||||
service->do_create(this);
|
||||
if (inst_id == 0xFF) {
|
||||
ESP_LOGW(TAG, "Could not create BLE service %s, too many instances", uuid.to_string().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
BLEService *service = // NOLINT(cppcoreguidelines-owning-memory)
|
||||
new BLEService(uuid, num_handles, inst_id, advertise);
|
||||
this->services_.emplace(BLEServer::get_service_key(uuid, inst_id), service);
|
||||
if (this->parent_->is_active() && this->registered_) {
|
||||
service->do_create(this);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
void BLEServer::remove_service(ESPBTUUID uuid) {
|
||||
ESP_LOGV(TAG, "Removing BLE service - %s", uuid.to_string().c_str());
|
||||
BLEService *service = this->get_service(uuid);
|
||||
void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
ESP_LOGV(TAG, "Removing BLE service - %s %d", uuid.to_string().c_str(), inst_id);
|
||||
BLEService *service = this->get_service(uuid, inst_id);
|
||||
if (service == nullptr) {
|
||||
ESP_LOGW(TAG, "BLE service %s not found", uuid.to_string().c_str());
|
||||
ESP_LOGW(TAG, "BLE service %s %d does not exist", uuid.to_string().c_str(), inst_id);
|
||||
return;
|
||||
}
|
||||
service->do_delete();
|
||||
delete service; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
this->services_.erase(uuid.to_string());
|
||||
this->services_.erase(BLEServer::get_service_key(uuid, inst_id));
|
||||
}
|
||||
|
||||
BLEService *BLEServer::get_service(ESPBTUUID uuid) {
|
||||
BLEService *BLEServer::get_service(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
BLEService *service = nullptr;
|
||||
if (this->services_.count(uuid.to_string()) > 0) {
|
||||
service = this->services_.at(uuid.to_string());
|
||||
if (this->services_.count(BLEServer::get_service_key(uuid, inst_id)) > 0) {
|
||||
service = this->services_.at(BLEServer::get_service_key(uuid, inst_id));
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
std::string BLEServer::get_service_key(ESPBTUUID uuid, uint8_t inst_id) {
|
||||
return uuid.to_string() + std::to_string(inst_id);
|
||||
}
|
||||
|
||||
void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t *param) {
|
||||
switch (event) {
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
ESP_LOGD(TAG, "BLE Client connected");
|
||||
this->add_client_(param->connect.conn_id, (void *) this);
|
||||
this->connected_clients_++;
|
||||
for (auto *component : this->service_components_) {
|
||||
component->on_client_connect();
|
||||
}
|
||||
this->add_client_(param->connect.conn_id);
|
||||
this->emit_(BLEServerEvt::EmptyEvt::ON_CONNECT, param->connect.conn_id);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
ESP_LOGD(TAG, "BLE Client disconnected");
|
||||
if (this->remove_client_(param->disconnect.conn_id))
|
||||
this->connected_clients_--;
|
||||
this->remove_client_(param->disconnect.conn_id);
|
||||
this->parent_->advertising_start();
|
||||
for (auto *component : this->service_components_) {
|
||||
component->on_client_disconnect();
|
||||
}
|
||||
this->emit_(BLEServerEvt::EmptyEvt::ON_DISCONNECT, param->disconnect.conn_id);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_REG_EVT: {
|
||||
|
Reference in New Issue
Block a user