diff --git a/esphome/components/esp32_ble/__init__.py b/esphome/components/esp32_ble/__init__.py index 75cf9d707d..08e30c9247 100644 --- a/esphome/components/esp32_ble/__init__.py +++ b/esphome/components/esp32_ble/__init__.py @@ -2,8 +2,10 @@ from esphome import automation import esphome.codegen as cg from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant import esphome.config_validation as cv -from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID +from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ESPHOME, CONF_ID, CONF_NAME from esphome.core import CORE +from esphome.core.config import CONF_NAME_ADD_MAC_SUFFIX +import esphome.final_validate as fv DEPENDENCIES = ["esp32"] CODEOWNERS = ["@jesserockz", "@Rapsssito"] @@ -50,6 +52,7 @@ TX_POWER_LEVELS = { CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32BLE), + cv.Optional(CONF_NAME): cv.All(cv.string, cv.Length(max=20)), cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum( IO_CAPABILITY, lower=True ), @@ -67,7 +70,22 @@ def validate_variant(_): raise cv.Invalid(f"{variant} does not support Bluetooth") -FINAL_VALIDATE_SCHEMA = validate_variant +def final_validation(config): + validate_variant(config) + if (name := config.get(CONF_NAME)) is not None: + full_config = fv.full_config.get() + max_length = 20 + if full_config[CONF_ESPHOME][CONF_NAME_ADD_MAC_SUFFIX]: + max_length -= 7 # "-AABBCC" is appended when add mac suffix option is used + if len(name) > max_length: + raise cv.Invalid( + f"Name '{name}' is too long, maximum length is {max_length} characters" + ) + + return config + + +FINAL_VALIDATE_SCHEMA = final_validation async def to_code(config): @@ -75,6 +93,8 @@ async def to_code(config): cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY])) cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME])) + if (name := config.get(CONF_NAME)) is not None: + cg.add(var.set_name(name)) await cg.register_component(var, config) if CORE.using_esp_idf: diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 5d08b6e973..d7dcf93f86 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -188,12 +188,20 @@ bool ESP32BLE::ble_setup_() { } } - std::string name = App.get_name(); - if (name.length() > 20) { + std::string name; + if (this->name_.has_value()) { + name = this->name_.value(); if (App.is_name_add_mac_suffix_enabled()) { - name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address - } else { - name = name.substr(0, 20); + name += "-" + get_mac_address().substr(6); + } + } else { + name = App.get_name(); + if (name.length() > 20) { + if (App.is_name_add_mac_suffix_enabled()) { + name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address + } else { + name = name.substr(0, 20); + } } } diff --git a/esphome/components/esp32_ble/ble.h b/esphome/components/esp32_ble/ble.h index 7c55583852..ed7575f128 100644 --- a/esphome/components/esp32_ble/ble.h +++ b/esphome/components/esp32_ble/ble.h @@ -90,6 +90,7 @@ class ESP32BLE : public Component { void loop() override; void dump_config() override; float get_setup_priority() const override; + void set_name(const std::string &name) { this->name_ = name; } void advertising_start(); void advertising_set_service_data(const std::vector &data); @@ -131,6 +132,7 @@ class ESP32BLE : public Component { esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; uint32_t advertising_cycle_time_; bool enable_on_boot_; + optional name_; }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/components/esp32_ble/ble_advertising.cpp b/esphome/components/esp32_ble/ble_advertising.cpp index 1d340c76d9..92b7c60368 100644 --- a/esphome/components/esp32_ble/ble_advertising.cpp +++ b/esphome/components/esp32_ble/ble_advertising.cpp @@ -83,7 +83,7 @@ esp_err_t BLEAdvertising::services_advertisement_() { esp_err_t err; this->advertising_data_.set_scan_rsp = false; - this->advertising_data_.include_name = !this->scan_response_; + this->advertising_data_.include_name = true; this->advertising_data_.include_txpower = !this->scan_response_; err = esp_ble_gap_config_adv_data(&this->advertising_data_); if (err != ESP_OK) {