"""Helper functions for webOS Smart TV.""" from __future__ import annotations from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.device_registry import DeviceEntry from . import WebOsClientWrapper, async_control_connect from .const import DATA_CONFIG_ENTRY, DOMAIN, LIVE_TV_APP_ID, WEBOSTV_EXCEPTIONS @callback def async_get_device_entry_by_device_id( hass: HomeAssistant, device_id: str ) -> DeviceEntry: """ Get Device Entry from Device Registry by device ID. Raises ValueError if device ID is invalid. """ device_reg = dr.async_get(hass) if (device := device_reg.async_get(device_id)) is None: raise ValueError(f"Device {device_id} is not a valid {DOMAIN} device.") return device @callback def async_is_device_config_entry_not_loaded( hass: HomeAssistant, device_id: str ) -> bool: """Return whether device's config entries are not loaded.""" device = async_get_device_entry_by_device_id(hass, device_id) return any( (entry := hass.config_entries.async_get_entry(entry_id)) and entry.state != ConfigEntryState.LOADED for entry_id in device.config_entries ) @callback def async_get_device_id_from_entity_id(hass: HomeAssistant, entity_id: str) -> str: """ Get device ID from an entity ID. Raises ValueError if entity or device ID is invalid. """ ent_reg = er.async_get(hass) entity_entry = ent_reg.async_get(entity_id) if ( entity_entry is None or entity_entry.device_id is None or entity_entry.platform != DOMAIN ): raise ValueError(f"Entity {entity_id} is not a valid {DOMAIN} entity.") return entity_entry.device_id @callback def async_get_client_wrapper_by_device_entry( hass: HomeAssistant, device: DeviceEntry ) -> WebOsClientWrapper: """ Get WebOsClientWrapper from Device Registry by device entry. Raises ValueError if client wrapper is not found. """ for config_entry_id in device.config_entries: wrapper: WebOsClientWrapper | None if wrapper := hass.data[DOMAIN][DATA_CONFIG_ENTRY].get(config_entry_id): break if not wrapper: raise ValueError( f"Device {device.id} is not from an existing {DOMAIN} config entry" ) return wrapper async def async_get_sources(host: str, key: str) -> list[str]: """Construct sources list.""" try: client = await async_control_connect(host, key) except WEBOSTV_EXCEPTIONS: return [] sources = [] found_live_tv = False for app in client.apps.values(): sources.append(app["title"]) if app["id"] == LIVE_TV_APP_ID: found_live_tv = True for source in client.inputs.values(): sources.append(source["label"]) if source["appId"] == LIVE_TV_APP_ID: found_live_tv = True if not found_live_tv: sources.append("Live TV") # Preserve order when filtering duplicates return list(dict.fromkeys(sources))