Remove deprecated yaml config from androidtv (#68339)

This commit is contained in:
Robert Hillis 2022-03-22 23:45:35 -04:00 committed by GitHub
parent b2d7fe15bb
commit a11a5366be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 6 additions and 212 deletions

View file

@ -1,13 +1,11 @@
"""Support for functionality to interact with Android TV/Fire TV devices.""" """Support for functionality to interact with Android TV/Fire TV devices."""
import logging
import os import os
from adb_shell.auth.keygen import keygen from adb_shell.auth.keygen import keygen
from androidtv.adb_manager.adb_manager_sync import ADBPythonSync from androidtv.adb_manager.adb_manager_sync import ADBPythonSync
from androidtv.setup_async import setup from androidtv.setup_async import setup
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.config_entries import ConfigEntry
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
CONF_HOST, CONF_HOST,
@ -17,7 +15,6 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.device_registry import format_mac from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.storage import STORAGE_DIR from homeassistant.helpers.storage import STORAGE_DIR
@ -35,7 +32,6 @@ from .const import (
DEVICE_FIRETV, DEVICE_FIRETV,
DOMAIN, DOMAIN,
PROP_ETHMAC, PROP_ETHMAC,
PROP_SERIALNO,
PROP_WIFIMAC, PROP_WIFIMAC,
SIGNAL_CONFIG_ENTITY, SIGNAL_CONFIG_ENTITY,
) )
@ -45,8 +41,6 @@ RELOAD_OPTIONS = [CONF_STATE_DETECTION_RULES]
_INVALID_MACS = {"ff:ff:ff:ff:ff:ff"} _INVALID_MACS = {"ff:ff:ff:ff:ff:ff"}
_LOGGER = logging.getLogger(__name__)
def get_androidtv_mac(dev_props): def get_androidtv_mac(dev_props):
"""Return formatted mac from device properties.""" """Return formatted mac from device properties."""
@ -116,30 +110,6 @@ async def async_connect_androidtv(
return aftv, None return aftv, None
def _migrate_aftv_entity(hass, aftv, entry_unique_id):
"""Migrate a entity to new unique id."""
entity_reg = er.async_get(hass)
entity_unique_id = entry_unique_id
if entity_reg.async_get_entity_id(MP_DOMAIN, DOMAIN, entity_unique_id):
# entity already exist, nothing to do
return
if not (old_unique_id := aftv.device_properties.get(PROP_SERIALNO)):
# serial no not found, exit
return
migr_entity = entity_reg.async_get_entity_id(MP_DOMAIN, DOMAIN, old_unique_id)
if not migr_entity:
# old entity not found, exit
return
try:
entity_reg.async_update_entity(migr_entity, new_unique_id=entity_unique_id)
except ValueError as exp:
_LOGGER.warning("Migration of old entity failed: %s", exp)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Android TV integration.""" """Set up the Android TV integration."""
return True return True
@ -155,10 +125,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not aftv: if not aftv:
raise ConfigEntryNotReady(error_message) raise ConfigEntryNotReady(error_message)
# migrate existing entity to new unique ID
if entry.source == SOURCE_IMPORT:
_migrate_aftv_entity(hass, aftv, entry.unique_id)
async def async_close_connection(event): async def async_close_connection(event):
"""Close Android TV connection on HA Stop.""" """Close Android TV connection on HA Stop."""
await aftv.adb_close() await aftv.adb_close()

View file

@ -20,7 +20,6 @@ from .const import (
CONF_APPS, CONF_APPS,
CONF_EXCLUDE_UNNAMED_APPS, CONF_EXCLUDE_UNNAMED_APPS,
CONF_GET_SOURCES, CONF_GET_SOURCES,
CONF_MIGRATION_OPTIONS,
CONF_SCREENCAP, CONF_SCREENCAP,
CONF_STATE_DETECTION_RULES, CONF_STATE_DETECTION_RULES,
CONF_TURN_OFF_COMMAND, CONF_TURN_OFF_COMMAND,
@ -72,10 +71,6 @@ class AndroidTVFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1 VERSION = 1
def __init__(self):
"""Initialize AndroidTV config flow."""
self._import_options = None
@callback @callback
def _show_setup_form(self, user_input=None, error=None): def _show_setup_form(self, user_input=None, error=None):
"""Show the setup form to the user.""" """Show the setup form to the user."""
@ -171,24 +166,11 @@ class AndroidTVFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_create_entry( return self.async_create_entry(
title=user_input.get(CONF_NAME) or host, title=user_input.get(CONF_NAME) or host,
data=user_input, data=user_input,
options=self._import_options,
) )
user_input = user_input or {} user_input = user_input or {}
return self._show_setup_form(user_input, error) return self._show_setup_form(user_input, error)
async def async_step_import(self, import_config=None):
"""Import a config entry."""
for entry in self._async_current_entries():
if entry.data[CONF_HOST] == import_config[CONF_HOST]:
_LOGGER.warning(
"Host [%s] already configured. This yaml configuration has already been imported. Please remove it",
import_config[CONF_HOST],
)
return self.async_abort(reason="already_configured")
self._import_options = import_config.pop(CONF_MIGRATION_OPTIONS, None)
return await self.async_step_user(import_config)
@staticmethod @staticmethod
@callback @callback
def async_get_options_flow(config_entry): def async_get_options_flow(config_entry):

View file

@ -10,7 +10,6 @@ CONF_ADBKEY = "adbkey"
CONF_APPS = "apps" CONF_APPS = "apps"
CONF_EXCLUDE_UNNAMED_APPS = "exclude_unnamed_apps" CONF_EXCLUDE_UNNAMED_APPS = "exclude_unnamed_apps"
CONF_GET_SOURCES = "get_sources" CONF_GET_SOURCES = "get_sources"
CONF_MIGRATION_OPTIONS = "migration_options"
CONF_SCREENCAP = "screencap" CONF_SCREENCAP = "screencap"
CONF_STATE_DETECTION_RULES = "state_detection_rules" CONF_STATE_DETECTION_RULES = "state_detection_rules"
CONF_TURN_OFF_COMMAND = "turn_off_command" CONF_TURN_OFF_COMMAND = "turn_off_command"
@ -28,7 +27,6 @@ DEVICE_FIRETV = "firetv"
DEVICE_CLASSES = [DEFAULT_DEVICE_CLASS, DEVICE_ANDROIDTV, DEVICE_FIRETV] DEVICE_CLASSES = [DEFAULT_DEVICE_CLASS, DEVICE_ANDROIDTV, DEVICE_FIRETV]
PROP_ETHMAC = "ethmac" PROP_ETHMAC = "ethmac"
PROP_SERIALNO = "serialno"
PROP_WIFIMAC = "wifimac" PROP_WIFIMAC = "wifimac"
SIGNAL_CONFIG_ENTITY = "androidtv_config" SIGNAL_CONFIG_ENTITY = "androidtv_config"

View file

@ -12,13 +12,12 @@ from adb_shell.exceptions import (
InvalidResponseError, InvalidResponseError,
TcpTimeoutException, TcpTimeoutException,
) )
from androidtv import ha_state_detection_rules_validator
from androidtv.constants import APPS, KEYS from androidtv.constants import APPS, KEYS
from androidtv.exceptions import LockNotAcquiredException from androidtv.exceptions import LockNotAcquiredException
import voluptuous as vol import voluptuous as vol
from homeassistant.components import persistent_notification from homeassistant.components import persistent_notification
from homeassistant.components.media_player import PLATFORM_SCHEMA, MediaPlayerEntity from homeassistant.components.media_player import MediaPlayerEntity
from homeassistant.components.media_player.const import ( from homeassistant.components.media_player.const import (
SUPPORT_NEXT_TRACK, SUPPORT_NEXT_TRACK,
SUPPORT_PAUSE, SUPPORT_PAUSE,
@ -32,17 +31,14 @@ from homeassistant.components.media_player.const import (
SUPPORT_VOLUME_SET, SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP, SUPPORT_VOLUME_STEP,
) )
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_COMMAND, ATTR_COMMAND,
ATTR_CONNECTIONS, ATTR_CONNECTIONS,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
ATTR_MODEL, ATTR_MODEL,
ATTR_SW_VERSION, ATTR_SW_VERSION,
CONF_DEVICE_CLASS,
CONF_HOST, CONF_HOST,
CONF_NAME,
CONF_PORT,
STATE_IDLE, STATE_IDLE,
STATE_OFF, STATE_OFF,
STATE_PAUSED, STATE_PAUSED,
@ -55,31 +51,21 @@ from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import get_androidtv_mac from . import get_androidtv_mac
from .const import ( from .const import (
ANDROID_DEV, ANDROID_DEV,
ANDROID_DEV_OPT, ANDROID_DEV_OPT,
CONF_ADB_SERVER_IP,
CONF_ADB_SERVER_PORT,
CONF_ADBKEY,
CONF_APPS, CONF_APPS,
CONF_EXCLUDE_UNNAMED_APPS, CONF_EXCLUDE_UNNAMED_APPS,
CONF_GET_SOURCES, CONF_GET_SOURCES,
CONF_MIGRATION_OPTIONS,
CONF_SCREENCAP, CONF_SCREENCAP,
CONF_STATE_DETECTION_RULES,
CONF_TURN_OFF_COMMAND, CONF_TURN_OFF_COMMAND,
CONF_TURN_ON_COMMAND, CONF_TURN_ON_COMMAND,
DEFAULT_ADB_SERVER_PORT,
DEFAULT_DEVICE_CLASS,
DEFAULT_EXCLUDE_UNNAMED_APPS, DEFAULT_EXCLUDE_UNNAMED_APPS,
DEFAULT_GET_SOURCES, DEFAULT_GET_SOURCES,
DEFAULT_PORT,
DEFAULT_SCREENCAP, DEFAULT_SCREENCAP,
DEVICE_ANDROIDTV, DEVICE_ANDROIDTV,
DEVICE_CLASSES,
DOMAIN, DOMAIN,
SIGNAL_CONFIG_ENTITY, SIGNAL_CONFIG_ENTITY,
) )
@ -123,34 +109,6 @@ SERVICE_UPLOAD = "upload"
DEFAULT_NAME = "Android TV" DEFAULT_NAME = "Android TV"
# Deprecated in Home Assistant 2022.2
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_DEVICE_CLASS, default=DEFAULT_DEVICE_CLASS): vol.In(
DEVICE_CLASSES
),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_ADBKEY): cv.isfile,
vol.Optional(CONF_ADB_SERVER_IP): cv.string,
vol.Optional(CONF_ADB_SERVER_PORT, default=DEFAULT_ADB_SERVER_PORT): cv.port,
vol.Optional(CONF_GET_SOURCES, default=DEFAULT_GET_SOURCES): cv.boolean,
vol.Optional(CONF_APPS, default={}): vol.Schema(
{cv.string: vol.Any(cv.string, None)}
),
vol.Optional(CONF_TURN_ON_COMMAND): cv.string,
vol.Optional(CONF_TURN_OFF_COMMAND): cv.string,
vol.Optional(CONF_STATE_DETECTION_RULES, default={}): vol.Schema(
{cv.string: ha_state_detection_rules_validator(vol.Invalid)}
),
vol.Optional(
CONF_EXCLUDE_UNNAMED_APPS, default=DEFAULT_EXCLUDE_UNNAMED_APPS
): cv.boolean,
vol.Optional(CONF_SCREENCAP, default=DEFAULT_SCREENCAP): cv.boolean,
}
)
# Translate from `AndroidTV` / `FireTV` reported state to HA state. # Translate from `AndroidTV` / `FireTV` reported state to HA state.
ANDROIDTV_STATES = { ANDROIDTV_STATES = {
"off": STATE_OFF, "off": STATE_OFF,
@ -161,53 +119,6 @@ ANDROIDTV_STATES = {
} }
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Android TV / Fire TV platform."""
host = config[CONF_HOST]
# get main data
config_data = {
CONF_HOST: host,
CONF_DEVICE_CLASS: config.get(CONF_DEVICE_CLASS, DEFAULT_DEVICE_CLASS),
CONF_PORT: config.get(CONF_PORT, DEFAULT_PORT),
}
for key in (CONF_ADBKEY, CONF_ADB_SERVER_IP, CONF_ADB_SERVER_PORT, CONF_NAME):
if key in config:
config_data[key] = config[key]
# get options
config_options = {
key: config[key]
for key in (
CONF_APPS,
CONF_EXCLUDE_UNNAMED_APPS,
CONF_GET_SOURCES,
CONF_SCREENCAP,
CONF_STATE_DETECTION_RULES,
CONF_TURN_OFF_COMMAND,
CONF_TURN_ON_COMMAND,
)
if key in config
}
# save option to use with entry
if config_options:
config_data[CONF_MIGRATION_OPTIONS] = config_options
# Launch config entries setup
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=config_data
)
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
entry: ConfigEntry, entry: ConfigEntry,
@ -217,9 +128,6 @@ async def async_setup_entry(
aftv = hass.data[DOMAIN][entry.entry_id][ANDROID_DEV] aftv = hass.data[DOMAIN][entry.entry_id][ANDROID_DEV]
device_class = aftv.DEVICE_CLASS device_class = aftv.DEVICE_CLASS
device_type = "Android TV" if device_class == DEVICE_ANDROIDTV else "Fire TV" device_type = "Android TV" if device_class == DEVICE_ANDROIDTV else "Fire TV"
if CONF_NAME in entry.data:
device_name = entry.data[CONF_NAME]
else:
device_name = f"{device_type} {entry.data[CONF_HOST]}" device_name = f"{device_type} {entry.data[CONF_HOST]}"
device_args = [ device_args = [

View file

@ -33,10 +33,8 @@ from homeassistant.components.androidtv.const import (
PROP_ETHMAC, PROP_ETHMAC,
PROP_WIFIMAC, PROP_WIFIMAC,
) )
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.config_entries import SOURCE_USER
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER from homeassistant.const import CONF_DEVICE_CLASS, CONF_HOST, CONF_PORT
from homeassistant.const import CONF_DEVICE_CLASS, CONF_HOST, CONF_PLATFORM, CONF_PORT
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
from tests.components.androidtv.patchers import isfile from tests.components.androidtv.patchers import isfile
@ -132,28 +130,6 @@ async def test_user(hass, config, eth_mac, wifi_mac):
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
async def test_import(hass):
"""Test import config."""
# test with all provided
with patch(
CONNECT_METHOD,
return_value=(MockConfigDevice(), None),
), PATCH_SETUP_ENTRY as mock_setup_entry, PATCH_GET_HOST_IP:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=CONFIG_PYTHON_ADB,
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == HOST
assert result["data"] == CONFIG_PYTHON_ADB
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_adbkey(hass): async def test_user_adbkey(hass):
"""Test user step with adbkey file.""" """Test user step with adbkey file."""
config_data = CONFIG_PYTHON_ADB.copy() config_data = CONFIG_PYTHON_ADB.copy()
@ -178,25 +154,6 @@ async def test_user_adbkey(hass):
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
async def test_import_data(hass):
"""Test import from configuration file."""
config_data = CONFIG_PYTHON_ADB.copy()
config_data[CONF_PLATFORM] = DOMAIN
config_data[CONF_ADBKEY] = ADBKEY
config_data[CONF_TURN_OFF_COMMAND] = "off"
platform_data = {MP_DOMAIN: config_data}
with patch(
CONNECT_METHOD,
return_value=(MockConfigDevice(), None),
), PATCH_SETUP_ENTRY as mock_setup_entry, PATCH_GET_HOST_IP, PATCH_ISFILE, PATCH_ACCESS:
assert await async_setup_component(hass, MP_DOMAIN, platform_data)
await hass.async_block_till_done()
assert len(mock_setup_entry.mock_calls) == 1
async def test_error_both_key_server(hass): async def test_error_both_key_server(hass):
"""Test we abort if both adb key and server are provided.""" """Test we abort if both adb key and server are provided."""
config_data = CONFIG_ADB_SERVER.copy() config_data = CONFIG_ADB_SERVER.copy()
@ -317,23 +274,6 @@ async def test_abort_if_host_exist(hass):
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
async def test_abort_import_if_host_exist(hass):
"""Test we abort if component is already setup."""
MockConfigEntry(
domain=DOMAIN, data=CONFIG_ADB_SERVER, unique_id=ETH_MAC
).add_to_hass(hass)
# Should fail, same Host in entry
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=CONFIG_ADB_SERVER,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
async def test_abort_if_unique_exist(hass): async def test_abort_if_unique_exist(hass):
"""Test we abort if component is already setup.""" """Test we abort if component is already setup."""
config_data = CONFIG_ADB_SERVER.copy() config_data = CONFIG_ADB_SERVER.copy()