1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-27 07:32:22 +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:
Rodrigo Martín
2025-01-28 12:00:28 +01:00
committed by GitHub
parent dd18a219db
commit f7f8bf4da4
26 changed files with 1221 additions and 342 deletions

View File

@@ -1,6 +1,6 @@
from esphome import automation
import esphome.codegen as cg
from esphome.components import binary_sensor, esp32_ble_server, output
from esphome.components import binary_sensor, output
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID
@@ -24,9 +24,7 @@ Error = improv_ns.enum("Error")
State = improv_ns.enum("State")
esp32_improv_ns = cg.esphome_ns.namespace("esp32_improv")
ESP32ImprovComponent = esp32_improv_ns.class_(
"ESP32ImprovComponent", cg.Component, esp32_ble_server.BLEServiceComponent
)
ESP32ImprovComponent = esp32_improv_ns.class_("ESP32ImprovComponent", cg.Component)
ESP32ImprovProvisionedTrigger = esp32_improv_ns.class_(
"ESP32ImprovProvisionedTrigger", automation.Trigger.template()
)
@@ -47,7 +45,6 @@ ESP32ImprovStoppedTrigger = esp32_improv_ns.class_(
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(ESP32ImprovComponent),
cv.GenerateID(CONF_BLE_SERVER_ID): cv.use_id(esp32_ble_server.BLEServer),
cv.Required(CONF_AUTHORIZER): cv.Any(
cv.none, cv.use_id(binary_sensor.BinarySensor)
),
@@ -100,9 +97,6 @@ async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
ble_server = await cg.get_variable(config[CONF_BLE_SERVER_ID])
cg.add(ble_server.register_service_component(var))
cg.add_define("USE_IMPROV")
cg.add_library("improv/Improv", "1.2.4")

View File

@@ -4,12 +4,15 @@
#include "esphome/components/esp32_ble_server/ble_2902.h"
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/components/bytebuffer/bytebuffer.h"
#ifdef USE_ESP32
namespace esphome {
namespace esp32_improv {
using namespace bytebuffer;
static const char *const TAG = "esp32_improv.component";
static const char *const ESPHOME_MY_LINK = "https://my.home-assistant.io/redirect/config_flow_start?domain=esphome";
@@ -26,6 +29,8 @@ void ESP32ImprovComponent::setup() {
});
}
#endif
global_ble_server->on(BLEServerEvt::EmptyEvt::ON_DISCONNECT,
[this](uint16_t conn_id) { this->set_error_(improv::ERROR_NONE); });
}
void ESP32ImprovComponent::setup_characteristics() {
@@ -40,11 +45,12 @@ void ESP32ImprovComponent::setup_characteristics() {
this->error_->add_descriptor(error_descriptor);
this->rpc_ = this->service_->create_characteristic(improv::RPC_COMMAND_UUID, BLECharacteristic::PROPERTY_WRITE);
this->rpc_->on_write([this](const std::vector<uint8_t> &data) {
if (!data.empty()) {
this->incoming_data_.insert(this->incoming_data_.end(), data.begin(), data.end());
}
});
this->rpc_->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::on(
BLECharacteristicEvt::VectorEvt::ON_WRITE, [this](const std::vector<uint8_t> &data, uint16_t id) {
if (!data.empty()) {
this->incoming_data_.insert(this->incoming_data_.end(), data.begin(), data.end());
}
});
BLEDescriptor *rpc_descriptor = new BLE2902();
this->rpc_->add_descriptor(rpc_descriptor);
@@ -62,7 +68,7 @@ void ESP32ImprovComponent::setup_characteristics() {
if (this->status_indicator_ != nullptr)
capabilities |= improv::CAPABILITY_IDENTIFY;
#endif
this->capabilities_->set_value(capabilities);
this->capabilities_->set_value(ByteBuffer::wrap(capabilities));
this->setup_complete_ = true;
}
@@ -80,8 +86,7 @@ void ESP32ImprovComponent::loop() {
if (this->service_ == nullptr) {
// Setup the service
ESP_LOGD(TAG, "Creating Improv service");
global_ble_server->create_service(ESPBTUUID::from_raw(improv::SERVICE_UUID), true);
this->service_ = global_ble_server->get_service(ESPBTUUID::from_raw(improv::SERVICE_UUID));
this->service_ = global_ble_server->create_service(ESPBTUUID::from_raw(improv::SERVICE_UUID), true);
this->setup_characteristics();
}
@@ -93,15 +98,15 @@ void ESP32ImprovComponent::loop() {
case improv::STATE_STOPPED:
this->set_status_indicator_state_(false);
if (this->service_->is_created() && this->should_start_ && this->setup_complete_) {
if (this->service_->is_running()) {
if (this->should_start_ && this->setup_complete_) {
if (this->service_->is_created()) {
this->service_->start();
} else if (this->service_->is_running()) {
esp32_ble::global_ble->advertising_start();
this->set_state_(improv::STATE_AWAITING_AUTHORIZATION);
this->set_error_(improv::ERROR_NONE);
ESP_LOGD(TAG, "Service started!");
} else {
this->service_->start();
}
}
break;
@@ -199,8 +204,7 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
ESP_LOGV(TAG, "Setting state: %d", state);
this->state_ = state;
if (this->status_->get_value().empty() || this->status_->get_value()[0] != state) {
uint8_t data[1]{state};
this->status_->set_value(data, 1);
this->status_->set_value(ByteBuffer::wrap(static_cast<uint8_t>(state)));
if (state != improv::STATE_STOPPED)
this->status_->notify();
}
@@ -232,15 +236,14 @@ void ESP32ImprovComponent::set_error_(improv::Error error) {
ESP_LOGE(TAG, "Error: %d", error);
}
if (this->error_->get_value().empty() || this->error_->get_value()[0] != error) {
uint8_t data[1]{error};
this->error_->set_value(data, 1);
this->error_->set_value(ByteBuffer::wrap(static_cast<uint8_t>(error)));
if (this->state_ != improv::STATE_STOPPED)
this->error_->notify();
}
}
void ESP32ImprovComponent::send_response_(std::vector<uint8_t> &response) {
this->rpc_response_->set_value(response);
this->rpc_response_->set_value(ByteBuffer::wrap(response));
if (this->state_ != improv::STATE_STOPPED)
this->rpc_response_->notify();
}
@@ -339,8 +342,6 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() {
wifi::global_wifi_component->clear_sta();
}
void ESP32ImprovComponent::on_client_disconnect() { this->set_error_(improv::ERROR_NONE); };
ESP32ImprovComponent *global_improv_component = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace esp32_improv

View File

@@ -32,18 +32,17 @@ namespace esp32_improv {
using namespace esp32_ble_server;
class ESP32ImprovComponent : public Component, public BLEServiceComponent {
class ESP32ImprovComponent : public Component {
public:
ESP32ImprovComponent();
void dump_config() override;
void loop() override;
void setup() override;
void setup_characteristics();
void on_client_disconnect() override;
float get_setup_priority() const override;
void start() override;
void stop() override;
void start();
void stop();
bool is_active() const { return this->state_ != improv::STATE_STOPPED; }
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK