mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 17:49:37 +01:00
Add LG Netcast service to send remote control commands (#168649)
This commit is contained in:
@@ -11,7 +11,7 @@ from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
PLATFORMS: Final[list[Platform]] = [Platform.MEDIA_PLAYER]
|
||||
PLATFORMS: Final[list[Platform]] = [Platform.MEDIA_PLAYER, Platform.REMOTE]
|
||||
|
||||
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"""Remote control support for LG Netcast TV."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterable
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from pylgnetcast import LG_COMMAND, LgNetCastClient, LgNetCastError
|
||||
from requests import RequestException
|
||||
|
||||
from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import LgNetCastConfigEntry
|
||||
from .const import ATTR_MANUFACTURER, DOMAIN
|
||||
|
||||
VALID_COMMANDS: frozenset[str] = frozenset(
|
||||
k
|
||||
for k in vars(LG_COMMAND)
|
||||
if not k.startswith("_") and isinstance(getattr(LG_COMMAND, k), int)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: LgNetCastConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up LG Netcast Remote from a config entry."""
|
||||
client = config_entry.runtime_data
|
||||
unique_id = config_entry.unique_id
|
||||
if TYPE_CHECKING:
|
||||
assert unique_id is not None
|
||||
|
||||
async_add_entities([LgNetCastRemote(client, unique_id)])
|
||||
|
||||
|
||||
class LgNetCastRemote(RemoteEntity):
|
||||
"""Device that sends commands to an LG Netcast TV."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = None
|
||||
|
||||
def __init__(self, client: LgNetCastClient, unique_id: str) -> None:
|
||||
"""Initialize the LG Netcast remote."""
|
||||
self._client = client
|
||||
self._attr_unique_id = unique_id
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, unique_id)},
|
||||
manufacturer=ATTR_MANUFACTURER,
|
||||
)
|
||||
|
||||
def send_command(self, command: Iterable[str], **kwargs: Any) -> None:
|
||||
"""Send commands to the TV."""
|
||||
num_repeats = kwargs[ATTR_NUM_REPEATS]
|
||||
|
||||
commands: list[int] = []
|
||||
for cmd in command:
|
||||
if cmd not in VALID_COMMANDS:
|
||||
raise ServiceValidationError(f"Unknown command: {cmd!r}")
|
||||
commands.append(getattr(LG_COMMAND, cmd))
|
||||
for _ in range(num_repeats):
|
||||
try:
|
||||
with self._client as client:
|
||||
for lg_command in commands:
|
||||
client.send_command(lg_command)
|
||||
except LgNetCastError, RequestException:
|
||||
self._attr_is_on = False
|
||||
self.schedule_update_ha_state()
|
||||
return
|
||||
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on is handled via a separate turn_on trigger."""
|
||||
raise NotImplementedError(
|
||||
"Turning on the TV is not supported by the LG Netcast remote entity"
|
||||
)
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the TV."""
|
||||
self.send_command(["POWER"], **{ATTR_NUM_REPEATS: 1})
|
||||
@@ -0,0 +1,59 @@
|
||||
"""Tests for LG Netcast remote platform."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from pylgnetcast import LG_COMMAND
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.remote import (
|
||||
ATTR_COMMAND,
|
||||
DOMAIN as REMOTE_DOMAIN,
|
||||
SERVICE_SEND_COMMAND,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
|
||||
from . import MODEL_NAME, setup_lgnetcast
|
||||
|
||||
REMOTE_ENTITY_ID = f"{REMOTE_DOMAIN}.{MODEL_NAME.lower()}"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_lg_netcast() -> Generator[MagicMock]:
|
||||
"""Mock LG Netcast library."""
|
||||
with patch(
|
||||
"homeassistant.components.lg_netcast.LgNetCastClient"
|
||||
) as mock_client_class:
|
||||
yield mock_client_class
|
||||
|
||||
|
||||
async def test_send_command(hass: HomeAssistant, mock_lg_netcast: MagicMock) -> None:
|
||||
"""Test remote.send_command calls the client with the correct command code."""
|
||||
await setup_lgnetcast(hass)
|
||||
context_client = mock_lg_netcast.return_value.__enter__.return_value
|
||||
|
||||
await hass.services.async_call(
|
||||
REMOTE_DOMAIN,
|
||||
SERVICE_SEND_COMMAND,
|
||||
{ATTR_ENTITY_ID: REMOTE_ENTITY_ID, ATTR_COMMAND: ["POWER"]},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
context_client.send_command.assert_called_once_with(LG_COMMAND.POWER)
|
||||
|
||||
|
||||
async def test_send_command_invalid(
|
||||
hass: HomeAssistant, mock_lg_netcast: MagicMock
|
||||
) -> None:
|
||||
"""Test remote.send_command raises ServiceValidationError for an unknown command name."""
|
||||
await setup_lgnetcast(hass)
|
||||
|
||||
with pytest.raises(ServiceValidationError, match="Unknown command"):
|
||||
await hass.services.async_call(
|
||||
REMOTE_DOMAIN,
|
||||
SERVICE_SEND_COMMAND,
|
||||
{ATTR_ENTITY_ID: REMOTE_ENTITY_ID, ATTR_COMMAND: ["NOT_A_REAL_COMMAND"]},
|
||||
blocking=True,
|
||||
)
|
||||
Reference in New Issue
Block a user