mirror of
https://github.com/esphome/esphome.git
synced 2025-09-01 10:52:19 +01:00
Set ble tx power
This commit is contained in:
@@ -3,7 +3,17 @@ import re
|
||||
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
|
||||
from esphome.components.esp32 import (
|
||||
VARIANT_ESP32C2,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_ESP32C5,
|
||||
VARIANT_ESP32C6,
|
||||
VARIANT_ESP32H2,
|
||||
VARIANT_ESP32S3,
|
||||
add_idf_sdkconfig_option,
|
||||
const,
|
||||
get_esp32_variant,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ENABLE_ON_BOOT,
|
||||
@@ -11,8 +21,10 @@ from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_NAME,
|
||||
CONF_NAME_ADD_MAC_SUFFIX,
|
||||
CONF_TX_POWER,
|
||||
)
|
||||
from esphome.core import CORE, TimePeriod
|
||||
from esphome.cpp_types import MockObj
|
||||
import esphome.final_validate as fv
|
||||
|
||||
DEPENDENCIES = ["esp32"]
|
||||
@@ -151,7 +163,8 @@ IO_CAPABILITY = {
|
||||
|
||||
esp_power_level_t = cg.global_ns.enum("esp_power_level_t")
|
||||
|
||||
TX_POWER_LEVELS = {
|
||||
# Power level mappings for code generation - ESP32 classic
|
||||
TX_POWER_LEVELS_ESP32 = {
|
||||
-12: esp_power_level_t.ESP_PWR_LVL_N12,
|
||||
-9: esp_power_level_t.ESP_PWR_LVL_N9,
|
||||
-6: esp_power_level_t.ESP_PWR_LVL_N6,
|
||||
@@ -162,6 +175,53 @@ TX_POWER_LEVELS = {
|
||||
9: esp_power_level_t.ESP_PWR_LVL_P9,
|
||||
}
|
||||
|
||||
# Power level mappings for code generation - Extended variants
|
||||
TX_POWER_LEVELS_EXT = {
|
||||
-24: esp_power_level_t.ESP_PWR_LVL_N24,
|
||||
-21: esp_power_level_t.ESP_PWR_LVL_N21,
|
||||
-18: esp_power_level_t.ESP_PWR_LVL_N18,
|
||||
-15: esp_power_level_t.ESP_PWR_LVL_N15,
|
||||
-12: esp_power_level_t.ESP_PWR_LVL_N12,
|
||||
-9: esp_power_level_t.ESP_PWR_LVL_N9,
|
||||
-6: esp_power_level_t.ESP_PWR_LVL_N6,
|
||||
-3: esp_power_level_t.ESP_PWR_LVL_N3,
|
||||
0: esp_power_level_t.ESP_PWR_LVL_N0,
|
||||
3: esp_power_level_t.ESP_PWR_LVL_P3,
|
||||
6: esp_power_level_t.ESP_PWR_LVL_P6,
|
||||
9: esp_power_level_t.ESP_PWR_LVL_P9,
|
||||
12: esp_power_level_t.ESP_PWR_LVL_P12,
|
||||
15: esp_power_level_t.ESP_PWR_LVL_P15,
|
||||
18: esp_power_level_t.ESP_PWR_LVL_P18,
|
||||
20: esp_power_level_t.ESP_PWR_LVL_P20,
|
||||
}
|
||||
|
||||
|
||||
def _get_tx_power_levels() -> dict[str, MockObj]:
|
||||
variant = get_esp32_variant()
|
||||
if variant in [
|
||||
VARIANT_ESP32C2,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_ESP32C5,
|
||||
VARIANT_ESP32C6,
|
||||
VARIANT_ESP32H2,
|
||||
VARIANT_ESP32S3,
|
||||
]:
|
||||
return TX_POWER_LEVELS_EXT
|
||||
return TX_POWER_LEVELS_ESP32
|
||||
|
||||
|
||||
def validate_tx_power(value: int) -> int:
|
||||
value = cv.decibel(value)
|
||||
power_levels = _get_tx_power_levels()
|
||||
if value not in power_levels:
|
||||
raise cv.Invalid(
|
||||
f"TX power {value}dBm is not valid. "
|
||||
f"Valid values are: {', '.join(str(v) + 'dBm' for v in sorted(power_levels.keys()))}"
|
||||
)
|
||||
# Return just the dBm value, we'll map it to enum in to_code
|
||||
return value
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
||||
@@ -169,6 +229,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum(
|
||||
IO_CAPABILITY, lower=True
|
||||
),
|
||||
cv.Optional(CONF_TX_POWER): validate_tx_power,
|
||||
cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean,
|
||||
cv.Optional(CONF_ADVERTISING, default=False): cv.boolean,
|
||||
cv.Optional(
|
||||
@@ -259,6 +320,9 @@ async def to_code(config):
|
||||
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))
|
||||
if (tx_power := config.get(CONF_TX_POWER)) is not None:
|
||||
# The validation already returned the enum value
|
||||
cg.add(var.set_tx_power(_get_tx_power_levels()[tx_power]))
|
||||
await cg.register_component(var, config)
|
||||
|
||||
if CORE.using_esp_idf:
|
||||
|
@@ -212,6 +212,15 @@ bool ESP32BLE::ble_setup_() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set TX power for all BLE operations (advertising, scanning, connections)
|
||||
err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, this->tx_power_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err));
|
||||
// Continue anyway as this is not critical
|
||||
} else {
|
||||
ESP_LOGD(TAG, "BLE TX power set to level %d", this->tx_power_);
|
||||
}
|
||||
|
||||
// BLE takes some time to be fully set up, 200ms should be more than enough
|
||||
delay(200); // NOLINT
|
||||
|
||||
@@ -520,11 +529,106 @@ void ESP32BLE::dump_config() {
|
||||
io_capability_s = "invalid";
|
||||
break;
|
||||
}
|
||||
// Convert TX power level to dBm for display
|
||||
int tx_power_dbm = 0;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
// ESP32 classic power levels (0-7)
|
||||
switch (this->tx_power_) {
|
||||
case 0:
|
||||
tx_power_dbm = -12;
|
||||
break; // ESP_PWR_LVL_N12
|
||||
case 1:
|
||||
tx_power_dbm = -9;
|
||||
break; // ESP_PWR_LVL_N9
|
||||
case 2:
|
||||
tx_power_dbm = -6;
|
||||
break; // ESP_PWR_LVL_N6
|
||||
case 3:
|
||||
tx_power_dbm = -3;
|
||||
break; // ESP_PWR_LVL_N3
|
||||
case 4:
|
||||
tx_power_dbm = 0;
|
||||
break; // ESP_PWR_LVL_N0
|
||||
case 5:
|
||||
tx_power_dbm = 3;
|
||||
break; // ESP_PWR_LVL_P3
|
||||
case 6:
|
||||
tx_power_dbm = 6;
|
||||
break; // ESP_PWR_LVL_P6
|
||||
case 7:
|
||||
tx_power_dbm = 9;
|
||||
break; // ESP_PWR_LVL_P9
|
||||
default:
|
||||
tx_power_dbm = 0;
|
||||
break;
|
||||
}
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || \
|
||||
defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || \
|
||||
defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// Extended power levels for C2/C3/C5/C6/H2/S3 (0-15)
|
||||
switch (this->tx_power_) {
|
||||
case 0:
|
||||
tx_power_dbm = -24;
|
||||
break; // ESP_PWR_LVL_N24
|
||||
case 1:
|
||||
tx_power_dbm = -21;
|
||||
break; // ESP_PWR_LVL_N21
|
||||
case 2:
|
||||
tx_power_dbm = -18;
|
||||
break; // ESP_PWR_LVL_N18
|
||||
case 3:
|
||||
tx_power_dbm = -15;
|
||||
break; // ESP_PWR_LVL_N15
|
||||
case 4:
|
||||
tx_power_dbm = -12;
|
||||
break; // ESP_PWR_LVL_N12
|
||||
case 5:
|
||||
tx_power_dbm = -9;
|
||||
break; // ESP_PWR_LVL_N9
|
||||
case 6:
|
||||
tx_power_dbm = -6;
|
||||
break; // ESP_PWR_LVL_N6
|
||||
case 7:
|
||||
tx_power_dbm = -3;
|
||||
break; // ESP_PWR_LVL_N3
|
||||
case 8:
|
||||
tx_power_dbm = 0;
|
||||
break; // ESP_PWR_LVL_N0
|
||||
case 9:
|
||||
tx_power_dbm = 3;
|
||||
break; // ESP_PWR_LVL_P3
|
||||
case 10:
|
||||
tx_power_dbm = 6;
|
||||
break; // ESP_PWR_LVL_P6
|
||||
case 11:
|
||||
tx_power_dbm = 9;
|
||||
break; // ESP_PWR_LVL_P9
|
||||
case 12:
|
||||
tx_power_dbm = 12;
|
||||
break; // ESP_PWR_LVL_P12
|
||||
case 13:
|
||||
tx_power_dbm = 15;
|
||||
break; // ESP_PWR_LVL_P15
|
||||
case 14:
|
||||
tx_power_dbm = 18;
|
||||
break; // ESP_PWR_LVL_P18
|
||||
case 15:
|
||||
tx_power_dbm = 20;
|
||||
break; // ESP_PWR_LVL_P20
|
||||
default:
|
||||
tx_power_dbm = 0;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// Unknown variant
|
||||
tx_power_dbm = 0;
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"BLE:\n"
|
||||
" MAC address: %s\n"
|
||||
" IO Capability: %s",
|
||||
format_mac_address_pretty(mac_address).c_str(), io_capability_s);
|
||||
" IO Capability: %s\n"
|
||||
" TX Power: %d dBm",
|
||||
format_mac_address_pretty(mac_address).c_str(), io_capability_s, tx_power_dbm);
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, "Bluetooth stack is not enabled");
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <esp_bt.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gattc_api.h>
|
||||
#include <esp_gatts_api.h>
|
||||
@@ -94,6 +95,7 @@ class BLEStatusEventHandler {
|
||||
class ESP32BLE : public Component {
|
||||
public:
|
||||
void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; }
|
||||
void set_tx_power(esp_power_level_t tx_power) { this->tx_power_ = tx_power; }
|
||||
|
||||
void set_advertising_cycle_time(uint32_t advertising_cycle_time) {
|
||||
this->advertising_cycle_time_ = advertising_cycle_time;
|
||||
@@ -172,6 +174,7 @@ class ESP32BLE : public Component {
|
||||
// 1-byte aligned members (grouped together to minimize padding)
|
||||
BLEComponentState state_{BLE_COMPONENT_STATE_OFF}; // 1 byte (uint8_t enum)
|
||||
bool enable_on_boot_{}; // 1 byte
|
||||
esp_power_level_t tx_power_{ESP_PWR_LVL_P9}; // 1 byte (default: +9 dBm)
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
Reference in New Issue
Block a user