1
0
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:
mithomas
2026-04-26 14:14:16 +02:00
committed by GitHub
parent a506be4be0
commit aa0199b442
3 changed files with 143 additions and 1 deletions
@@ -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,
)