mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 02:56:01 +00:00
[media_player] Migrate triggers to callback automation (#15200)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
dea8fdd906
commit
2e42547d32
@@ -9,7 +9,6 @@ from esphome.const import (
|
||||
CONF_ON_STATE,
|
||||
CONF_ON_TURN_OFF,
|
||||
CONF_ON_TURN_ON,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_VOLUME,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
@@ -65,15 +64,19 @@ _COMMAND_ACTIONS = [
|
||||
"clear_playlist",
|
||||
]
|
||||
|
||||
# State triggers: (config_key, C++ class name)
|
||||
StateAnyForwarder = media_player_ns.class_("StateAnyForwarder")
|
||||
StateEnterForwarder = media_player_ns.class_("StateEnterForwarder")
|
||||
MediaPlayerState = media_player_ns.enum("MediaPlayerState")
|
||||
|
||||
# State triggers: (config_key, state enum or None for any-state)
|
||||
_STATE_TRIGGERS = [
|
||||
(CONF_ON_STATE, "StateTrigger"),
|
||||
(CONF_ON_IDLE, "IdleTrigger"),
|
||||
(CONF_ON_PLAY, "PlayTrigger"),
|
||||
(CONF_ON_PAUSE, "PauseTrigger"),
|
||||
(CONF_ON_ANNOUNCEMENT, "AnnouncementTrigger"),
|
||||
(CONF_ON_TURN_ON, "OnTrigger"),
|
||||
(CONF_ON_TURN_OFF, "OffTrigger"),
|
||||
(CONF_ON_STATE, None),
|
||||
(CONF_ON_IDLE, MediaPlayerState.MEDIA_PLAYER_STATE_IDLE),
|
||||
(CONF_ON_PLAY, MediaPlayerState.MEDIA_PLAYER_STATE_PLAYING),
|
||||
(CONF_ON_PAUSE, MediaPlayerState.MEDIA_PLAYER_STATE_PAUSED),
|
||||
(CONF_ON_ANNOUNCEMENT, MediaPlayerState.MEDIA_PLAYER_STATE_ANNOUNCING),
|
||||
(CONF_ON_TURN_ON, MediaPlayerState.MEDIA_PLAYER_STATE_ON),
|
||||
(CONF_ON_TURN_OFF, MediaPlayerState.MEDIA_PLAYER_STATE_OFF),
|
||||
]
|
||||
|
||||
# State conditions that all share the same schema and codegen handler
|
||||
@@ -98,10 +101,15 @@ VolumeSetAction = media_player_ns.class_(
|
||||
|
||||
@setup_entity("media_player")
|
||||
async def setup_media_player_core_(var, config):
|
||||
for conf_key, _ in _STATE_TRIGGERS:
|
||||
for conf_key, state_enum in _STATE_TRIGGERS:
|
||||
for conf in config.get(conf_key, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
if state_enum is None:
|
||||
forwarder = StateAnyForwarder
|
||||
else:
|
||||
forwarder = StateEnterForwarder.template(state_enum)
|
||||
await automation.build_callback_automation(
|
||||
var, "add_on_state_callback", [], conf, forwarder=forwarder
|
||||
)
|
||||
|
||||
|
||||
async def register_media_player(var, config):
|
||||
@@ -120,14 +128,8 @@ async def new_media_player(config, *args):
|
||||
|
||||
_MEDIA_PLAYER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
|
||||
{
|
||||
cv.Optional(conf_key): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
media_player_ns.class_(class_name, automation.Trigger.template())
|
||||
),
|
||||
}
|
||||
)
|
||||
for conf_key, class_name in _STATE_TRIGGERS
|
||||
cv.Optional(conf_key): automation.validate_automation({})
|
||||
for conf_key, _ in _STATE_TRIGGERS
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -71,32 +71,27 @@ template<typename... Ts> class VolumeSetAction : public Action<Ts...>, public Pa
|
||||
void play(const Ts &...x) override { this->parent_->make_call().set_volume(this->volume_.value(x...)).perform(); }
|
||||
};
|
||||
|
||||
class StateTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit StateTrigger(MediaPlayer *player) {
|
||||
player->add_on_state_callback([this]() { this->trigger(); });
|
||||
/// Callback forwarder that triggers an Automation<> on any state change.
|
||||
/// Pointer-sized (single Automation* field) to fit inline in Callback::ctx_.
|
||||
struct StateAnyForwarder {
|
||||
Automation<> *automation;
|
||||
void operator()(MediaPlayerState /*state*/) const { this->automation->trigger(); }
|
||||
};
|
||||
|
||||
/// Callback forwarder that triggers an Automation<> only when a specific media player state is entered.
|
||||
/// Pointer-sized (single Automation* field) to fit inline in Callback::ctx_.
|
||||
template<MediaPlayerState State> struct StateEnterForwarder {
|
||||
Automation<> *automation;
|
||||
void operator()(MediaPlayerState state) const {
|
||||
if (state == State)
|
||||
this->automation->trigger();
|
||||
}
|
||||
};
|
||||
|
||||
template<MediaPlayerState State> class MediaPlayerStateTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit MediaPlayerStateTrigger(MediaPlayer *player) : player_(player) {
|
||||
player->add_on_state_callback([this]() {
|
||||
if (this->player_->state == State)
|
||||
this->trigger();
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
MediaPlayer *player_;
|
||||
};
|
||||
|
||||
using IdleTrigger = MediaPlayerStateTrigger<MediaPlayerState::MEDIA_PLAYER_STATE_IDLE>;
|
||||
using PlayTrigger = MediaPlayerStateTrigger<MediaPlayerState::MEDIA_PLAYER_STATE_PLAYING>;
|
||||
using PauseTrigger = MediaPlayerStateTrigger<MediaPlayerState::MEDIA_PLAYER_STATE_PAUSED>;
|
||||
using AnnouncementTrigger = MediaPlayerStateTrigger<MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING>;
|
||||
using OnTrigger = MediaPlayerStateTrigger<MediaPlayerState::MEDIA_PLAYER_STATE_ON>;
|
||||
using OffTrigger = MediaPlayerStateTrigger<MediaPlayerState::MEDIA_PLAYER_STATE_OFF>;
|
||||
static_assert(sizeof(StateAnyForwarder) <= sizeof(void *));
|
||||
static_assert(std::is_trivially_copyable_v<StateAnyForwarder>);
|
||||
static_assert(sizeof(StateEnterForwarder<MediaPlayerState::MEDIA_PLAYER_STATE_IDLE>) <= sizeof(void *));
|
||||
static_assert(std::is_trivially_copyable_v<StateEnterForwarder<MediaPlayerState::MEDIA_PLAYER_STATE_IDLE>>);
|
||||
|
||||
template<typename... Ts> class IsIdleCondition : public Condition<Ts...>, public Parented<MediaPlayer> {
|
||||
public:
|
||||
|
||||
@@ -199,7 +199,7 @@ MediaPlayerCall &MediaPlayerCall::set_announcement(bool announce) {
|
||||
}
|
||||
|
||||
void MediaPlayer::publish_state() {
|
||||
this->state_callback_.call();
|
||||
this->state_callback_.call(this->state);
|
||||
#if defined(USE_MEDIA_PLAYER) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_media_player_update(this);
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,7 @@ class MediaPlayer : public EntityBase {
|
||||
|
||||
virtual void control(const MediaPlayerCall &call) = 0;
|
||||
|
||||
LazyCallbackManager<void()> state_callback_{};
|
||||
LazyCallbackManager<void(MediaPlayerState)> state_callback_{};
|
||||
};
|
||||
|
||||
} // namespace media_player
|
||||
|
||||
@@ -39,8 +39,8 @@ void VoiceAssistant::setup() {
|
||||
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
if (this->media_player_ != nullptr) {
|
||||
this->media_player_->add_on_state_callback([this]() {
|
||||
switch (this->media_player_->state) {
|
||||
this->media_player_->add_on_state_callback([this](media_player::MediaPlayerState state) {
|
||||
switch (state) {
|
||||
case media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING:
|
||||
if (this->media_player_response_state_ == MediaPlayerResponseState::URL_SENT) {
|
||||
// State changed to announcing after receiving the url
|
||||
|
||||
Reference in New Issue
Block a user