diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index 5db73d14914..7b901e7ab37 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -80,7 +80,9 @@ SUPPORT_FIRETV = ( | SUPPORT_STOP ) +ATTR_ADB_RESPONSE = "adb_response" ATTR_DEVICE_PATH = "device_path" +ATTR_HDMI_INPUT = "hdmi_input" ATTR_LOCAL_PATH = "local_path" CONF_ADBKEY = "adbkey" @@ -374,13 +376,13 @@ def adb_decorator(override_available=False): err, ) await self.aftv.adb_close() - self._available = False + self._attr_available = False # pylint: disable=protected-access return None except Exception: # An unforeseen exception occurred. Close the ADB connection so that # it doesn't happen over and over again, then raise the exception. await self.aftv.adb_close() - self._available = False + self._attr_available = False # pylint: disable=protected-access raise return _adb_exception_catcher @@ -404,7 +406,7 @@ class ADBDevice(MediaPlayerEntity): ): """Initialize the Android TV / Fire TV device.""" self.aftv = aftv - self._name = name + self._attr_name = name self._app_id_to_name = APPS.copy() self._app_id_to_name.update(apps) self._app_name_to_id = { @@ -415,12 +417,8 @@ class ADBDevice(MediaPlayerEntity): # in `self._app_name_to_id` for key, value in apps.items(): self._app_name_to_id[value] = key - self._get_sources = get_sources - self._keys = KEYS - - self._device_properties = self.aftv.device_properties - self._unique_id = self._device_properties.get("serialno") + self._attr_unique_id = self.aftv.device_properties.get("serialno") self.turn_on_command = turn_on_command self.turn_off_command = turn_off_command @@ -446,66 +444,11 @@ class ADBDevice(MediaPlayerEntity): self.exceptions = (ConnectionResetError, RuntimeError) # Property attributes - self._adb_response = None - self._available = True - self._current_app = None - self._sources = None - self._state = None - self._hdmi_input = None - - @property - def app_id(self): - """Return the current app.""" - return self._current_app - - @property - def app_name(self): - """Return the friendly name of the current app.""" - return self._app_id_to_name.get(self._current_app, self._current_app) - - @property - def available(self): - """Return whether or not the ADB connection is valid.""" - return self._available - - @property - def extra_state_attributes(self): - """Provide the last ADB command's response and the device's HDMI input as attributes.""" - return { - "adb_response": self._adb_response, - "hdmi_input": self._hdmi_input, + self._attr_extra_state_attributes = { + ATTR_ADB_RESPONSE: None, + ATTR_HDMI_INPUT: None, } - @property - def media_image_hash(self): - """Hash value for media image.""" - return f"{datetime.now().timestamp()}" if self._screencap else None - - @property - def name(self): - """Return the device name.""" - return self._name - - @property - def source(self): - """Return the current app.""" - return self._app_id_to_name.get(self._current_app, self._current_app) - - @property - def source_list(self): - """Return a list of running apps.""" - return self._sources - - @property - def state(self): - """Return the state of the player.""" - return self._state - - @property - def unique_id(self): - """Return the device unique id.""" - return self._unique_id - @adb_decorator() async def _adb_screencap(self): """Take a screen capture from the device.""" @@ -515,6 +458,9 @@ class ADBDevice(MediaPlayerEntity): """Fetch current playing image.""" if not self._screencap or self.state in [STATE_OFF, None] or not self.available: return None, None + self._attr_media_image_hash = ( + f"{datetime.now().timestamp()}" if self._screencap else None + ) media_data = await self._adb_screencap() if media_data: @@ -584,15 +530,17 @@ class ADBDevice(MediaPlayerEntity): @adb_decorator() async def adb_command(self, cmd): """Send an ADB command to an Android TV / Fire TV device.""" - key = self._keys.get(cmd) + key = KEYS.get(cmd) if key: await self.aftv.adb_shell(f"input keyevent {key}") return if cmd == "GET_PROPERTIES": - self._adb_response = str(await self.aftv.get_properties_dict()) + self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = str( + await self.aftv.get_properties_dict() + ) self.async_write_ha_state() - return self._adb_response + return try: response = await self.aftv.adb_shell(cmd) @@ -600,17 +548,17 @@ class ADBDevice(MediaPlayerEntity): return if isinstance(response, str) and response.strip(): - self._adb_response = response.strip() + self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = response.strip() self.async_write_ha_state() - return self._adb_response + return @adb_decorator() async def learn_sendevent(self): """Translate a key press on a remote to ADB 'sendevent' commands.""" output = await self.aftv.learn_sendevent() if output: - self._adb_response = output + self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = output self.async_write_ha_state() msg = f"Output from service '{SERVICE_LEARN_SENDEVENT}' from {self.entity_id}: '{output}'" @@ -634,84 +582,48 @@ class ADBDevice(MediaPlayerEntity): class AndroidTVDevice(ADBDevice): """Representation of an Android TV device.""" - def __init__( - self, - aftv, - name, - apps, - get_sources, - turn_on_command, - turn_off_command, - exclude_unnamed_apps, - screencap, - ): - """Initialize the Android TV device.""" - super().__init__( - aftv, - name, - apps, - get_sources, - turn_on_command, - turn_off_command, - exclude_unnamed_apps, - screencap, - ) - - self._is_volume_muted = None - self._volume_level = None + _attr_supported_features = SUPPORT_ANDROIDTV @adb_decorator(override_available=True) async def async_update(self): """Update the device state and, if necessary, re-connect.""" # Check if device is disconnected. - if not self._available: + if not self.available: # Try to connect - self._available = await self.aftv.adb_connect(always_log_errors=False) + self._attr_available = await self.aftv.adb_connect(always_log_errors=False) # If the ADB connection is not intact, don't update. - if not self._available: + if not self.available: return # Get the updated state and attributes. ( state, - self._current_app, + self._attr_app_id, running_apps, _, - self._is_volume_muted, - self._volume_level, - self._hdmi_input, + self._attr_is_volume_muted, + self._attr_volume_level, + self._attr_extra_state_attributes[ATTR_HDMI_INPUT], ) = await self.aftv.update(self._get_sources) - self._state = ANDROIDTV_STATES.get(state) - if self._state is None: - self._available = False + self._attr_state = ANDROIDTV_STATES.get(state) + if self._attr_state is None: + self._attr_available = False if running_apps: + self._attr_source = self._attr_app_name = self._app_id_to_name.get( + self._attr_app_id, self._attr_app_id + ) sources = [ self._app_id_to_name.get( app_id, app_id if not self._exclude_unnamed_apps else None ) for app_id in running_apps ] - self._sources = [source for source in sources if source] + self._attr_source_list = [source for source in sources if source] else: - self._sources = None - - @property - def is_volume_muted(self): - """Boolean if volume is currently muted.""" - return self._is_volume_muted - - @property - def supported_features(self): - """Flag media player features that are supported.""" - return SUPPORT_ANDROIDTV - - @property - def volume_level(self): - """Return the volume level.""" - return self._volume_level + self._attr_source_list = None @adb_decorator() async def async_media_stop(self): @@ -731,56 +643,56 @@ class AndroidTVDevice(ADBDevice): @adb_decorator() async def async_volume_down(self): """Send volume down command.""" - self._volume_level = await self.aftv.volume_down(self._volume_level) + self._attr_volume_level = await self.aftv.volume_down(self._attr_volume_level) @adb_decorator() async def async_volume_up(self): """Send volume up command.""" - self._volume_level = await self.aftv.volume_up(self._volume_level) + self._attr_volume_level = await self.aftv.volume_up(self._attr_volume_level) class FireTVDevice(ADBDevice): """Representation of a Fire TV device.""" + _attr_supported_features = SUPPORT_FIRETV + @adb_decorator(override_available=True) async def async_update(self): """Update the device state and, if necessary, re-connect.""" # Check if device is disconnected. - if not self._available: + if not self.available: # Try to connect - self._available = await self.aftv.adb_connect(always_log_errors=False) + self._attr_available = await self.aftv.adb_connect(always_log_errors=False) # If the ADB connection is not intact, don't update. - if not self._available: + if not self.available: return # Get the `state`, `current_app`, `running_apps` and `hdmi_input`. ( state, - self._current_app, + self._attr_app_id, running_apps, - self._hdmi_input, + self._attr_extra_state_attributes[ATTR_HDMI_INPUT], ) = await self.aftv.update(self._get_sources) - self._state = ANDROIDTV_STATES.get(state) - if self._state is None: - self._available = False + self._attr_state = ANDROIDTV_STATES.get(state) + if self._attr_state is None: + self._attr_available = False if running_apps: + self._attr_source = self._app_id_to_name.get( + self._attr_app_id, self._attr_app_id + ) sources = [ self._app_id_to_name.get( app_id, app_id if not self._exclude_unnamed_apps else None ) for app_id in running_apps ] - self._sources = [source for source in sources if source] + self._attr_source_list = [source for source in sources if source] else: - self._sources = None - - @property - def supported_features(self): - """Flag media player features that are supported.""" - return SUPPORT_FIRETV + self._attr_source_list = None @adb_decorator() async def async_media_stop(self):