"""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() 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() 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() 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() 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() await self.wake_up_if_asleep() await handle_vehicle_command(self.api.media_prev_track())