Skip to content

Commit

Permalink
Review config and device_info initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
ollo69 committed Nov 5, 2023
1 parent ccd70e9 commit f73be3c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 98 deletions.
78 changes: 19 additions & 59 deletions custom_components/samsungtv_smart/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@
)
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.storage import STORAGE_DIR
from homeassistant.helpers.typing import ConfigType

Expand All @@ -48,9 +46,7 @@
ATTR_DEVICE_OS,
CONF_APP_LIST,
CONF_CHANNEL_LIST,
CONF_DEVICE_MODEL,
CONF_DEVICE_NAME,
CONF_DEVICE_OS,
CONF_LOAD_ALL_APPS,
CONF_SCAN_APP_HTTP,
CONF_SHOW_CHANNEL_NR,
Expand All @@ -60,8 +56,8 @@
CONF_UPDATE_CUSTOM_PING_URL,
CONF_UPDATE_METHOD,
CONF_WS_NAME,
DATA_CFG,
DATA_CFG_YAML,
DATA_DEV_INFO,
DATA_OPTIONS,
DEFAULT_PORT,
DEFAULT_SOURCE_LIST,
Expand Down Expand Up @@ -540,16 +536,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_migrate_options_format(hass, entry)

# setup entry
hass.data.setdefault(DOMAIN, {}).setdefault(entry.entry_id, {})
if DATA_CFG_YAML in hass.data[DOMAIN][entry.entry_id]:
mac_addr = hass.data[DOMAIN][entry.entry_id][DATA_CFG_YAML].get(CONF_MAC)
else:
mac_addr = None
if DOMAIN not in hass.data:
hass.data[DOMAIN] = {}

hass.data[DOMAIN][entry.entry_id][DATA_DEV_INFO] = SamsungTVDeviceInfo(
entry.data, entry.entry_id, mac_addr
)
hass.data[DOMAIN][entry.entry_id][DATA_OPTIONS] = entry.options.copy()
add_conf = None
config = entry.data.copy()
if entry.entry_id in hass.data[DOMAIN]:
add_conf = hass.data[DOMAIN][entry.entry_id].get(DATA_CFG_YAML, {})
for attr, value in add_conf.items():
if value:
config[attr] = value

# setup entry
hass.data[DOMAIN][entry.entry_id] = {
DATA_CFG: config,
DATA_OPTIONS: entry.options.copy(),
}
if add_conf:
hass.data[DOMAIN][entry.entry_id][DATA_CFG_YAML] = add_conf
entry.async_on_unload(entry.add_update_listener(_update_listener))

await hass.config_entries.async_forward_entry_setups(entry, SAMSMART_PLATFORM)
Expand All @@ -562,6 +566,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if unload_ok := await hass.config_entries.async_unload_platforms(
entry, SAMSMART_PLATFORM
):
hass.data[DOMAIN][entry.entry_id].pop(DATA_CFG)
hass.data[DOMAIN][entry.entry_id].pop(DATA_OPTIONS)
if not hass.data[DOMAIN][entry.entry_id]:
hass.data[DOMAIN].pop(entry.entry_id)
Expand All @@ -582,48 +587,3 @@ async def _update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update when config_entry options update."""
hass.data[DOMAIN][entry.entry_id][DATA_OPTIONS] = entry.options.copy()
async_dispatcher_send(hass, SIGNAL_CONFIG_ENTITY)


class SamsungTVDeviceInfo:
"""Define generic samsung device info."""

def __init__(
self, config: dict[str, str], entry_id: str, forced_mac: str | None = None
) -> None:
"""Initialize the class."""
self._config = config
self._unique_id = config.get(CONF_ID, entry_id)
self._name = config.get(CONF_NAME, config[CONF_HOST])
self._mac = forced_mac or config.get(CONF_MAC)

@property
def unique_id(self) -> str:
"""Return device unique id."""
return self._unique_id

@property
def name(self) -> str:
"""Return device name."""
return self._name

@property
def device_info(self) -> DeviceInfo:
"""Return device information."""
config = self._config

model = config.get(CONF_DEVICE_MODEL, "Samsung TV")
if dev_name := config.get(CONF_DEVICE_NAME):
model = f"{model} ({dev_name})"

device_info = DeviceInfo(
identifiers={(DOMAIN, self.unique_id)},
name=self.name,
manufacturer="Samsung Electronics",
model=model,
)
if dev_os := config.get(CONF_DEVICE_OS):
device_info["sw_version"] = dev_os
if self._mac:
device_info["connections"] = {(CONNECTION_NETWORK_MAC, self._mac)}

return device_info
2 changes: 1 addition & 1 deletion custom_components/samsungtv_smart/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class PowerOnMethod(Enum):
MIN_HA_MIN_VER = 7
__min_ha_version__ = f"{MIN_HA_MAJ_VER}.{MIN_HA_MIN_VER}.0"

DATA_CFG = "cfg"
DATA_CFG_YAML = "cfg_yaml"
DATA_DEV_INFO = "dev_info"
DATA_OPTIONS = "options"
LOCAL_LOGO_PATH = "local_logo_path"
WS_PREFIX = "[Home Assistant]"
Expand Down
48 changes: 48 additions & 0 deletions custom_components/samsungtv_smart/entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Base SamsungTV Entity."""
from __future__ import annotations

