"""Shared config helpers for the NVIDIA Shield integration.""" import os from dataclasses import dataclass from homeassistant.core import HomeAssistant from .const import ( CONF_ADB_ENABLED, CONF_ADB_HOST, CONF_ADB_PORT, CONF_HOST, CONF_PROTOCOL_HOST, DEFAULT_ADB_PORT, DOMAIN, ) @dataclass class AdbConfig: """Resolved ADB connection settings for a config entry.""" host: str port: int key_path: str def adb_key_path(hass: HomeAssistant) -> str: """Path of the ADB private key for this integration (may not exist yet).""" return os.path.join(hass.config.config_dir, ".storage", DOMAIN, "adbkey") def protocol_cert_paths(hass: HomeAssistant) -> tuple[str, str]: """Local (certfile, keyfile) paths for the remote protocol client. Mirrors core androidtv_remote's storage pattern: private material under ``.storage//``. Shared between config-flow pairing and runtime — an entry aborts duplicate setup by unique_id (= device MAC), so one pair of files suffices per install. """ base = os.path.join(hass.config.config_dir, ".storage", DOMAIN) os.makedirs(base, exist_ok=True) return os.path.join(base, "client.pem"), os.path.join(base, "client.key") def entry_host(entry) -> str: """The Shield's address for an entry (t41: ONE field). ``options`` is the source of truth; ``data`` is read as a fallback so an entry created by an older flow (or a hand-written seed) still resolves. """ options = getattr(entry, "options", None) or {} data = getattr(entry, "data", None) or {} return str(options.get(CONF_HOST) or data.get(CONF_HOST) or "").strip() def seed_host(block: dict) -> str: """The address a YAML seed block carries (t41). ``host`` is the current key; the legacy ``protocol_host`` / ``adb_host`` stay accepted so an existing configuration.yaml keeps seeding, protocol first (that transport is the one that cannot fall back to anything else). """ for key in (CONF_HOST, CONF_PROTOCOL_HOST, CONF_ADB_HOST): value = str((block or {}).get(key) or "").strip() if value: return value return "" def seed_adb_enabled(block: dict) -> bool: """Does a seed block ask for ADB? (t32 F4's shape rule, t41's keys). An explicit ``adb_enabled`` wins. Otherwise an address that names the Shield — the current ``host`` key or the legacy ``adb_host`` — turns ADB on, while a protocol-only block leaves it off. """ block = block or {} if CONF_ADB_ENABLED in block: return bool(block[CONF_ADB_ENABLED]) return bool(block.get(CONF_HOST) or block.get(CONF_ADB_HOST)) def resolve_adb_config(hass: HomeAssistant, entry) -> AdbConfig | None: """Resolve host/port/key_path for the entry's ADB connection, or None. Priority: the entry's own address (t41: no other integration is consulted) and its ADB port option. """ host = entry_host(entry) if not host: return None port = int(entry.options.get(CONF_ADB_PORT, DEFAULT_ADB_PORT)) return AdbConfig(host=host, port=port, key_path=adb_key_path(hass))