mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Add missing type hints for AndroidTV (#96554)
* Add missing type hints for AndroidTV * Suggested change
This commit is contained in:
parent
9775832d53
commit
c95e2c074c
@ -9,6 +9,7 @@ from typing import Any, Concatenate, ParamSpec, TypeVar
|
|||||||
|
|
||||||
from androidtv.constants import APPS, KEYS
|
from androidtv.constants import APPS, KEYS
|
||||||
from androidtv.exceptions import LockNotAcquiredException
|
from androidtv.exceptions import LockNotAcquiredException
|
||||||
|
from androidtv.setup_async import AndroidTVAsync, FireTVAsync
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import persistent_notification
|
from homeassistant.components import persistent_notification
|
||||||
@ -88,13 +89,15 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Android Debug Bridge entity."""
|
"""Set up the Android Debug Bridge entity."""
|
||||||
aftv = hass.data[DOMAIN][entry.entry_id][ANDROID_DEV]
|
aftv: AndroidTVAsync | FireTVAsync = hass.data[DOMAIN][entry.entry_id][ANDROID_DEV]
|
||||||
device_class = aftv.DEVICE_CLASS
|
device_class = aftv.DEVICE_CLASS
|
||||||
device_type = (
|
device_type = (
|
||||||
PREFIX_ANDROIDTV if device_class == DEVICE_ANDROIDTV else PREFIX_FIRETV
|
PREFIX_ANDROIDTV if device_class == DEVICE_ANDROIDTV else PREFIX_FIRETV
|
||||||
)
|
)
|
||||||
# CONF_NAME may be present in entry.data for configuration imported from YAML
|
# CONF_NAME may be present in entry.data for configuration imported from YAML
|
||||||
device_name = entry.data.get(CONF_NAME) or f"{device_type} {entry.data[CONF_HOST]}"
|
device_name: str = entry.data.get(
|
||||||
|
CONF_NAME, f"{device_type} {entry.data[CONF_HOST]}"
|
||||||
|
)
|
||||||
|
|
||||||
device_args = [
|
device_args = [
|
||||||
aftv,
|
aftv,
|
||||||
@ -171,8 +174,11 @@ def adb_decorator(
|
|||||||
except LockNotAcquiredException:
|
except LockNotAcquiredException:
|
||||||
# If the ADB lock could not be acquired, skip this command
|
# If the ADB lock could not be acquired, skip this command
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"ADB command not executed because the connection is currently"
|
(
|
||||||
" in use"
|
"ADB command %s not executed because the connection is"
|
||||||
|
" currently in use"
|
||||||
|
),
|
||||||
|
func.__name__,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
except self.exceptions as err:
|
except self.exceptions as err:
|
||||||
@ -207,13 +213,13 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
aftv,
|
aftv: AndroidTVAsync | FireTVAsync,
|
||||||
name,
|
name: str,
|
||||||
dev_type,
|
dev_type: str,
|
||||||
unique_id,
|
unique_id: str,
|
||||||
entry_id,
|
entry_id: str,
|
||||||
entry_data,
|
entry_data: dict[str, Any],
|
||||||
):
|
) -> None:
|
||||||
"""Initialize the Android / Fire TV device."""
|
"""Initialize the Android / Fire TV device."""
|
||||||
self.aftv = aftv
|
self.aftv = aftv
|
||||||
self._attr_name = name
|
self._attr_name = name
|
||||||
@ -235,13 +241,13 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
if mac := get_androidtv_mac(info):
|
if mac := get_androidtv_mac(info):
|
||||||
self._attr_device_info[ATTR_CONNECTIONS] = {(CONNECTION_NETWORK_MAC, mac)}
|
self._attr_device_info[ATTR_CONNECTIONS] = {(CONNECTION_NETWORK_MAC, mac)}
|
||||||
|
|
||||||
self._app_id_to_name = {}
|
self._app_id_to_name: dict[str, str] = {}
|
||||||
self._app_name_to_id = {}
|
self._app_name_to_id: dict[str, str] = {}
|
||||||
self._get_sources = DEFAULT_GET_SOURCES
|
self._get_sources = DEFAULT_GET_SOURCES
|
||||||
self._exclude_unnamed_apps = DEFAULT_EXCLUDE_UNNAMED_APPS
|
self._exclude_unnamed_apps = DEFAULT_EXCLUDE_UNNAMED_APPS
|
||||||
self._screencap = DEFAULT_SCREENCAP
|
self._screencap = DEFAULT_SCREENCAP
|
||||||
self.turn_on_command = None
|
self.turn_on_command: str | None = None
|
||||||
self.turn_off_command = None
|
self.turn_off_command: str | None = None
|
||||||
|
|
||||||
# ADB exceptions to catch
|
# ADB exceptions to catch
|
||||||
if not aftv.adb_server_ip:
|
if not aftv.adb_server_ip:
|
||||||
@ -260,7 +266,7 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
# The number of consecutive failed connect attempts
|
# The number of consecutive failed connect attempts
|
||||||
self._failed_connect_count = 0
|
self._failed_connect_count = 0
|
||||||
|
|
||||||
def _process_config(self):
|
def _process_config(self) -> None:
|
||||||
"""Load the config options."""
|
"""Load the config options."""
|
||||||
_LOGGER.debug("Loading configuration options")
|
_LOGGER.debug("Loading configuration options")
|
||||||
options = self._entry_data[ANDROID_DEV_OPT]
|
options = self._entry_data[ANDROID_DEV_OPT]
|
||||||
@ -303,7 +309,7 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
return f"{datetime.now().timestamp()}" if self._screencap else None
|
return f"{datetime.now().timestamp()}" if self._screencap else None
|
||||||
|
|
||||||
@adb_decorator()
|
@adb_decorator()
|
||||||
async def _adb_screencap(self):
|
async def _adb_screencap(self) -> bytes | None:
|
||||||
"""Take a screen capture from the device."""
|
"""Take a screen capture from the device."""
|
||||||
return await self.aftv.adb_screencap()
|
return await self.aftv.adb_screencap()
|
||||||
|
|
||||||
@ -382,7 +388,7 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
await self.aftv.stop_app(self._app_name_to_id.get(source_, source_))
|
await self.aftv.stop_app(self._app_name_to_id.get(source_, source_))
|
||||||
|
|
||||||
@adb_decorator()
|
@adb_decorator()
|
||||||
async def adb_command(self, command):
|
async def adb_command(self, command: str) -> None:
|
||||||
"""Send an ADB command to an Android / Fire TV device."""
|
"""Send an ADB command to an Android / Fire TV device."""
|
||||||
if key := KEYS.get(command):
|
if key := KEYS.get(command):
|
||||||
await self.aftv.adb_shell(f"input keyevent {key}")
|
await self.aftv.adb_shell(f"input keyevent {key}")
|
||||||
@ -407,7 +413,7 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@adb_decorator()
|
@adb_decorator()
|
||||||
async def learn_sendevent(self):
|
async def learn_sendevent(self) -> None:
|
||||||
"""Translate a key press on a remote to ADB 'sendevent' commands."""
|
"""Translate a key press on a remote to ADB 'sendevent' commands."""
|
||||||
output = await self.aftv.learn_sendevent()
|
output = await self.aftv.learn_sendevent()
|
||||||
if output:
|
if output:
|
||||||
@ -426,7 +432,7 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
_LOGGER.info("%s", msg)
|
_LOGGER.info("%s", msg)
|
||||||
|
|
||||||
@adb_decorator()
|
@adb_decorator()
|
||||||
async def service_download(self, device_path, local_path):
|
async def service_download(self, device_path: str, local_path: str) -> None:
|
||||||
"""Download a file from your Android / Fire TV device to your Home Assistant instance."""
|
"""Download a file from your Android / Fire TV device to your Home Assistant instance."""
|
||||||
if not self.hass.config.is_allowed_path(local_path):
|
if not self.hass.config.is_allowed_path(local_path):
|
||||||
_LOGGER.warning("'%s' is not secure to load data from!", local_path)
|
_LOGGER.warning("'%s' is not secure to load data from!", local_path)
|
||||||
@ -435,7 +441,7 @@ class ADBDevice(MediaPlayerEntity):
|
|||||||
await self.aftv.adb_pull(local_path, device_path)
|
await self.aftv.adb_pull(local_path, device_path)
|
||||||
|
|
||||||
@adb_decorator()
|
@adb_decorator()
|
||||||
async def service_upload(self, device_path, local_path):
|
async def service_upload(self, device_path: str, local_path: str) -> None:
|
||||||
"""Upload a file from your Home Assistant instance to an Android / Fire TV device."""
|
"""Upload a file from your Home Assistant instance to an Android / Fire TV device."""
|
||||||
if not self.hass.config.is_allowed_path(local_path):
|
if not self.hass.config.is_allowed_path(local_path):
|
||||||
_LOGGER.warning("'%s' is not secure to load data from!", local_path)
|
_LOGGER.warning("'%s' is not secure to load data from!", local_path)
|
||||||
@ -460,6 +466,7 @@ class AndroidTVDevice(ADBDevice):
|
|||||||
| MediaPlayerEntityFeature.VOLUME_SET
|
| MediaPlayerEntityFeature.VOLUME_SET
|
||||||
| MediaPlayerEntityFeature.VOLUME_STEP
|
| MediaPlayerEntityFeature.VOLUME_STEP
|
||||||
)
|
)
|
||||||
|
aftv: AndroidTVAsync
|
||||||
|
|
||||||
@adb_decorator(override_available=True)
|
@adb_decorator(override_available=True)
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
@ -492,7 +499,7 @@ class AndroidTVDevice(ADBDevice):
|
|||||||
if self._attr_state is None:
|
if self._attr_state is None:
|
||||||
self._attr_available = False
|
self._attr_available = False
|
||||||
|
|
||||||
if running_apps:
|
if running_apps and self._attr_app_id:
|
||||||
self._attr_source = self._attr_app_name = self._app_id_to_name.get(
|
self._attr_source = self._attr_app_name = self._app_id_to_name.get(
|
||||||
self._attr_app_id, self._attr_app_id
|
self._attr_app_id, self._attr_app_id
|
||||||
)
|
)
|
||||||
@ -549,6 +556,7 @@ class FireTVDevice(ADBDevice):
|
|||||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||||
| MediaPlayerEntityFeature.STOP
|
| MediaPlayerEntityFeature.STOP
|
||||||
)
|
)
|
||||||
|
aftv: FireTVAsync
|
||||||
|
|
||||||
@adb_decorator(override_available=True)
|
@adb_decorator(override_available=True)
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
@ -578,7 +586,7 @@ class FireTVDevice(ADBDevice):
|
|||||||
if self._attr_state is None:
|
if self._attr_state is None:
|
||||||
self._attr_available = False
|
self._attr_available = False
|
||||||
|
|
||||||
if running_apps:
|
if running_apps and self._attr_app_id:
|
||||||
self._attr_source = self._app_id_to_name.get(
|
self._attr_source = self._app_id_to_name.get(
|
||||||
self._attr_app_id, self._attr_app_id
|
self._attr_app_id, self._attr_app_id
|
||||||
)
|
)
|
||||||
|
@ -23,7 +23,7 @@ PROPS_DEV_MAC = "ether ab:cd:ef:gh:ij:kl brd"
|
|||||||
class AdbDeviceTcpAsyncFake:
|
class AdbDeviceTcpAsyncFake:
|
||||||
"""A fake of the `adb_shell.adb_device_async.AdbDeviceTcpAsync` class."""
|
"""A fake of the `adb_shell.adb_device_async.AdbDeviceTcpAsync` class."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
"""Initialize a fake `adb_shell.adb_device_async.AdbDeviceTcpAsync` instance."""
|
"""Initialize a fake `adb_shell.adb_device_async.AdbDeviceTcpAsync` instance."""
|
||||||
self.available = False
|
self.available = False
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class AdbDeviceTcpAsyncFake:
|
|||||||
class ClientAsyncFakeSuccess:
|
class ClientAsyncFakeSuccess:
|
||||||
"""A fake of the `ClientAsync` class when the connection and shell commands succeed."""
|
"""A fake of the `ClientAsync` class when the connection and shell commands succeed."""
|
||||||
|
|
||||||
def __init__(self, host=ADB_SERVER_HOST, port=DEFAULT_ADB_SERVER_PORT):
|
def __init__(self, host=ADB_SERVER_HOST, port=DEFAULT_ADB_SERVER_PORT) -> None:
|
||||||
"""Initialize a `ClientAsyncFakeSuccess` instance."""
|
"""Initialize a `ClientAsyncFakeSuccess` instance."""
|
||||||
self._devices = []
|
self._devices = []
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class ClientAsyncFakeSuccess:
|
|||||||
class ClientAsyncFakeFail:
|
class ClientAsyncFakeFail:
|
||||||
"""A fake of the `ClientAsync` class when the connection and shell commands fail."""
|
"""A fake of the `ClientAsync` class when the connection and shell commands fail."""
|
||||||
|
|
||||||
def __init__(self, host=ADB_SERVER_HOST, port=DEFAULT_ADB_SERVER_PORT):
|
def __init__(self, host=ADB_SERVER_HOST, port=DEFAULT_ADB_SERVER_PORT) -> None:
|
||||||
"""Initialize a `ClientAsyncFakeFail` instance."""
|
"""Initialize a `ClientAsyncFakeFail` instance."""
|
||||||
self._devices = []
|
self._devices = []
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ class ClientAsyncFakeFail:
|
|||||||
class DeviceAsyncFake:
|
class DeviceAsyncFake:
|
||||||
"""A fake of the `DeviceAsync` class."""
|
"""A fake of the `DeviceAsync` class."""
|
||||||
|
|
||||||
def __init__(self, host):
|
def __init__(self, host) -> None:
|
||||||
"""Initialize a `DeviceAsyncFake` instance."""
|
"""Initialize a `DeviceAsyncFake` instance."""
|
||||||
self.host = host
|
self.host = host
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ def keygen_fixture() -> None:
|
|||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
def _setup(config):
|
def _setup(config) -> tuple[str, str, MockConfigEntry]:
|
||||||
"""Perform common setup tasks for the tests."""
|
"""Perform common setup tasks for the tests."""
|
||||||
patch_key = config[ADB_PATCH_KEY]
|
patch_key = config[ADB_PATCH_KEY]
|
||||||
entity_id = f"{MP_DOMAIN}.{slugify(config[TEST_ENTITY_NAME])}"
|
entity_id = f"{MP_DOMAIN}.{slugify(config[TEST_ENTITY_NAME])}"
|
||||||
@ -453,8 +453,8 @@ async def test_exclude_sources(
|
|||||||
|
|
||||||
|
|
||||||
async def _test_select_source(
|
async def _test_select_source(
|
||||||
hass, config, conf_apps, source, expected_arg, method_patch
|
hass: HomeAssistant, config, conf_apps, source, expected_arg, method_patch
|
||||||
):
|
) -> None:
|
||||||
"""Test that the methods for launching and stopping apps are called correctly when selecting a source."""
|
"""Test that the methods for launching and stopping apps are called correctly when selecting a source."""
|
||||||
patch_key, entity_id, config_entry = _setup(config)
|
patch_key, entity_id, config_entry = _setup(config)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -947,13 +947,13 @@ async def test_get_image_disabled(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
|
|
||||||
async def _test_service(
|
async def _test_service(
|
||||||
hass,
|
hass: HomeAssistant,
|
||||||
entity_id,
|
entity_id,
|
||||||
ha_service_name,
|
ha_service_name,
|
||||||
androidtv_method,
|
androidtv_method,
|
||||||
additional_service_data=None,
|
additional_service_data=None,
|
||||||
return_value=None,
|
return_value=None,
|
||||||
):
|
) -> None:
|
||||||
"""Test generic Android media player entity service."""
|
"""Test generic Android media player entity service."""
|
||||||
service_data = {ATTR_ENTITY_ID: entity_id}
|
service_data = {ATTR_ENTITY_ID: entity_id}
|
||||||
if additional_service_data:
|
if additional_service_data:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user