mirror of
https://github.com/esphome/esphome.git
synced 2026-09-28 15:30:21 +00:00
[openthread] Use register_apply_action for openthread.set_poll_period (#19697)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user