[openthread] Add tx power option (#14200)

Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
schrob
2026-03-03 05:28:01 +01:00
committed by GitHub
parent db15b94cd7
commit 60d66ca2dc
5 changed files with 41 additions and 1 deletions

View File

@@ -4,13 +4,20 @@ from esphome.components.esp32 import (
VARIANT_ESP32C6,
VARIANT_ESP32H2,
add_idf_sdkconfig_option,
get_esp32_variant,
include_builtin_idf_component,
only_on_variant,
require_vfs_select,
)
from esphome.components.mdns import MDNSComponent, enable_mdns_storage
import esphome.config_validation as cv
from esphome.const import CONF_CHANNEL, CONF_ENABLE_IPV6, CONF_ID, CONF_USE_ADDRESS
from esphome.const import (
CONF_CHANNEL,
CONF_ENABLE_IPV6,
CONF_ID,
CONF_OUTPUT_POWER,
CONF_USE_ADDRESS,
)
from esphome.core import CORE, TimePeriodMilliseconds
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -45,6 +52,20 @@ CONF_DEVICE_TYPES = [
]
def _validate_txpower(value):
if CORE.is_esp32:
variant = get_esp32_variant()
# HW limits: Datasheet section "802.15.4 RF Transmitter (TX) Characteristics"
# Further regulatory/soft limit may apply, e.g. by region
if variant in (VARIANT_ESP32C6, VARIANT_ESP32C5):
return cv.int_range(min=-15, max=20)(value)
if variant == VARIANT_ESP32H2:
return cv.int_range(min=-24, max=20)(value)
return value # Unsupported, fail later with clear error
def set_sdkconfig_options(config):
# and expose options for using SPI/UART RCPs
add_idf_sdkconfig_option("CONFIG_IEEE802154_ENABLED", True)
@@ -155,6 +176,10 @@ CONFIG_SCHEMA = cv.All(
cv.Optional(CONF_TLV): cv.string_strict,
cv.Optional(CONF_USE_ADDRESS): cv.string_strict,
cv.Optional(CONF_POLL_PERIOD): cv.positive_time_period_milliseconds,
cv.Optional(CONF_OUTPUT_POWER): cv.All(
cv.decibel,
_validate_txpower,
),
}
).extend(_CONNECTION_SCHEMA),
cv.has_exactly_one_key(CONF_NETWORK_KEY, CONF_TLV),
@@ -197,4 +222,7 @@ async def to_code(config):
cg.add(srp.set_mdns(mdns_component))
await cg.register_component(srp, config)
if (output_power := config.get(CONF_OUTPUT_POWER)) is not None:
cg.add(ot.set_output_power(output_power))
set_sdkconfig_options(config)

View File

@@ -43,6 +43,9 @@ void OpenThreadComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Device is configured as Minimal End Device (MED)");
}
#endif
if (this->output_power_.has_value()) {
ESP_LOGCONFIG(TAG, " Output power: %" PRId8 "dBm", *this->output_power_);
}
}
bool OpenThreadComponent::is_connected() {

View File

@@ -38,6 +38,7 @@ class OpenThreadComponent : public Component {
#if CONFIG_OPENTHREAD_MTD
void set_poll_period(uint32_t poll_period) { this->poll_period_ = poll_period; }
#endif
void set_output_power(int8_t output_power) { this->output_power_ = output_power; }
protected:
std::optional<otIp6Address> get_omr_address_(InstanceLock &lock);
@@ -45,6 +46,7 @@ class OpenThreadComponent : public Component {
#if CONFIG_OPENTHREAD_MTD
uint32_t poll_period_{0};
#endif
std::optional<int8_t> output_power_{};
bool teardown_started_{false};
bool teardown_complete_{false};

View File

@@ -135,6 +135,12 @@ void OpenThreadComponent::ot_main() {
TRUEFALSE(link_mode_config.mRxOnWhenIdle));
#endif
if (this->output_power_.has_value()) {
if (const auto err = otPlatRadioSetTransmitPower(instance, *this->output_power_); err != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set power: %s", otThreadErrorToString(err));
}
}
// Run the main loop
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_create_task();

View File

@@ -13,3 +13,4 @@ openthread:
force_dataset: true
use_address: open-thread-test.local
poll_period: 20sec
output_power: 1dBm