From e6fda4b35785a65e1f3289b0af8518c4dc5e9a4a Mon Sep 17 00:00:00 2001 From: ollo69 <60491700+ollo69@users.noreply.github.com> Date: Mon, 6 May 2024 01:15:33 +0200 Subject: [PATCH] Store runtime data inside the config entry in AndroidTV (#116895) --- .../components/androidtv/__init__.py | 33 +++++++++++-------- homeassistant/components/androidtv/const.py | 3 -- .../components/androidtv/diagnostics.py | 9 +++-- homeassistant/components/androidtv/entity.py | 26 +++++++-------- .../components/androidtv/media_player.py | 28 +++++----------- 5 files changed, 43 insertions(+), 56 deletions(-) diff --git a/homeassistant/components/androidtv/__init__.py b/homeassistant/components/androidtv/__init__.py index 884a06bca68..dc7fd95519f 100644 --- a/homeassistant/components/androidtv/__init__.py +++ b/homeassistant/components/androidtv/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Mapping +from dataclasses import dataclass import os from typing import Any @@ -36,8 +37,6 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.storage import STORAGE_DIR from .const import ( - ANDROID_DEV, - ANDROID_DEV_OPT, CONF_ADB_SERVER_IP, CONF_ADB_SERVER_PORT, CONF_ADBKEY, @@ -45,7 +44,6 @@ from .const import ( DEFAULT_ADB_SERVER_PORT, DEVICE_ANDROIDTV, DEVICE_FIRETV, - DOMAIN, PROP_ETHMAC, PROP_WIFIMAC, SIGNAL_CONFIG_ENTITY, @@ -69,6 +67,17 @@ RELOAD_OPTIONS = [CONF_STATE_DETECTION_RULES] _INVALID_MACS = {"ff:ff:ff:ff:ff:ff"} +@dataclass +class AndroidTVRuntimeData: + """Runtime data definition.""" + + aftv: AndroidTVAsync | FireTVAsync + dev_opt: dict[str, Any] + + +AndroidTVConfigEntry = ConfigEntry[AndroidTVRuntimeData] + + def get_androidtv_mac(dev_props: dict[str, Any]) -> str | None: """Return formatted mac from device properties.""" for prop_mac in (PROP_ETHMAC, PROP_WIFIMAC): @@ -148,7 +157,7 @@ async def async_connect_androidtv( return aftv, None -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_setup_entry(hass: HomeAssistant, entry: AndroidTVConfigEntry) -> bool: """Set up Android Debug Bridge platform.""" state_det_rules = entry.options.get(CONF_STATE_DETECTION_RULES) @@ -176,30 +185,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) entry.async_on_unload(entry.add_update_listener(update_listener)) - hass.data.setdefault(DOMAIN, {})[entry.entry_id] = { - ANDROID_DEV: aftv, - ANDROID_DEV_OPT: entry.options.copy(), - } + entry.runtime_data = AndroidTVRuntimeData(aftv, entry.options.copy()) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: AndroidTVConfigEntry) -> bool: """Unload a config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - aftv = hass.data[DOMAIN][entry.entry_id][ANDROID_DEV] + aftv = entry.runtime_data.aftv await aftv.adb_close() - hass.data[DOMAIN].pop(entry.entry_id) return unload_ok -async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: +async def update_listener(hass: HomeAssistant, entry: AndroidTVConfigEntry) -> None: """Update when config_entry options update.""" reload_opt = False - old_options = hass.data[DOMAIN][entry.entry_id][ANDROID_DEV_OPT] + old_options = entry.runtime_data.dev_opt for opt_key, opt_val in entry.options.items(): if opt_key in RELOAD_OPTIONS: old_val = old_options.get(opt_key) @@ -211,5 +216,5 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: await hass.config_entries.async_reload(entry.entry_id) return - hass.data[DOMAIN][entry.entry_id][ANDROID_DEV_OPT] = entry.options.copy() + entry.runtime_data.dev_opt = entry.options.copy() async_dispatcher_send(hass, f"{SIGNAL_CONFIG_ENTITY}_{entry.entry_id}") diff --git a/homeassistant/components/androidtv/const.py b/homeassistant/components/androidtv/const.py index fb43e0af090..ee279c0fb3a 100644 --- a/homeassistant/components/androidtv/const.py +++ b/homeassistant/components/androidtv/const.py @@ -2,9 +2,6 @@ DOMAIN = "androidtv" -ANDROID_DEV = DOMAIN -ANDROID_DEV_OPT = "androidtv_opt" - CONF_ADB_SERVER_IP = "adb_server_ip" CONF_ADB_SERVER_PORT = "adb_server_port" CONF_ADBKEY = "adbkey" diff --git a/homeassistant/components/androidtv/diagnostics.py b/homeassistant/components/androidtv/diagnostics.py index 5dba4109f32..3e4244d6d9f 100644 --- a/homeassistant/components/androidtv/diagnostics.py +++ b/homeassistant/components/androidtv/diagnostics.py @@ -7,12 +7,12 @@ from typing import Any import attr from homeassistant.components.diagnostics import async_redact_data -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_CONNECTIONS, ATTR_IDENTIFIERS, CONF_UNIQUE_ID from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from .const import ANDROID_DEV, DOMAIN, PROP_ETHMAC, PROP_SERIALNO, PROP_WIFIMAC +from . import AndroidTVConfigEntry +from .const import DOMAIN, PROP_ETHMAC, PROP_SERIALNO, PROP_WIFIMAC TO_REDACT = {CONF_UNIQUE_ID} # UniqueID contain MAC Address TO_REDACT_DEV = {ATTR_CONNECTIONS, ATTR_IDENTIFIERS} @@ -20,14 +20,13 @@ TO_REDACT_DEV_PROP = {PROP_ETHMAC, PROP_SERIALNO, PROP_WIFIMAC} async def async_get_config_entry_diagnostics( - hass: HomeAssistant, entry: ConfigEntry + hass: HomeAssistant, entry: AndroidTVConfigEntry ) -> dict[str, dict[str, Any]]: """Return diagnostics for a config entry.""" data = {"entry": async_redact_data(entry.as_dict(), TO_REDACT)} - hass_data = hass.data[DOMAIN][entry.entry_id] # Get information from AndroidTV library - aftv = hass_data[ANDROID_DEV] + aftv = entry.runtime_data.aftv data["device_properties"] = { **async_redact_data(aftv.device_properties, TO_REDACT_DEV_PROP), "device_class": aftv.DEVICE_CLASS, diff --git a/homeassistant/components/androidtv/entity.py b/homeassistant/components/androidtv/entity.py index 2185f6d151a..0085dafe127 100644 --- a/homeassistant/components/androidtv/entity.py +++ b/homeassistant/components/androidtv/entity.py @@ -8,9 +8,7 @@ import logging from typing import Any, Concatenate, ParamSpec, TypeVar from androidtv.exceptions import LockNotAcquiredException -from androidtv.setup_async import AndroidTVAsync, FireTVAsync -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_CONNECTIONS, ATTR_IDENTIFIERS, @@ -23,7 +21,12 @@ from homeassistant.const import ( from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo from homeassistant.helpers.entity import Entity -from . import ADB_PYTHON_EXCEPTIONS, ADB_TCP_EXCEPTIONS, get_androidtv_mac +from . import ( + ADB_PYTHON_EXCEPTIONS, + ADB_TCP_EXCEPTIONS, + AndroidTVConfigEntry, + get_androidtv_mac, +) from .const import DEVICE_ANDROIDTV, DOMAIN PREFIX_ANDROIDTV = "Android TV" @@ -103,18 +106,13 @@ class AndroidTVEntity(Entity): _attr_has_entity_name = True - def __init__( - self, - aftv: AndroidTVAsync | FireTVAsync, - entry: ConfigEntry, - entry_data: dict[str, Any], - ) -> None: + def __init__(self, entry: AndroidTVConfigEntry) -> None: """Initialize the AndroidTV base entity.""" - self.aftv = aftv + self.aftv = entry.runtime_data.aftv self._attr_unique_id = entry.unique_id - self._entry_data = entry_data + self._entry_runtime_data = entry.runtime_data - device_class = aftv.DEVICE_CLASS + device_class = self.aftv.DEVICE_CLASS device_type = ( PREFIX_ANDROIDTV if device_class == DEVICE_ANDROIDTV else PREFIX_FIRETV ) @@ -122,7 +120,7 @@ class AndroidTVEntity(Entity): device_name = entry.data.get( CONF_NAME, f"{device_type} {entry.data[CONF_HOST]}" ) - info = aftv.device_properties + info = self.aftv.device_properties model = info.get(ATTR_MODEL) self._attr_device_info = DeviceInfo( model=f"{model} ({device_type})" if model else device_type, @@ -138,7 +136,7 @@ class AndroidTVEntity(Entity): self._attr_device_info[ATTR_CONNECTIONS] = {(CONNECTION_NETWORK_MAC, mac)} # ADB exceptions to catch - if not aftv.adb_server_ip: + if not self.aftv.adb_server_ip: # Using "adb_shell" (Python ADB implementation) self.exceptions = ADB_PYTHON_EXCEPTIONS else: diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index 016a7a5a7a2..884b5f60f57 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -18,7 +18,6 @@ from homeassistant.components.media_player import ( MediaPlayerEntityFeature, MediaPlayerState, ) -from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_COMMAND from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_platform @@ -26,9 +25,8 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util import Throttle +from . import AndroidTVConfigEntry from .const import ( - ANDROID_DEV, - ANDROID_DEV_OPT, CONF_APPS, CONF_EXCLUDE_UNNAMED_APPS, CONF_GET_SOURCES, @@ -39,7 +37,6 @@ from .const import ( DEFAULT_GET_SOURCES, DEFAULT_SCREENCAP, DEVICE_ANDROIDTV, - DOMAIN, SIGNAL_CONFIG_ENTITY, ) from .entity import AndroidTVEntity, adb_decorator @@ -70,20 +67,16 @@ ANDROIDTV_STATES = { async def async_setup_entry( hass: HomeAssistant, - entry: ConfigEntry, + entry: AndroidTVConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Android Debug Bridge entity.""" - entry_data = hass.data[DOMAIN][entry.entry_id] - aftv: AndroidTVAsync | FireTVAsync = entry_data[ANDROID_DEV] - - device_class = aftv.DEVICE_CLASS - device_args = [aftv, entry, entry_data] + device_class = entry.runtime_data.aftv.DEVICE_CLASS async_add_entities( [ - AndroidTVDevice(*device_args) + AndroidTVDevice(entry) if device_class == DEVICE_ANDROIDTV - else FireTVDevice(*device_args) + else FireTVDevice(entry) ] ) @@ -120,14 +113,9 @@ class ADBDevice(AndroidTVEntity, MediaPlayerEntity): _attr_device_class = MediaPlayerDeviceClass.TV _attr_name = None - def __init__( - self, - aftv: AndroidTVAsync | FireTVAsync, - entry: ConfigEntry, - entry_data: dict[str, Any], - ) -> None: + def __init__(self, entry: AndroidTVConfigEntry) -> None: """Initialize the Android / Fire TV device.""" - super().__init__(aftv, entry, entry_data) + super().__init__(entry) self._entry_id = entry.entry_id self._media_image: tuple[bytes | None, str | None] = None, None @@ -153,7 +141,7 @@ class ADBDevice(AndroidTVEntity, MediaPlayerEntity): def _process_config(self) -> None: """Load the config options.""" _LOGGER.debug("Loading configuration options") - options = self._entry_data[ANDROID_DEV_OPT] + options = self._entry_runtime_data.dev_opt apps = options.get(CONF_APPS, {}) self._app_id_to_name = APPS.copy()