Skip to content

Commit

Permalink
Move LG webOS TV actions to entitiy services (home-assistant#135285)
Browse files Browse the repository at this point in the history
  • Loading branch information
thecode authored Jan 10, 2025
1 parent bce7e9b commit 1f0eda8
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 86 deletions.
61 changes: 2 additions & 59 deletions homeassistant/components/webostv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,33 @@

from contextlib import suppress
import logging
from typing import NamedTuple

from aiowebostv import WebOsClient, WebOsTvPairError
import voluptuous as vol

from homeassistant.components import notify as hass_notify
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_COMMAND,
ATTR_ENTITY_ID,
CONF_CLIENT_SECRET,
CONF_HOST,
CONF_NAME,
EVENT_HOMEASSISTANT_STOP,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall
from homeassistant.core import Event, HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers import config_validation as cv, discovery
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import ConfigType

from .const import (
ATTR_BUTTON,
ATTR_CONFIG_ENTRY_ID,
ATTR_PAYLOAD,
ATTR_SOUND_OUTPUT,
DATA_CONFIG_ENTRY,
DATA_HASS_CONFIG,
DOMAIN,
PLATFORMS,
SERVICE_BUTTON,
SERVICE_COMMAND,
SERVICE_SELECT_SOUND_OUTPUT,
WEBOSTV_EXCEPTIONS,
)

CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)

CALL_SCHEMA = vol.Schema({vol.Required(ATTR_ENTITY_ID): cv.comp_entity_ids})


class ServiceMethodDetails(NamedTuple):
"""Details for SERVICE_TO_METHOD mapping."""

method: str
schema: vol.Schema


BUTTON_SCHEMA = CALL_SCHEMA.extend({vol.Required(ATTR_BUTTON): cv.string})

COMMAND_SCHEMA = CALL_SCHEMA.extend(
{vol.Required(ATTR_COMMAND): cv.string, vol.Optional(ATTR_PAYLOAD): dict}
)

SOUND_OUTPUT_SCHEMA = CALL_SCHEMA.extend({vol.Required(ATTR_SOUND_OUTPUT): cv.string})

SERVICE_TO_METHOD = {
SERVICE_BUTTON: ServiceMethodDetails(method="async_button", schema=BUTTON_SCHEMA),
SERVICE_COMMAND: ServiceMethodDetails(
method="async_command", schema=COMMAND_SCHEMA
),
SERVICE_SELECT_SOUND_OUTPUT: ServiceMethodDetails(
method="async_select_sound_output",
schema=SOUND_OUTPUT_SCHEMA,
),
}

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -100,17 +61,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Update the stored key without triggering reauth
update_client_key(hass, entry, client)

async def async_service_handler(service: ServiceCall) -> None:
method = SERVICE_TO_METHOD[service.service]
data = service.data.copy()
data["method"] = method.method
async_dispatcher_send(hass, DOMAIN, data)

for service, method in SERVICE_TO_METHOD.items():
hass.services.async_register(
DOMAIN, service, async_service_handler, schema=method.schema
)

hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id] = client
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

Expand Down Expand Up @@ -174,17 +124,10 @@ def update_client_key(

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

if unload_ok:
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
client = hass.data[DOMAIN][DATA_CONFIG_ENTRY].pop(entry.entry_id)
await hass_notify.async_reload(hass, DOMAIN)
client.clear_state_update_callbacks()
await client.disconnect()

# unregister service calls, check if this is the last entry to unload
if unload_ok and not hass.data[DOMAIN][DATA_CONFIG_ENTRY]:
for service in SERVICE_TO_METHOD:
hass.services.async_remove(DOMAIN, service)

return unload_ok
50 changes: 26 additions & 24 deletions homeassistant/components/webostv/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import Any, Concatenate, cast

from aiowebostv import WebOsClient, WebOsTvPairError
import voluptuous as vol

from homeassistant import util
from homeassistant.components.media_player import (
Expand All @@ -22,29 +23,29 @@
MediaType,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
ENTITY_MATCH_ALL,
ENTITY_MATCH_NONE,
)
from homeassistant.const import ATTR_COMMAND, ATTR_SUPPORTED_FEATURES
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.trigger import PluggableAction
from homeassistant.helpers.typing import VolDictType

from . import update_client_key
from .const import (
ATTR_BUTTON,
ATTR_PAYLOAD,
ATTR_SOUND_OUTPUT,
CONF_SOURCES,
DATA_CONFIG_ENTRY,
DOMAIN,
LIVE_TV_APP_ID,
SERVICE_BUTTON,
SERVICE_COMMAND,
SERVICE_SELECT_SOUND_OUTPUT,
WEBOSTV_EXCEPTIONS,
)
from .triggers.turn_on import async_get_turn_on_trigger
Expand All @@ -71,11 +72,29 @@
PARALLEL_UPDATES = 0
SCAN_INTERVAL = timedelta(seconds=10)

BUTTON_SCHEMA: VolDictType = {vol.Required(ATTR_BUTTON): cv.string}
COMMAND_SCHEMA: VolDictType = {
vol.Required(ATTR_COMMAND): cv.string,
vol.Optional(ATTR_PAYLOAD): dict,
}
SOUND_OUTPUT_SCHEMA: VolDictType = {vol.Required(ATTR_SOUND_OUTPUT): cv.string}

SERVICES = (
(SERVICE_BUTTON, BUTTON_SCHEMA, "async_button"),
(SERVICE_COMMAND, COMMAND_SCHEMA, "async_command"),
(SERVICE_SELECT_SOUND_OUTPUT, SOUND_OUTPUT_SCHEMA, "async_select_sound_output"),
)


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the LG webOS Smart TV platform."""
platform = entity_platform.async_get_current_platform()

for service_name, schema, method in SERVICES:
platform.async_register_entity_service(service_name, schema, method)

client = hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id]
async_add_entities([LgWebOSMediaPlayerEntity(entry, client)])

Expand Down Expand Up @@ -143,10 +162,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.async_on_remove(
async_dispatcher_connect(self.hass, DOMAIN, self.async_signal_handler)
)

await self._client.register_state_update_callback(
self.async_handle_state_update
)
Expand All @@ -166,19 +181,6 @@ async def async_will_remove_from_hass(self) -> None:
"""Call disconnect on removal."""
self._client.unregister_state_update_callback(self.async_handle_state_update)

async def async_signal_handler(self, data: dict[str, Any]) -> None:
"""Handle domain-specific signal by calling appropriate method."""
if (entity_ids := data[ATTR_ENTITY_ID]) == ENTITY_MATCH_NONE:
return

if entity_ids == ENTITY_MATCH_ALL or self.entity_id in entity_ids:
params = {
key: value
for key, value in data.items()
if key not in ["entity_id", "method"]
}
await getattr(self, data["method"])(**params)

async def async_handle_state_update(self, _client: WebOsClient) -> None:
"""Update state from WebOsClient."""
self._update_states()
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/webostv/quality_scale.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
rules:
# Bronze
action-setup:
status: todo
comment: move actions to entity services
action-setup: done
appropriate-polling: done
brands: done
common-modules:
Expand Down

0 comments on commit 1f0eda8

Please sign in to comment.