Skip to content

Commit 80c611e

Browse files
authored
Add support for additional remote commands to Xbox integration (home-assistant#157206)
1 parent b44aafc commit 80c611e

File tree

2 files changed

+195
-5
lines changed

2 files changed

+195
-5
lines changed

homeassistant/components/xbox/remote.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from __future__ import annotations
44

55
import asyncio
6-
from collections.abc import Iterable
6+
from collections.abc import Callable, Iterable
77
from typing import Any
88

9+
from pythonxbox.api.provider.smartglass import SmartglassProvider
910
from pythonxbox.api.provider.smartglass.models import InputKeyType, PowerState
1011

1112
from homeassistant.components.remote import (
@@ -22,6 +23,22 @@
2223

2324
PARALLEL_UPDATES = 1
2425

26+
MAP_COMMAND: dict[str, Callable[[SmartglassProvider], Callable]] = {
27+
"WakeUp": lambda x: x.wake_up,
28+
"TurnOff": lambda x: x.turn_off,
29+
"Reboot": lambda x: x.reboot,
30+
"Mute": lambda x: x.mute,
31+
"Unmute": lambda x: x.unmute,
32+
"Play": lambda x: x.play,
33+
"Pause": lambda x: x.pause,
34+
"Previous": lambda x: x.previous,
35+
"Next": lambda x: x.next,
36+
"GoHome": lambda x: x.go_home,
37+
"GoBack": lambda x: x.go_back,
38+
"ShowGuideTab": lambda x: x.show_guide_tab,
39+
"ShowGuide": lambda x: x.show_tv_guide,
40+
}
41+
2542

2643
async def async_setup_entry(
2744
hass: HomeAssistant,
@@ -59,10 +76,14 @@ async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> Non
5976

6077
for _ in range(num_repeats):
6178
for single_command in command:
62-
try:
79+
if single_command in InputKeyType:
6380
button = InputKeyType(single_command)
6481
await self.client.smartglass.press_button(self._console.id, button)
65-
except ValueError:
82+
elif single_command in MAP_COMMAND:
83+
await MAP_COMMAND[single_command](self.client.smartglass)(
84+
self._console.id
85+
)
86+
else:
6687
await self.client.smartglass.insert_text(
6788
self._console.id, single_command
6889
)

tests/components/xbox/test_remote.py

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
"""Test the Xbox remote platform."""
22

33
from collections.abc import Generator
4-
from unittest.mock import patch
4+
from unittest.mock import AsyncMock, patch
55

66
import pytest
7+
from pythonxbox.api.provider.smartglass.models import InputKeyType
78
from syrupy.assertion import SnapshotAssertion
89

10+
from homeassistant.components.remote import (
11+
ATTR_DELAY_SECS,
12+
DOMAIN as REMOTE_DOMAIN,
13+
SERVICE_SEND_COMMAND,
14+
)
915
from homeassistant.config_entries import ConfigEntryState
10-
from homeassistant.const import Platform
16+
from homeassistant.const import (
17+
ATTR_COMMAND,
18+
ATTR_ENTITY_ID,
19+
SERVICE_TURN_OFF,
20+
SERVICE_TURN_ON,
21+
Platform,
22+
)
1123
from homeassistant.core import HomeAssistant
1224
from homeassistant.helpers import entity_registry as er
1325

@@ -40,3 +52,160 @@ async def test_remotes(
4052
assert config_entry.state is ConfigEntryState.LOADED
4153

4254
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
55+
56+
57+
@pytest.mark.parametrize(
58+
("button", "payload"),
59+
[
60+
("A", InputKeyType.A),
61+
("B", InputKeyType.B),
62+
("X", InputKeyType.X),
63+
("Y", InputKeyType.Y),
64+
("Up", InputKeyType.Up),
65+
("Down", InputKeyType.Down),
66+
("Left", InputKeyType.Left),
67+
("Right", InputKeyType.Right),
68+
("Menu", InputKeyType.Menu),
69+
("View", InputKeyType.View),
70+
("Nexus", InputKeyType.Nexus),
71+
],
72+
)
73+
async def test_send_button_command(
74+
hass: HomeAssistant,
75+
xbox_live_client: AsyncMock,
76+
config_entry: MockConfigEntry,
77+
button: str,
78+
payload: InputKeyType,
79+
) -> None:
80+
"""Test remote send button command."""
81+
82+
config_entry.add_to_hass(hass)
83+
await hass.config_entries.async_setup(config_entry.entry_id)
84+
await hass.async_block_till_done()
85+
86+
assert config_entry.state is ConfigEntryState.LOADED
87+
88+
await hass.services.async_call(
89+
REMOTE_DOMAIN,
90+
SERVICE_SEND_COMMAND,
91+
{ATTR_COMMAND: button, ATTR_DELAY_SECS: 0},
92+
target={ATTR_ENTITY_ID: "remote.xone"},
93+
blocking=True,
94+
)
95+
96+
xbox_live_client.smartglass.press_button.assert_called_once_with("HIJKLMN", payload)
97+
98+
99+
@pytest.mark.parametrize(
100+
("command", "call_method"),
101+
[
102+
("WakeUp", "wake_up"),
103+
("TurnOff", "turn_off"),
104+
("Reboot", "reboot"),
105+
("Mute", "mute"),
106+
("Unmute", "unmute"),
107+
("Play", "play"),
108+
("Pause", "pause"),
109+
("Previous", "previous"),
110+
("Next", "next"),
111+
("GoHome", "go_home"),
112+
("GoBack", "go_back"),
113+
("ShowGuideTab", "show_guide_tab"),
114+
("ShowGuide", "show_tv_guide"),
115+
],
116+
)
117+
async def test_send_command(
118+
hass: HomeAssistant,
119+
xbox_live_client: AsyncMock,
120+
config_entry: MockConfigEntry,
121+
command: str,
122+
call_method: str,
123+
) -> None:
124+
"""Test remote send command."""
125+
126+
config_entry.add_to_hass(hass)
127+
await hass.config_entries.async_setup(config_entry.entry_id)
128+
await hass.async_block_till_done()
129+
130+
assert config_entry.state is ConfigEntryState.LOADED
131+
132+
await hass.services.async_call(
133+
REMOTE_DOMAIN,
134+
SERVICE_SEND_COMMAND,
135+
{ATTR_COMMAND: command, ATTR_DELAY_SECS: 0},
136+
target={ATTR_ENTITY_ID: "remote.xone"},
137+
blocking=True,
138+
)
139+
140+
call = getattr(xbox_live_client.smartglass, call_method)
141+
call.assert_called_once_with("HIJKLMN")
142+
143+
144+
async def test_send_text(
145+
hass: HomeAssistant,
146+
xbox_live_client: AsyncMock,
147+
config_entry: MockConfigEntry,
148+
) -> None:
149+
"""Test remote send text."""
150+
151+
config_entry.add_to_hass(hass)
152+
await hass.config_entries.async_setup(config_entry.entry_id)
153+
await hass.async_block_till_done()
154+
155+
assert config_entry.state is ConfigEntryState.LOADED
156+
157+
await hass.services.async_call(
158+
REMOTE_DOMAIN,
159+
SERVICE_SEND_COMMAND,
160+
{ATTR_COMMAND: "Hello", ATTR_DELAY_SECS: 0},
161+
target={ATTR_ENTITY_ID: "remote.xone"},
162+
blocking=True,
163+
)
164+
165+
xbox_live_client.smartglass.insert_text.assert_called_once_with("HIJKLMN", "Hello")
166+
167+
168+
async def test_turn_on(
169+
hass: HomeAssistant,
170+
xbox_live_client: AsyncMock,
171+
config_entry: MockConfigEntry,
172+
) -> None:
173+
"""Test remote turn on."""
174+
175+
config_entry.add_to_hass(hass)
176+
await hass.config_entries.async_setup(config_entry.entry_id)
177+
await hass.async_block_till_done()
178+
179+
assert config_entry.state is ConfigEntryState.LOADED
180+
181+
await hass.services.async_call(
182+
REMOTE_DOMAIN,
183+
SERVICE_TURN_ON,
184+
target={ATTR_ENTITY_ID: "remote.xone"},
185+
blocking=True,
186+
)
187+
188+
xbox_live_client.smartglass.wake_up.assert_called_once_with("HIJKLMN")
189+
190+
191+
async def test_turn_off(
192+
hass: HomeAssistant,
193+
xbox_live_client: AsyncMock,
194+
config_entry: MockConfigEntry,
195+
) -> None:
196+
"""Test remote turn off."""
197+
198+
config_entry.add_to_hass(hass)
199+
await hass.config_entries.async_setup(config_entry.entry_id)
200+
await hass.async_block_till_done()
201+
202+
assert config_entry.state is ConfigEntryState.LOADED
203+
204+
await hass.services.async_call(
205+
REMOTE_DOMAIN,
206+
SERVICE_TURN_OFF,
207+
target={ATTR_ENTITY_ID: "remote.xone"},
208+
blocking=True,
209+
)
210+
211+
xbox_live_client.smartglass.turn_off.assert_called_once_with("HIJKLMN")

0 commit comments

Comments
 (0)