from typing import Any

from homeassistant.const import (
ATTR_CONNECTIONS,
ATTR_SW_VERSION,
ATTR_IDENTIFIERS,
CONF_ID,
CONF_HOST,
CONF_MAC,
CONF_NAME,
)
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.entity import DeviceInfo, Entity

from .const import CONF_DEVICE_MODEL, CONF_DEVICE_NAME, CONF_DEVICE_OS, DOMAIN


class SamsungTVEntity(Entity):
"""Defines a base SamsungTV entity."""

_attr_has_entity_name = True

def __init__(self, config: dict[str, Any], entry_id: str) -> None:
"""Initialize the class."""
self._name = config.get(CONF_NAME, config[CONF_HOST])
self._mac = config.get(CONF_MAC)
self._attr_unique_id = config.get(CONF_ID, entry_id)

model = config.get(CONF_DEVICE_MODEL, "Samsung TV")
if dev_name := config.get(CONF_DEVICE_NAME):
model = f"{model} ({dev_name})"

self._attr_device_info = DeviceInfo(
manufacturer="Samsung Electronics",
model=model,
name=self._name,
)
if self.unique_id:
self._attr_device_info[ATTR_IDENTIFIERS] = {(DOMAIN, self.unique_id)}
if dev_os := config.get(CONF_DEVICE_OS):
self._attr_device_info[ATTR_SW_VERSION] = dev_os
if self._mac:
self._attr_device_info[ATTR_CONNECTIONS] = {
(CONNECTION_NETWORK_MAC, self._mac)
}
38 changes: 9 additions & 29 deletions custom_components/samsungtv_smart/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
CONF_BROADCAST_ADDRESS,
CONF_DEVICE_ID,
CONF_HOST,
CONF_MAC,
CONF_NAME,
CONF_PORT,
CONF_SERVICE,
CONF_SERVICE_DATA,
Expand All @@ -58,7 +56,6 @@
from homeassistant.util import Throttle, dt as dt_util
from homeassistant.util.async_ import run_callback_threadsafe

from . import SamsungTVDeviceInfo
from .api.samsungcast import SamsungCastTube
from .api.samsungws import ArtModeStatus, SamsungTVAsyncRest, SamsungTVWS
from .api.smartthings import SmartThingsTV, STStatus
Expand All @@ -84,8 +81,7 @@
CONF_USE_ST_STATUS_INFO,
CONF_WOL_REPEAT,
CONF_WS_NAME,
DATA_CFG_YAML,
DATA_DEV_INFO,
DATA_CFG,
DATA_OPTIONS,
DEFAULT_APP,
DEFAULT_PORT,
Expand All @@ -103,6 +99,7 @@
AppLoadMethod,
PowerOnMethod,
)
from .entity import SamsungTVEntity
from .logo import LOGO_OPTION_DEFAULT, LocalImageUrl, Logo, LogoOption

