diff --git a/homeassistant/components/yamaha/const.py b/homeassistant/components/yamaha/const.py index fea962938eb..bcfdc55a511 100644 --- a/homeassistant/components/yamaha/const.py +++ b/homeassistant/components/yamaha/const.py @@ -1,4 +1,11 @@ """Constants for the Yamaha component.""" DOMAIN = "yamaha" +CURSOR_TYPE_DOWN = "down" +CURSOR_TYPE_LEFT = "left" +CURSOR_TYPE_RETURN = "return" +CURSOR_TYPE_RIGHT = "right" +CURSOR_TYPE_SELECT = "select" +CURSOR_TYPE_UP = "up" SERVICE_ENABLE_OUTPUT = "enable_output" +SERVICE_MENU_CURSOR = "menu_cursor" SERVICE_SELECT_SCENE = "select_scene" diff --git a/homeassistant/components/yamaha/media_player.py b/homeassistant/components/yamaha/media_player.py index 3f79be43f6e..147a983b298 100644 --- a/homeassistant/components/yamaha/media_player.py +++ b/homeassistant/components/yamaha/media_player.py @@ -31,10 +31,21 @@ from homeassistant.const import ( ) from homeassistant.helpers import config_validation as cv, entity_platform -from .const import SERVICE_ENABLE_OUTPUT, SERVICE_SELECT_SCENE +from .const import ( + CURSOR_TYPE_DOWN, + CURSOR_TYPE_LEFT, + CURSOR_TYPE_RETURN, + CURSOR_TYPE_RIGHT, + CURSOR_TYPE_SELECT, + CURSOR_TYPE_UP, + SERVICE_ENABLE_OUTPUT, + SERVICE_MENU_CURSOR, + SERVICE_SELECT_SCENE, +) _LOGGER = logging.getLogger(__name__) +ATTR_CURSOR = "cursor" ATTR_ENABLED = "enabled" ATTR_PORT = "port" @@ -45,6 +56,14 @@ CONF_SOURCE_NAMES = "source_names" CONF_ZONE_IGNORE = "zone_ignore" CONF_ZONE_NAMES = "zone_names" +CURSOR_TYPE_MAP = { + CURSOR_TYPE_DOWN: rxv.RXV.menu_down.__name__, + CURSOR_TYPE_LEFT: rxv.RXV.menu_left.__name__, + CURSOR_TYPE_RETURN: rxv.RXV.menu_return.__name__, + CURSOR_TYPE_RIGHT: rxv.RXV.menu_right.__name__, + CURSOR_TYPE_SELECT: rxv.RXV.menu_sel.__name__, + CURSOR_TYPE_UP: rxv.RXV.menu_up.__name__, +} DATA_YAMAHA = "yamaha_known_receivers" DEFAULT_NAME = "Yamaha Receiver" @@ -164,6 +183,12 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= {vol.Required(ATTR_ENABLED): cv.boolean, vol.Required(ATTR_PORT): cv.string}, "enable_output", ) + # Register Service 'menu_cursor' + platform.async_register_entity_service( + SERVICE_MENU_CURSOR, + {vol.Required(ATTR_CURSOR): vol.In(CURSOR_TYPE_MAP)}, + YamahaDevice.menu_cursor.__name__, + ) class YamahaDevice(MediaPlayerEntity): @@ -382,6 +407,10 @@ class YamahaDevice(MediaPlayerEntity): """Enable or disable an output port..""" self.receiver.enable_output(port, enabled) + def menu_cursor(self, cursor): + """Press a menu cursor button.""" + getattr(self.receiver, CURSOR_TYPE_MAP[cursor])() + def set_scene(self, scene): """Set the current scene.""" try: diff --git a/homeassistant/components/yamaha/services.yaml b/homeassistant/components/yamaha/services.yaml index fe2b2c66384..8d25d5925c1 100644 --- a/homeassistant/components/yamaha/services.yaml +++ b/homeassistant/components/yamaha/services.yaml @@ -19,6 +19,20 @@ enable_output: required: true selector: boolean: +menu_cursor: + name: Menu cursor + description: Control the cursor in a menu + target: + entity: + integration: yamaha + domain: media_player + fields: + cursor: + name: Cursor + description: Name of the cursor key to press ('up', 'down', 'left', 'right', 'select', 'return') + example: down + selector: + text: select_scene: name: Select scene description: "Select a scene on the receiver" diff --git a/tests/components/yamaha/test_media_player.py b/tests/components/yamaha/test_media_player.py index 84a9e475c32..45624ae0a8b 100644 --- a/tests/components/yamaha/test_media_player.py +++ b/tests/components/yamaha/test_media_player.py @@ -130,6 +130,32 @@ async def test_enable_output(hass, device, main_zone): assert main_zone.enable_output.call_args == call(port, enabled) +@pytest.mark.parametrize( + "cursor,method", + [ + (yamaha.CURSOR_TYPE_DOWN, "menu_down"), + (yamaha.CURSOR_TYPE_LEFT, "menu_left"), + (yamaha.CURSOR_TYPE_RETURN, "menu_return"), + (yamaha.CURSOR_TYPE_RIGHT, "menu_right"), + (yamaha.CURSOR_TYPE_SELECT, "menu_sel"), + (yamaha.CURSOR_TYPE_UP, "menu_up"), + ], +) +@pytest.mark.usefixtures("device") +async def test_menu_cursor(hass, main_zone, cursor, method): + """Verify that the correct menu method is called for the menu_cursor service.""" + assert await async_setup_component(hass, mp.DOMAIN, CONFIG) + await hass.async_block_till_done() + + data = { + "entity_id": "media_player.yamaha_receiver_main_zone", + "cursor": cursor, + } + await hass.services.async_call(DOMAIN, yamaha.SERVICE_MENU_CURSOR, data, True) + + getattr(main_zone, method).assert_called_once_with() + + async def test_select_scene(hass, device, main_zone, caplog): """Test select scene service.""" scene_prop = PropertyMock(return_value=None)