mirror of
https://github.com/esphome/esphome.git
synced 2025-09-04 12:22:20 +01:00
Set ble tx power
This commit is contained in:
@@ -3,7 +3,17 @@ import re
|
|||||||
|
|
||||||
from esphome import automation
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
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
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ENABLE_ON_BOOT,
|
CONF_ENABLE_ON_BOOT,
|
||||||
@@ -11,8 +21,10 @@ from esphome.const import (
|
|||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_NAME_ADD_MAC_SUFFIX,
|
CONF_NAME_ADD_MAC_SUFFIX,
|
||||||
|
CONF_TX_POWER,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, TimePeriod
|
from esphome.core import CORE, TimePeriod
|
||||||
|
from esphome.cpp_types import MockObj
|
||||||
import esphome.final_validate as fv
|
import esphome.final_validate as fv
|
||||||
|
|
||||||
DEPENDENCIES = ["esp32"]
|
DEPENDENCIES = ["esp32"]
|
||||||
@@ -151,7 +163,8 @@ IO_CAPABILITY = {
|
|||||||
|
|
||||||
esp_power_level_t = cg.global_ns.enum("esp_power_level_t")
|
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,
|
-12: esp_power_level_t.ESP_PWR_LVL_N12,
|
||||||
-9: esp_power_level_t.ESP_PWR_LVL_N9,
|
-9: esp_power_level_t.ESP_PWR_LVL_N9,
|
||||||
-6: esp_power_level_t.ESP_PWR_LVL_N6,
|
-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,
|
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(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
||||||
@@ -169,6 +229,7 @@ CONFIG_SCHEMA = cv.Schema(
|
|||||||
cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum(
|
cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum(
|
||||||
IO_CAPABILITY, lower=True
|
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_ENABLE_ON_BOOT, default=True): cv.boolean,
|
||||||
cv.Optional(CONF_ADVERTISING, default=False): cv.boolean,
|
cv.Optional(CONF_ADVERTISING, default=False): cv.boolean,
|
||||||
cv.Optional(
|
cv.Optional(
|
||||||
@@ -259,6 +320,9 @@ async def to_code(config):
|
|||||||
cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME]))
|
cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME]))
|
||||||
if (name := config.get(CONF_NAME)) is not None:
|
if (name := config.get(CONF_NAME)) is not None:
|
||||||
cg.add(var.set_name(name))
|
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)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
if CORE.using_esp_idf:
|
if CORE.using_esp_idf:
|
||||||
|
@@ -212,6 +212,15 @@ bool ESP32BLE::ble_setup_() {
|
|||||||
return false;
|
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
|
// BLE takes some time to be fully set up, 200ms should be more than enough
|
||||||
delay(200); // NOLINT
|
delay(200); // NOLINT
|
||||||
|
|
||||||
@@ -520,11 +529,106 @@ void ESP32BLE::dump_config() {
|
|||||||
io_capability_s = "invalid";
|
io_capability_s = "invalid";
|
||||||
break;
|
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,
|
ESP_LOGCONFIG(TAG,
|
||||||
"BLE:\n"
|
"BLE:\n"
|
||||||
" MAC address: %s\n"
|
" MAC address: %s\n"
|
||||||
" IO Capability: %s",
|
" IO Capability: %s\n"
|
||||||
format_mac_address_pretty(mac_address).c_str(), io_capability_s);
|
" TX Power: %d dBm",
|
||||||
|
format_mac_address_pretty(mac_address).c_str(), io_capability_s, tx_power_dbm);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGCONFIG(TAG, "Bluetooth stack is not enabled");
|
ESP_LOGCONFIG(TAG, "Bluetooth stack is not enabled");
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
|
#include <esp_bt.h>
|
||||||
#include <esp_gap_ble_api.h>
|
#include <esp_gap_ble_api.h>
|
||||||
#include <esp_gattc_api.h>
|
#include <esp_gattc_api.h>
|
||||||
#include <esp_gatts_api.h>
|
#include <esp_gatts_api.h>
|
||||||
@@ -94,6 +95,7 @@ class BLEStatusEventHandler {
|
|||||||
class ESP32BLE : public Component {
|
class ESP32BLE : public Component {
|
||||||
public:
|
public:
|
||||||
void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; }
|
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) {
|
void set_advertising_cycle_time(uint32_t advertising_cycle_time) {
|
||||||
this->advertising_cycle_time_ = 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)
|
// 1-byte aligned members (grouped together to minimize padding)
|
||||||
BLEComponentState state_{BLE_COMPONENT_STATE_OFF}; // 1 byte (uint8_t enum)
|
BLEComponentState state_{BLE_COMPONENT_STATE_OFF}; // 1 byte (uint8_t enum)
|
||||||
bool enable_on_boot_{}; // 1 byte
|
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)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
Reference in New Issue
Block a user