core/homeassistant/components/teslemetry/media_player.py

155 lines
5.2 KiB
Python

"""Media player platform for Teslemetry integration."""
from __future__ import annotations
from tesla_fleet_api.const import Scope
from homeassistant.components.media_player import (
MediaPlayerDeviceClass,
MediaPlayerEntity,
MediaPlayerEntityFeature,
MediaPlayerState,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TeslemetryConfigEntry
from .entity import TeslemetryVehicleEntity
from .helpers import handle_vehicle_command
from .models import TeslemetryVehicleData
STATES = {
"Playing": MediaPlayerState.PLAYING,
"Paused": MediaPlayerState.PAUSED,
"Stopped": MediaPlayerState.IDLE,
"Off": MediaPlayerState.OFF,
}
VOLUME_MAX = 11.0
VOLUME_STEP = 1.0 / 3
PARALLEL_UPDATES = 0
async def async_setup_entry(
hass: HomeAssistant,
entry: TeslemetryConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Teslemetry Media platform from a config entry."""
async_add_entities(
TeslemetryMediaEntity(vehicle, Scope.VEHICLE_CMDS in entry.runtime_data.scopes)
for vehicle in entry.runtime_data.vehicles
)
class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity):
"""Vehicle media player class."""
_attr_device_class = MediaPlayerDeviceClass.SPEAKER
_attr_supported_features = (
MediaPlayerEntityFeature.NEXT_TRACK
| MediaPlayerEntityFeature.PAUSE
| MediaPlayerEntityFeature.PLAY
| MediaPlayerEntityFeature.PREVIOUS_TRACK
| MediaPlayerEntityFeature.VOLUME_SET
)
_volume_max: float = VOLUME_MAX
def __init__(
self,
data: TeslemetryVehicleData,
scoped: bool,
) -> None:
"""Initialize the media player entity."""
super().__init__(data, "media")
self.scoped = scoped
if not scoped:
self._attr_supported_features = MediaPlayerEntityFeature(0)
def _async_update_attrs(self) -> None:
"""Update entity attributes."""
self._volume_max = (
self.get("vehicle_state_media_info_audio_volume_max") or VOLUME_MAX
)
self._attr_state = STATES.get(
self.get("vehicle_state_media_info_media_playback_status") or "Off",
)
self._attr_volume_step = (
1.0
/ self._volume_max
/ (
self.get("vehicle_state_media_info_audio_volume_increment")
or VOLUME_STEP
)
)
if volume := self.get("vehicle_state_media_info_audio_volume"):
self._attr_volume_level = volume / self._volume_max
else:
self._attr_volume_level = None
if duration := self.get("vehicle_state_media_info_now_playing_duration"):
self._attr_media_duration = duration / 1000
else:
self._attr_media_duration = None
if duration and (
position := self.get("vehicle_state_media_info_now_playing_elapsed")
):
self._attr_media_position = position / 1000
else:
self._attr_media_position = None
self._attr_media_title = self.get("vehicle_state_media_info_now_playing_title")
self._attr_media_artist = self.get(
"vehicle_state_media_info_now_playing_artist"
)
self._attr_media_album_name = self.get(
"vehicle_state_media_info_now_playing_album"
)
self._attr_media_playlist = self.get(
"vehicle_state_media_info_now_playing_station"
)
self._attr_source = self.get("vehicle_state_media_info_now_playing_source")
async def async_set_volume_level(self, volume: float) -> None:
"""Set volume level, range 0..1."""
self.raise_for_scope(Scope.VEHICLE_CMDS)
await self.wake_up_if_asleep()
await handle_vehicle_command(
self.api.adjust_volume(int(volume * self._volume_max))
)
self._attr_volume_level = volume
self.async_write_ha_state()
async def async_media_play(self) -> None:
"""Send play command."""
if self.state != MediaPlayerState.PLAYING:
self.raise_for_scope(Scope.VEHICLE_CMDS)
await self.wake_up_if_asleep()
await handle_vehicle_command(self.api.media_toggle_playback())
self._attr_state = MediaPlayerState.PLAYING
self.async_write_ha_state()
async def async_media_pause(self) -> None:
"""Send pause command."""
if self.state == MediaPlayerState.PLAYING:
self.raise_for_scope(Scope.VEHICLE_CMDS)
await self.wake_up_if_asleep()
await handle_vehicle_command(self.api.media_toggle_playback())
self._attr_state = MediaPlayerState.PAUSED
self.async_write_ha_state()
async def async_media_next_track(self) -> None:
"""Send next track command."""
self.raise_for_scope(Scope.VEHICLE_CMDS)
await self.wake_up_if_asleep()
await handle_vehicle_command(self.api.media_next_track())
async def async_media_previous_track(self) -> None:
"""Send previous track command."""
self.raise_for_scope(Scope.VEHICLE_CMDS)
await self.wake_up_if_asleep()
await handle_vehicle_command(self.api.media_prev_track())