[openthread] Use register_apply_action for openthread.set_poll_period (#19697)

This commit is contained in:
J. Nick Koston
2026-09-26 01:34:38 +01:00
committed by GitHub
parent b8c32854ed
commit 3f2de92e5d
5 changed files with 23 additions and 126 deletions
+2 -22
View File
@@ -35,12 +35,10 @@ from esphome.const import (
)
from esphome.core import (
CORE,
ID,
CoroPriority,
TimePeriodMilliseconds,
coroutine_with_priority,
)
from esphome.cpp_generator import MockObj, TemplateArgsType
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -328,12 +326,6 @@ async def to_code(config: ConfigType) -> None:
# Actions
OpenThreadComponentPollPeriodAction = openthread_ns.class_(
"OpenThreadComponentPollPeriodAction",
automation.Action,
cg.Parented.template(OpenThreadComponent),
)
POLL_PERIOD_ACTION_SCHEMA = automation.maybe_conf(
CONF_POLL_PERIOD,
cv.Schema(
@@ -347,20 +339,8 @@ POLL_PERIOD_ACTION_SCHEMA = automation.maybe_conf(
)
@automation.register_action(
automation.register_apply_action(
"openthread.set_poll_period",
OpenThreadComponentPollPeriodAction,
POLL_PERIOD_ACTION_SCHEMA,
synchronous=True,
automation.ApplyField(CONF_POLL_PERIOD, "apply_poll_period", cg.uint32),
)
async def openthread_poll_period_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config[CONF_POLL_PERIOD], args, cg.uint32)
cg.add(var.set_poll_period(template_))
return var
@@ -1,37 +0,0 @@
#include "esphome/core/defines.h"
#ifdef USE_OPENTHREAD
#include "automation.h"
#include "esphome/core/log.h"
namespace esphome::openthread {
static const char *const TAG = "openthread.automation";
void OpenThreadComponentBaseAction::warn_ftd_no_op_() {
ESP_LOGW(TAG, "OpenThread action has no effect on FTD devices (MTD only)");
}
void OpenThreadComponentBaseAction::lock_and_apply_() {
if (this->parent_->is_ready()) {
if (auto lock = InstanceLock::try_acquire(LOCK_ACQUIRE_TIMEOUT_MS); lock) {
if (auto *instance = lock.get_instance(); instance != nullptr) {
this->apply_locked(instance);
}
} else {
ESP_LOGW(TAG, "Failed to acquire lock in action");
}
} else {
// Action may trigger early before setup, e.g. due to enabled "restore mode".
// Trying to acquire lock would fail!
//
// But default component values already have been overwritten.
// It is sufficient to let component apply those later during setup.
ESP_LOGD(TAG, "Not (yet) ready to apply");
}
}
} // namespace esphome::openthread
#endif
@@ -1,61 +0,0 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_OPENTHREAD
#include "openthread.h"
#include "esphome/core/automation.h"
#include "esphome/core/helpers.h"
namespace esphome::openthread {
/** Base class allowing to fetch OpenThread lock from parent component
* while applying action
*
* - Nontemplate aspects belong here to avoid template bloat.
* - Subclasses implement virtual action method that is called under lock.
* - Seal leaf subclasses via @a final to support devirtualization.
*/
class OpenThreadComponentBaseAction : public Parented<OpenThreadComponent> {
public:
// Enforce ctor with parent argument (not without args)
explicit OpenThreadComponentBaseAction(OpenThreadComponent *ot) : Parented<OpenThreadComponent>(ot) {}
protected:
/** Handler to implement in subclass for applying action parts that need lock */
virtual void apply_locked(otInstance *instance) = 0;
/** Fetch OT lock and then call @a apply_locked */
void lock_and_apply_();
/** Log a warning that this action has no effect on FTD devices */
void warn_ftd_no_op_();
/** Timeout (ms) for acquiring OT lock */
static constexpr uint32_t LOCK_ACQUIRE_TIMEOUT_MS = 100;
};
/** Action to set single poll period parameter */
template<typename... Ts>
class OpenThreadComponentPollPeriodAction final : public Action<Ts...>, public OpenThreadComponentBaseAction {
TEMPLATABLE_VALUE(uint32_t, poll_period)
public:
/* Passthrough ctor */
using OpenThreadComponentBaseAction::OpenThreadComponentBaseAction;
protected:
void play(const Ts &...x) override {
#if CONFIG_OPENTHREAD_MTD
this->parent_->set_poll_period(this->poll_period_.value(x...));
this->lock_and_apply_();
#else
this->warn_ftd_no_op_();
#endif
}
void apply_locked(otInstance *instance) override { this->parent_->apply_linkmode_(instance); }
};
} // namespace esphome::openthread
#endif
@@ -282,6 +282,25 @@ void OpenThreadComponent::on_factory_reset(std::function<void()> callback) {
ESP_LOGD(TAG, "Waiting on Confirmation Removal SRP Host and Services");
}
void OpenThreadComponent::apply_poll_period(uint32_t poll_period) {
#if CONFIG_OPENTHREAD_MTD
this->set_poll_period(poll_period);
if (!this->is_lock_initialized()) {
// The action may run before the stack is up, e.g. from a restore mode; ot_main applies the stored value.
ESP_LOGD(TAG, "Not (yet) ready to apply");
return;
}
auto lock = InstanceLock::try_acquire(100);
if (!lock) {
ESP_LOGW(TAG, "Failed to acquire lock in action");
return;
}
this->apply_linkmode_(lock.get_instance());
#else
ESP_LOGW(TAG, "OpenThread action has no effect on FTD devices (MTD only)");
#endif
}
void OpenThreadComponent::apply_linkmode_(otInstance *instance) {
otLinkModeConfig link_mode_config{};
#if CONFIG_OPENTHREAD_FTD
+2 -6
View File
@@ -25,8 +25,6 @@ enum class TeardownStage : uint8_t {
TEARDOWN_STAGE_COMPLETED,
};
template<typename... Ts> class OpenThreadComponentPollPeriodAction;
class OpenThreadComponent final : public Component {
public:
OpenThreadComponent();
@@ -53,15 +51,13 @@ class OpenThreadComponent final : public Component {
void set_poll_period(uint32_t poll_period) { this->poll_period_ = poll_period; }
uint32_t get_poll_period() const { return this->poll_period_; }
#endif
/// Set the poll period and re-apply the link mode under the OT lock; a warning only on FTD builds.
void apply_poll_period(uint32_t poll_period);
void set_output_power(int8_t output_power) { this->output_power_ = output_power; }
void set_connected(bool connected) { this->connected_ = connected; }
static void on_state_changed(otChangedFlags flags, void *context);
protected:
// Actions re-apply link mode under the OT lock; allow them to call apply_linkmode_()
// without exposing this lock-sensitive, raw-instance method on the public API.
template<typename... Ts> friend class OpenThreadComponentPollPeriodAction;
/** Apply Link Mode settings (incl poll period).
* Callers running outside the OpenThread task must hold InstanceLock.
* ot_main() runs on the OpenThread task itself and must not acquire the lock.