ha-core/homeassistant/components/esphome/media_player.py

154 lines
4.9 KiB
Python

"""Support for ESPHome media players."""
from __future__ import annotations
from typing import Any
from aioesphomeapi import (
EntityInfo,
MediaPlayerCommand,
MediaPlayerEntityState,
MediaPlayerInfo,
MediaPlayerState as EspMediaPlayerState,
)
from homeassistant.components import media_source
from homeassistant.components.media_player import (
BrowseMedia,
MediaPlayerDeviceClass,
MediaPlayerEntity,
MediaPlayerEntityFeature,
MediaPlayerState,
MediaType,
async_process_play_media_url,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .entity import EsphomeEntity, esphome_state_property, platform_async_setup_entry
from .enum_mapper import EsphomeEnumMapper
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up esphome media players based on a config entry."""
await platform_async_setup_entry(
hass,
entry,
async_add_entities,
info_type=MediaPlayerInfo,
entity_type=EsphomeMediaPlayer,
state_type=MediaPlayerEntityState,
)
_STATES: EsphomeEnumMapper[EspMediaPlayerState, MediaPlayerState] = EsphomeEnumMapper(
{
EspMediaPlayerState.IDLE: MediaPlayerState.IDLE,
EspMediaPlayerState.PLAYING: MediaPlayerState.PLAYING,
EspMediaPlayerState.PAUSED: MediaPlayerState.PAUSED,
}
)
class EsphomeMediaPlayer(
EsphomeEntity[MediaPlayerInfo, MediaPlayerEntityState], MediaPlayerEntity
):
"""A media player implementation for esphome."""
_attr_device_class = MediaPlayerDeviceClass.SPEAKER
@callback
def _on_static_info_update(self, static_info: EntityInfo) -> None:
"""Set attrs from static info."""
super()._on_static_info_update(static_info)
flags = (
MediaPlayerEntityFeature.PLAY_MEDIA
| MediaPlayerEntityFeature.BROWSE_MEDIA
| MediaPlayerEntityFeature.STOP
| MediaPlayerEntityFeature.VOLUME_SET
| MediaPlayerEntityFeature.VOLUME_MUTE
)
if self._static_info.supports_pause:
flags |= MediaPlayerEntityFeature.PAUSE | MediaPlayerEntityFeature.PLAY
self._attr_supported_features = flags
@property
@esphome_state_property
def state(self) -> MediaPlayerState | None:
"""Return current state."""
return _STATES.from_esphome(self._state.state)
@property
@esphome_state_property
def is_volume_muted(self) -> bool:
"""Return true if volume is muted."""
return self._state.muted
@property
@esphome_state_property
def volume_level(self) -> float | None:
"""Volume level of the media player (0..1)."""
return self._state.volume
async def async_play_media(
self, media_type: MediaType | str, media_id: str, **kwargs: Any
) -> None:
"""Send the play command with media url to the media player."""
if media_source.is_media_source_id(media_id):
sourced_media = await media_source.async_resolve_media(
self.hass, media_id, self.entity_id
)
media_id = sourced_media.url
media_id = async_process_play_media_url(self.hass, media_id)
await self._client.media_player_command(
self._key,
media_url=media_id,
)
async def async_browse_media(
self,
media_content_type: MediaType | str | None = None,
media_content_id: str | None = None,
) -> BrowseMedia:
"""Implement the websocket media browsing helper."""
return await media_source.async_browse_media(
self.hass,
media_content_id,
content_filter=lambda item: item.media_content_type.startswith("audio/"),
)
async def async_set_volume_level(self, volume: float) -> None:
"""Set volume level, range 0..1."""
await self._client.media_player_command(self._key, volume=volume)
async def async_media_pause(self) -> None:
"""Send pause command."""
await self._client.media_player_command(
self._key, command=MediaPlayerCommand.PAUSE
)
async def async_media_play(self) -> None:
"""Send play command."""
await self._client.media_player_command(
self._key, command=MediaPlayerCommand.PLAY
)
async def async_media_stop(self) -> None:
"""Send stop command."""
await self._client.media_player_command(
self._key, command=MediaPlayerCommand.STOP
)
async def async_mute_volume(self, mute: bool) -> None:
"""Mute the volume."""
await self._client.media_player_command(
self._key,
command=MediaPlayerCommand.MUTE if mute else MediaPlayerCommand.UNMUTE,
)