mirror of
https://github.com/esphome/esphome.git
synced 2026-09-28 07:20:24 +00:00
[media_player] Use register_apply_action for the media player actions (#19514)
This commit is contained in:
@@ -152,7 +152,7 @@ CONF_ON_PAUSE = "on_pause"
|
||||
CONF_ON_ANNOUNCEMENT = "on_announcement"
|
||||
CONF_MEDIA_URL = "media_url"
|
||||
|
||||
# Command actions that all share the same schema and codegen handler
|
||||
# Command actions that all share the same schema and only differ in the command sent
|
||||
_COMMAND_ACTIONS = [
|
||||
"play",
|
||||
"pause",
|
||||
@@ -201,16 +201,7 @@ _STATE_CONDITIONS = [
|
||||
"muted",
|
||||
]
|
||||
|
||||
# Special action classes with custom schemas/handlers
|
||||
PlayMediaAction = media_player_ns.class_(
|
||||
"PlayMediaAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
EnqueueMediaAction = media_player_ns.class_(
|
||||
"EnqueueMediaAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
VolumeSetAction = media_player_ns.class_(
|
||||
"VolumeSetAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
MediaPlayerCommand = media_player_ns.enum("MediaPlayerCommand", is_class=True)
|
||||
|
||||
|
||||
_CALLBACK_AUTOMATIONS = (
|
||||
@@ -329,59 +320,50 @@ _MEDIA_URL_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
)
|
||||
|
||||
|
||||
async def _media_action_handler(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
media_url = await cg.templatable(config[CONF_MEDIA_URL], args, cg.std_string)
|
||||
announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
|
||||
cg.add(var.set_media_url(media_url))
|
||||
cg.add(var.set_announcement(announcement))
|
||||
return var
|
||||
_ANNOUNCEMENT_FIELD = automation.ApplyField(
|
||||
CONF_ANNOUNCEMENT, "set_announcement", cg.bool_
|
||||
)
|
||||
_MEDIA_URL_FIELD = automation.ApplyField(CONF_MEDIA_URL, "set_media_url", cg.std_string)
|
||||
|
||||
|
||||
automation.register_action(
|
||||
def _set_command(command_name: str) -> automation.ApplyCall:
|
||||
command = getattr(
|
||||
MediaPlayerCommand, f"MEDIA_PLAYER_COMMAND_{command_name.upper()}"
|
||||
)
|
||||
return automation.ApplyCall(f"set_command({command})")
|
||||
|
||||
|
||||
automation.register_apply_action(
|
||||
"media_player.play_media",
|
||||
PlayMediaAction,
|
||||
_MEDIA_URL_ACTION_SCHEMA,
|
||||
synchronous=True,
|
||||
)(_media_action_handler)
|
||||
_MEDIA_URL_FIELD,
|
||||
_ANNOUNCEMENT_FIELD,
|
||||
call="make_call",
|
||||
)
|
||||
|
||||
automation.register_action(
|
||||
automation.register_apply_action(
|
||||
"media_player.enqueue",
|
||||
EnqueueMediaAction,
|
||||
_MEDIA_URL_ACTION_SCHEMA,
|
||||
synchronous=True,
|
||||
)(_media_action_handler)
|
||||
_set_command("enqueue"),
|
||||
_MEDIA_URL_FIELD,
|
||||
_ANNOUNCEMENT_FIELD,
|
||||
call="make_call",
|
||||
)
|
||||
|
||||
for _action_name in _COMMAND_ACTIONS:
|
||||
automation.register_apply_action(
|
||||
f"media_player.{_action_name}",
|
||||
MEDIA_PLAYER_ACTION_SCHEMA,
|
||||
_set_command(_action_name),
|
||||
_ANNOUNCEMENT_FIELD,
|
||||
call="make_call",
|
||||
)
|
||||
|
||||
|
||||
def _snake_to_camel(name):
|
||||
return "".join(word.capitalize() for word in name.split("_"))
|
||||
|
||||
|
||||
def _register_command_actions():
|
||||
async def handler(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
|
||||
cg.add(var.set_announcement(announcement))
|
||||
return var
|
||||
|
||||
for action_name in _COMMAND_ACTIONS:
|
||||
class_name = f"{_snake_to_camel(action_name)}Action"
|
||||
action_class = media_player_ns.class_(
|
||||
class_name, automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
automation.register_action(
|
||||
f"media_player.{action_name}",
|
||||
action_class,
|
||||
MEDIA_PLAYER_ACTION_SCHEMA,
|
||||
synchronous=True,
|
||||
)(handler)
|
||||
|
||||
|
||||
_register_command_actions()
|
||||
|
||||
|
||||
def _register_state_conditions():
|
||||
async def handler(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
@@ -401,9 +383,8 @@ def _register_state_conditions():
|
||||
_register_state_conditions()
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
automation.register_apply_action(
|
||||
"media_player.volume_set",
|
||||
VolumeSetAction,
|
||||
cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(MediaPlayer),
|
||||
@@ -411,14 +392,9 @@ _register_state_conditions()
|
||||
},
|
||||
key=CONF_VOLUME,
|
||||
),
|
||||
synchronous=True,
|
||||
automation.ApplyField(CONF_VOLUME, "set_volume", cg.float_),
|
||||
call="make_call",
|
||||
)
|
||||
async def media_player_volume_set_action(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
volume = await cg.templatable(config[CONF_VOLUME], args, cg.float_)
|
||||
cg.add(var.set_volume(volume))
|
||||
return var
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.CORE)
|
||||
|
||||
@@ -5,76 +5,6 @@
|
||||
|
||||
namespace esphome::media_player {
|
||||
|
||||
template<MediaPlayerCommand Command, typename... Ts>
|
||||
class MediaPlayerCommandAction final : public Action<Ts...>, public Parented<MediaPlayer> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(bool, announcement);
|
||||
void play(const Ts &...x) override {
|
||||
this->parent_->make_call().set_command(Command).set_announcement(this->announcement_.value(x...)).perform();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
using PlayAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_PLAY, Ts...>;
|
||||
template<typename... Ts>
|
||||
using PauseAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_PAUSE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using StopAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_STOP, Ts...>;
|
||||
template<typename... Ts>
|
||||
using ToggleAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_TOGGLE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using VolumeUpAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_VOLUME_UP, Ts...>;
|
||||
template<typename... Ts>
|
||||
using VolumeDownAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_VOLUME_DOWN, Ts...>;
|
||||
template<typename... Ts>
|
||||
using TurnOnAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_TURN_ON, Ts...>;
|
||||
template<typename... Ts>
|
||||
using TurnOffAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_TURN_OFF, Ts...>;
|
||||
template<typename... Ts>
|
||||
using NextAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_NEXT, Ts...>;
|
||||
template<typename... Ts>
|
||||
using PreviousAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_PREVIOUS, Ts...>;
|
||||
template<typename... Ts>
|
||||
using MuteAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_MUTE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using UnmuteAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_UNMUTE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using RepeatOffAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_OFF, Ts...>;
|
||||
template<typename... Ts>
|
||||
using RepeatOneAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ONE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using RepeatAllAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ALL, Ts...>;
|
||||
template<typename... Ts>
|
||||
using ShuffleAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_SHUFFLE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using UnshuffleAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_UNSHUFFLE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using GroupJoinAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_GROUP_JOIN, Ts...>;
|
||||
template<typename... Ts>
|
||||
using ClearPlaylistAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST, Ts...>;
|
||||
|
||||
template<MediaPlayerCommand Command, typename... Ts>
|
||||
class MediaPlayerMediaAction final : public Action<Ts...>, public Parented<MediaPlayer> {
|
||||
TEMPLATABLE_VALUE(std::string, media_url)
|
||||
TEMPLATABLE_VALUE(bool, announcement)
|
||||
void play(const Ts &...x) override {
|
||||
auto call = this->parent_->make_call();
|
||||
if constexpr (Command != MediaPlayerCommand::MEDIA_PLAYER_COMMAND_PLAY)
|
||||
call.set_command(Command);
|
||||
call.set_media_url(this->media_url_.value(x...)).set_announcement(this->announcement_.value(x...)).perform();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
using PlayMediaAction = MediaPlayerMediaAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_PLAY, Ts...>;
|
||||
template<typename... Ts>
|
||||
using EnqueueMediaAction = MediaPlayerMediaAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_ENQUEUE, Ts...>;
|
||||
|
||||
template<typename... Ts> class VolumeSetAction final : public Action<Ts...>, public Parented<MediaPlayer> {
|
||||
TEMPLATABLE_VALUE(float, volume)
|
||||
void play(const Ts &...x) override { this->parent_->make_call().set_volume(this->volume_.value(x...)).perform(); }
|
||||
};
|
||||
|
||||
/// Callback forwarder that triggers an Automation<> on any state change.
|
||||
/// Pointer-sized (single Automation* field) to fit inline in Callback::ctx_.
|
||||
struct StateAnyForwarder {
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: 13
|
||||
i2s_bclk_pin: 14
|
||||
i2s_mclk_pin: 15
|
||||
|
||||
speaker:
|
||||
- platform: i2s_audio
|
||||
id: test_speaker
|
||||
i2s_dout_pin: 18
|
||||
i2s_audio_id: i2s_audio_bus
|
||||
i2s_dout_pin: ${i2s_dout_pin}
|
||||
dac_type: external
|
||||
|
||||
media_player:
|
||||
- platform: speaker
|
||||
id: test_media_player
|
||||
name: None
|
||||
speaker: test_speaker
|
||||
announcement_pipeline:
|
||||
speaker: test_speaker
|
||||
format: NONE
|
||||
on_state:
|
||||
- media_player.play:
|
||||
- media_player.play_media: http://localhost/media.mp3
|
||||
- media_player.play_media: !lambda 'return "http://localhost/media.mp3";'
|
||||
- media_player.play_media: !lambda |-
|
||||
return id(test_media_player).is_muted() ? "http://localhost/muted.mp3" : "http://localhost/media.mp3";
|
||||
on_idle:
|
||||
- media_player.pause:
|
||||
on_play:
|
||||
- media_player.stop:
|
||||
- media_player.stop:
|
||||
announcement: true
|
||||
- media_player.stop:
|
||||
announcement: !lambda 'return id(test_media_player).is_muted();'
|
||||
on_announcement:
|
||||
- media_player.play:
|
||||
on_turn_on:
|
||||
@@ -61,8 +63,10 @@ media_player:
|
||||
- media_player.volume_up:
|
||||
- media_player.volume_down:
|
||||
- media_player.volume_set: 50%
|
||||
- media_player.volume_set: !lambda 'return id(test_media_player).volume / 2;'
|
||||
- media_player.enqueue: http://localhost/media.mp3
|
||||
- media_player.enqueue: !lambda 'return "http://localhost/media.mp3";'
|
||||
- media_player.enqueue: !lambda |-
|
||||
return id(test_media_player).is_muted() ? "http://localhost/muted.mp3" : "http://localhost/media.mp3";
|
||||
- media_player.enqueue:
|
||||
media_url: http://localhost/media.mp3
|
||||
announcement: true
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
i2s_dout_pin: GPIO18
|
||||
|
||||
packages:
|
||||
i2s_audio: !include ../../test_build_components/common/i2s_audio/esp32-idf.yaml
|
||||
media_player: !include common.yaml
|
||||
|
||||
wifi:
|
||||
ap:
|
||||
Reference in New Issue
Block a user