ATTR_ART_MODE_STATUS = "art_mode_status"
Expand Down Expand Up @@ -165,16 +162,8 @@ async def async_setup_entry(
# session used by aiohttp
session = async_get_clientsession(hass)
local_logo_path = hass.data[DOMAIN].get(LOCAL_LOGO_PATH)
dev_info: SamsungTVDeviceInfo = hass.data[DOMAIN][entry.entry_id][DATA_DEV_INFO]
config = hass.data[DOMAIN][entry.entry_id][DATA_CFG]

config = entry.data.copy()
add_conf = hass.data[DOMAIN][entry.entry_id].get(DATA_CFG_YAML, {})
for attr, value in add_conf.items():
if value:
config[attr] = value

hostname = config[CONF_HOST]
port = config.get(CONF_PORT, DEFAULT_PORT)
logo_file = hass.config.path(STORAGE_DIR, f"{DOMAIN}_logo_paths")

def update_token_func(token: str) -> None:
Expand All @@ -187,7 +176,7 @@ def update_token_func(token: str) -> None:
[
SamsungTVDevice(
config,
dev_info,
entry.entry_id,
hass.data[DOMAIN][entry.entry_id],
session,
update_token_func,
Expand All @@ -211,13 +200,6 @@ def update_token_func(token: str) -> None:
"async_set_art_mode",
)

_LOGGER.info(
"Samsung TV %s:%d added as '%s'",
hostname,
port,
config.get(CONF_NAME, hostname),
)


def _get_default_app_info(app_id):
"""Get information for default app."""
Expand All @@ -243,17 +225,16 @@ class ArtModeSupport(Enum):
FULL = 2


class SamsungTVDevice(MediaPlayerEntity):
class SamsungTVDevice(SamsungTVEntity, MediaPlayerEntity):
"""Representation of a Samsung TV."""

_attr_device_class = MediaPlayerDeviceClass.TV
_attr_has_entity_name = True
_attr_name = None

def __init__(
self,
config: dict[str, Any],
dev_info: SamsungTVDeviceInfo,
entry_id: str,
entry_data: dict[str, Any] | None,
session: ClientSession,
update_token_func: Callable[[str], None],
Expand All @@ -262,13 +243,12 @@ def __init__(
) -> None:
"""Initialize the Samsung device."""

super().__init__(config, entry_id)

self._entry_data = entry_data
self._host = config[CONF_HOST]
self._mac = config.get(CONF_MAC)

# Set entity attributes
self._attr_unique_id = dev_info.unique_id
self._attr_device_info = dev_info.device_info
self._attr_media_title = None
self._attr_media_image_url = None
self._attr_media_image_remotely_accessible = False
Expand Down Expand Up @@ -315,7 +295,7 @@ def __init__(
self._show_channel_number: bool = False

# ws initialization
ws_name = config.get(CONF_WS_NAME, dev_info.name)
ws_name = config.get(CONF_WS_NAME, self._name)
self._ws = SamsungTVWS(
host=self._host,
token=config.get(CONF_TOKEN),
Expand Down
16 changes: 7 additions & 9 deletions custom_components/samsungtv_smart/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.service import CONF_SERVICE_ENTITY_ID, async_call_from_config

from . import SamsungTVDeviceInfo
from .const import DATA_DEV_INFO, DOMAIN
from .const import DATA_CFG, DOMAIN
from .entity import SamsungTVEntity
from .media_player import MEDIA_TYPE_KEY

JOIN_COMMAND = "+"
Expand All @@ -55,25 +55,23 @@ def _add_remote_entity(utc_now: datetime) -> None:
if mp_entity_id is None:
return

dev_info: SamsungTVDeviceInfo = hass.data[DOMAIN][entry.entry_id][DATA_DEV_INFO]
async_add_entities([SamsungTVRemote(mp_entity_id, dev_info)])
config = hass.data[DOMAIN][entry.entry_id][DATA_CFG]
async_add_entities([SamsungTVRemote(config, entry.entry_id, mp_entity_id)])

# we wait for TV media player entity to be created
async_call_later(hass, 5, _add_remote_entity)


class SamsungTVRemote(RemoteEntity):
class SamsungTVRemote(SamsungTVEntity, RemoteEntity):
"""Device that sends commands to a SamsungTV."""

_attr_has_entity_name = True
_attr_name = None
_attr_should_poll = False

def __init__(self, mp_entity_id: str, dev_info: SamsungTVDeviceInfo):
def __init__(self, config: dict[str, Any], entry_id: str, mp_entity_id: str):
"""Initialize the remote."""
super().__init__(config, entry_id)
self._mp_entity_id = mp_entity_id
self._attr_unique_id = dev_info.unique_id
self._attr_device_info = dev_info.device_info

async def _async_call_service(
self,
Expand Down

0 comments on commit f73be3c

Please sign in to comment.