mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Bump androidtv to 0.0.28 (#26906)
* Bump androidtv to 0.0.28 * Address reviewer comments * Remove adb-shell from requirements_test_all.txt * Use a one-liner to avoid a coverage failure
This commit is contained in:
parent
b04a70995e
commit
45c548ae47
@ -3,7 +3,8 @@
|
|||||||
"name": "Androidtv",
|
"name": "Androidtv",
|
||||||
"documentation": "https://www.home-assistant.io/components/androidtv",
|
"documentation": "https://www.home-assistant.io/components/androidtv",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"androidtv==0.0.27"
|
"adb-shell==0.0.2",
|
||||||
|
"androidtv==0.0.28"
|
||||||
],
|
],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@JeffLIrion"]
|
"codeowners": ["@JeffLIrion"]
|
||||||
|
@ -3,6 +3,12 @@ import functools
|
|||||||
import logging
|
import logging
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from adb_shell.exceptions import (
|
||||||
|
InvalidChecksumError,
|
||||||
|
InvalidCommandError,
|
||||||
|
InvalidResponseError,
|
||||||
|
TcpTimeoutException,
|
||||||
|
)
|
||||||
from androidtv import setup, ha_state_detection_rules_validator
|
from androidtv import setup, ha_state_detection_rules_validator
|
||||||
from androidtv.constants import APPS, KEYS
|
from androidtv.constants import APPS, KEYS
|
||||||
|
|
||||||
@ -123,11 +129,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
"""Set up the Android TV / Fire TV platform."""
|
"""Set up the Android TV / Fire TV platform."""
|
||||||
hass.data.setdefault(ANDROIDTV_DOMAIN, {})
|
hass.data.setdefault(ANDROIDTV_DOMAIN, {})
|
||||||
|
|
||||||
host = "{0}:{1}".format(config[CONF_HOST], config[CONF_PORT])
|
host = f"{config[CONF_HOST]}:{config[CONF_PORT]}"
|
||||||
|
|
||||||
if CONF_ADB_SERVER_IP not in config:
|
if CONF_ADB_SERVER_IP not in config:
|
||||||
# Use "python-adb" (Python ADB implementation)
|
# Use "adb_shell" (Python ADB implementation)
|
||||||
adb_log = "using Python ADB implementation "
|
adb_log = "using Python ADB implementation " + (
|
||||||
|
f"with adbkey='{config[CONF_ADBKEY]}'"
|
||||||
|
if CONF_ADBKEY in config
|
||||||
|
else "without adbkey authentication"
|
||||||
|
)
|
||||||
if CONF_ADBKEY in config:
|
if CONF_ADBKEY in config:
|
||||||
aftv = setup(
|
aftv = setup(
|
||||||
host,
|
host,
|
||||||
@ -135,7 +145,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
device_class=config[CONF_DEVICE_CLASS],
|
device_class=config[CONF_DEVICE_CLASS],
|
||||||
state_detection_rules=config[CONF_STATE_DETECTION_RULES],
|
state_detection_rules=config[CONF_STATE_DETECTION_RULES],
|
||||||
)
|
)
|
||||||
adb_log += "with adbkey='{0}'".format(config[CONF_ADBKEY])
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
aftv = setup(
|
aftv = setup(
|
||||||
@ -143,7 +152,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
device_class=config[CONF_DEVICE_CLASS],
|
device_class=config[CONF_DEVICE_CLASS],
|
||||||
state_detection_rules=config[CONF_STATE_DETECTION_RULES],
|
state_detection_rules=config[CONF_STATE_DETECTION_RULES],
|
||||||
)
|
)
|
||||||
adb_log += "without adbkey authentication"
|
|
||||||
else:
|
else:
|
||||||
# Use "pure-python-adb" (communicate with ADB server)
|
# Use "pure-python-adb" (communicate with ADB server)
|
||||||
aftv = setup(
|
aftv = setup(
|
||||||
@ -153,9 +161,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||||||
device_class=config[CONF_DEVICE_CLASS],
|
device_class=config[CONF_DEVICE_CLASS],
|
||||||
state_detection_rules=config[CONF_STATE_DETECTION_RULES],
|
state_detection_rules=config[CONF_STATE_DETECTION_RULES],
|
||||||
)
|
)
|
||||||
adb_log = "using ADB server at {0}:{1}".format(
|
adb_log = f"using ADB server at {config[CONF_ADB_SERVER_IP]}:{config[CONF_ADB_SERVER_PORT]}"
|
||||||
config[CONF_ADB_SERVER_IP], config[CONF_ADB_SERVER_PORT]
|
|
||||||
)
|
|
||||||
|
|
||||||
if not aftv.available:
|
if not aftv.available:
|
||||||
# Determine the name that will be used for the device in the log
|
# Determine the name that will be used for the device in the log
|
||||||
@ -251,6 +257,7 @@ def adb_decorator(override_available=False):
|
|||||||
"establishing attempt in the next update. Error: %s",
|
"establishing attempt in the next update. Error: %s",
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
|
self.aftv.adb.close()
|
||||||
self._available = False # pylint: disable=protected-access
|
self._available = False # pylint: disable=protected-access
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -278,14 +285,7 @@ class ADBDevice(MediaPlayerDevice):
|
|||||||
|
|
||||||
# ADB exceptions to catch
|
# ADB exceptions to catch
|
||||||
if not self.aftv.adb_server_ip:
|
if not self.aftv.adb_server_ip:
|
||||||
# Using "python-adb" (Python ADB implementation)
|
# Using "adb_shell" (Python ADB implementation)
|
||||||
from adb.adb_protocol import (
|
|
||||||
InvalidChecksumError,
|
|
||||||
InvalidCommandError,
|
|
||||||
InvalidResponseError,
|
|
||||||
)
|
|
||||||
from adb.usb_exceptions import TcpTimeoutException
|
|
||||||
|
|
||||||
self.exceptions = (
|
self.exceptions = (
|
||||||
AttributeError,
|
AttributeError,
|
||||||
BrokenPipeError,
|
BrokenPipeError,
|
||||||
|
@ -111,6 +111,9 @@ adafruit-blinka==1.2.1
|
|||||||
# homeassistant.components.mcp23017
|
# homeassistant.components.mcp23017
|
||||||
adafruit-circuitpython-mcp230xx==1.1.2
|
adafruit-circuitpython-mcp230xx==1.1.2
|
||||||
|
|
||||||
|
# homeassistant.components.androidtv
|
||||||
|
adb-shell==0.0.2
|
||||||
|
|
||||||
# homeassistant.components.adguard
|
# homeassistant.components.adguard
|
||||||
adguardhome==0.2.1
|
adguardhome==0.2.1
|
||||||
|
|
||||||
@ -197,7 +200,7 @@ ambiclimate==0.2.1
|
|||||||
amcrest==1.5.3
|
amcrest==1.5.3
|
||||||
|
|
||||||
# homeassistant.components.androidtv
|
# homeassistant.components.androidtv
|
||||||
androidtv==0.0.27
|
androidtv==0.0.28
|
||||||
|
|
||||||
# homeassistant.components.anel_pwrctrl
|
# homeassistant.components.anel_pwrctrl
|
||||||
anel_pwrctrl-homeassistant==0.0.1.dev2
|
anel_pwrctrl-homeassistant==0.0.1.dev2
|
||||||
|
@ -80,7 +80,7 @@ aiowwlln==2.0.2
|
|||||||
ambiclimate==0.2.1
|
ambiclimate==0.2.1
|
||||||
|
|
||||||
# homeassistant.components.androidtv
|
# homeassistant.components.androidtv
|
||||||
androidtv==0.0.27
|
androidtv==0.0.28
|
||||||
|
|
||||||
# homeassistant.components.apns
|
# homeassistant.components.apns
|
||||||
apns2==0.3.0
|
apns2==0.3.0
|
||||||
|
@ -4,34 +4,24 @@ from socket import error as socket_error
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
class AdbCommandsFake:
|
class AdbDeviceFake:
|
||||||
"""A fake of the `adb.adb_commands.AdbCommands` class."""
|
"""A fake of the `adb_shell.adb_device.AdbDevice` class."""
|
||||||
|
|
||||||
def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialize a fake `adb_shell.adb_device.AdbDevice` instance."""
|
||||||
|
self.available = False
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Close the socket connection."""
|
||||||
|
self.available = False
|
||||||
|
|
||||||
|
def connect(self, *args, **kwargs):
|
||||||
"""Try to connect to a device."""
|
"""Try to connect to a device."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def Shell(self, cmd): # pylint: disable=invalid-name
|
def shell(self, cmd):
|
||||||
"""Send an ADB shell command."""
|
"""Send an ADB shell command."""
|
||||||
raise NotImplementedError
|
return None
|
||||||
|
|
||||||
|
|
||||||
class AdbCommandsFakeSuccess(AdbCommandsFake):
|
|
||||||
"""A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt succeeds."""
|
|
||||||
|
|
||||||
def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name
|
|
||||||
"""Successfully connect to a device."""
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
class AdbCommandsFakeFail(AdbCommandsFake):
|
|
||||||
"""A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt fails."""
|
|
||||||
|
|
||||||
def ConnectDevice(
|
|
||||||
self, *args, **kwargs
|
|
||||||
): # pylint: disable=invalid-name, no-self-use
|
|
||||||
"""Fail to connect to a device."""
|
|
||||||
raise socket_error
|
|
||||||
|
|
||||||
|
|
||||||
class ClientFakeSuccess:
|
class ClientFakeSuccess:
|
||||||
@ -85,31 +75,39 @@ class DeviceFake:
|
|||||||
|
|
||||||
|
|
||||||
def patch_connect(success):
|
def patch_connect(success):
|
||||||
"""Mock the `adb.adb_commands.AdbCommands` and `adb_messenger.client.Client` classes."""
|
"""Mock the `adb_shell.adb_device.AdbDevice` and `adb_messenger.client.Client` classes."""
|
||||||
|
|
||||||
|
def connect_success_python(self, *args, **kwargs):
|
||||||
|
"""Mock the `AdbDeviceFake.connect` method when it succeeds."""
|
||||||
|
self.available = True
|
||||||
|
|
||||||
|
def connect_fail_python(self, *args, **kwargs):
|
||||||
|
"""Mock the `AdbDeviceFake.connect` method when it fails."""
|
||||||
|
raise socket_error
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
return {
|
return {
|
||||||
"python": patch(
|
"python": patch(
|
||||||
"androidtv.adb_manager.AdbCommands", AdbCommandsFakeSuccess
|
f"{__name__}.AdbDeviceFake.connect", connect_success_python
|
||||||
),
|
),
|
||||||
"server": patch("androidtv.adb_manager.Client", ClientFakeSuccess),
|
"server": patch("androidtv.adb_manager.Client", ClientFakeSuccess),
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
"python": patch("androidtv.adb_manager.AdbCommands", AdbCommandsFakeFail),
|
"python": patch(f"{__name__}.AdbDeviceFake.connect", connect_fail_python),
|
||||||
"server": patch("androidtv.adb_manager.Client", ClientFakeFail),
|
"server": patch("androidtv.adb_manager.Client", ClientFakeFail),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def patch_shell(response=None, error=False):
|
def patch_shell(response=None, error=False):
|
||||||
"""Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods."""
|
"""Mock the `AdbDeviceFake.shell` and `DeviceFake.shell` methods."""
|
||||||
|
|
||||||
def shell_success(self, cmd):
|
def shell_success(self, cmd):
|
||||||
"""Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods when they are successful."""
|
"""Mock the `AdbDeviceFake.shell` and `DeviceFake.shell` methods when they are successful."""
|
||||||
self.shell_cmd = cmd
|
self.shell_cmd = cmd
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def shell_fail_python(self, cmd):
|
def shell_fail_python(self, cmd):
|
||||||
"""Mock the `AdbCommandsFake.Shell` method when it fails."""
|
"""Mock the `AdbDeviceFake.shell` method when it fails."""
|
||||||
self.shell_cmd = cmd
|
self.shell_cmd = cmd
|
||||||
raise AttributeError
|
raise AttributeError
|
||||||
|
|
||||||
@ -120,10 +118,13 @@ def patch_shell(response=None, error=False):
|
|||||||
|
|
||||||
if not error:
|
if not error:
|
||||||
return {
|
return {
|
||||||
"python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_success),
|
"python": patch(f"{__name__}.AdbDeviceFake.shell", shell_success),
|
||||||
"server": patch(f"{__name__}.DeviceFake.shell", shell_success),
|
"server": patch(f"{__name__}.DeviceFake.shell", shell_success),
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
"python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_fail_python),
|
"python": patch(f"{__name__}.AdbDeviceFake.shell", shell_fail_python),
|
||||||
"server": patch(f"{__name__}.DeviceFake.shell", shell_fail_server),
|
"server": patch(f"{__name__}.DeviceFake.shell", shell_fail_server),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PATCH_ADB_DEVICE = patch("androidtv.adb_manager.AdbDevice", AdbDeviceFake)
|
||||||
|
@ -79,7 +79,9 @@ async def _test_reconnect(hass, caplog, config):
|
|||||||
else:
|
else:
|
||||||
entity_id = "media_player.fire_tv"
|
entity_id = "media_player.fire_tv"
|
||||||
|
|
||||||
with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]:
|
with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[
|
||||||
|
patch_key
|
||||||
|
], patchers.patch_shell("")[patch_key]:
|
||||||
assert await async_setup_component(hass, DOMAIN, config)
|
assert await async_setup_component(hass, DOMAIN, config)
|
||||||
await hass.helpers.entity_component.async_update_entity(entity_id)
|
await hass.helpers.entity_component.async_update_entity(entity_id)
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
@ -151,7 +153,9 @@ async def _test_adb_shell_returns_none(hass, config):
|
|||||||
else:
|
else:
|
||||||
entity_id = "media_player.fire_tv"
|
entity_id = "media_player.fire_tv"
|
||||||
|
|
||||||
with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]:
|
with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[
|
||||||
|
patch_key
|
||||||
|
], patchers.patch_shell("")[patch_key]:
|
||||||
assert await async_setup_component(hass, DOMAIN, config)
|
assert await async_setup_component(hass, DOMAIN, config)
|
||||||
await hass.helpers.entity_component.async_update_entity(entity_id)
|
await hass.helpers.entity_component.async_update_entity(entity_id)
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user