diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index ca9de0bfb62..44a318988b2 100644 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -30,6 +30,7 @@ _LOGGER = logging.getLogger(__name__) ATTR_ACTIVITY = "activity" ATTR_COMMAND = "command" +ATTR_COMMAND_TYPE = "command_type" ATTR_DEVICE = "device" ATTR_NUM_REPEATS = "num_repeats" ATTR_DELAY_SECS = "delay_secs" @@ -46,6 +47,7 @@ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) SERVICE_SEND_COMMAND = "send_command" SERVICE_LEARN_COMMAND = "learn_command" +SERVICE_DELETE_COMMAND = "delete_command" SERVICE_SYNC = "sync" DEFAULT_NUM_REPEATS = 1 @@ -53,6 +55,7 @@ DEFAULT_DELAY_SECS = 0.4 DEFAULT_HOLD_SECS = 0 SUPPORT_LEARN_COMMAND = 1 +SUPPORT_DELETE_COMMAND = 2 REMOTE_SERVICE_ACTIVITY_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_ACTIVITY): cv.string} @@ -103,12 +106,22 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: { vol.Optional(ATTR_DEVICE): cv.string, vol.Optional(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(ATTR_COMMAND_TYPE): cv.string, vol.Optional(ATTR_ALTERNATIVE): cv.boolean, vol.Optional(ATTR_TIMEOUT): cv.positive_int, }, "async_learn_command", ) + component.async_register_entity_service( + SERVICE_DELETE_COMMAND, + { + vol.Required(ATTR_COMMAND): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(ATTR_DEVICE): cv.string, + }, + "async_delete_command", + ) + return True @@ -150,6 +163,17 @@ class RemoteEntity(ToggleEntity): assert self.hass is not None await self.hass.async_add_executor_job(ft.partial(self.learn_command, **kwargs)) + def delete_command(self, **kwargs: Any) -> None: + """Delete commands from the database.""" + raise NotImplementedError() + + async def async_delete_command(self, **kwargs: Any) -> None: + """Delete commands from the database.""" + assert self.hass is not None + await self.hass.async_add_executor_job( + ft.partial(self.delete_command, **kwargs) + ) + class RemoteDevice(RemoteEntity): """Representation of a remote (for backwards compatibility).""" diff --git a/homeassistant/components/remote/services.yaml b/homeassistant/components/remote/services.yaml index fc9d170726e..3868479efc6 100644 --- a/homeassistant/components/remote/services.yaml +++ b/homeassistant/components/remote/services.yaml @@ -58,9 +58,25 @@ learn_command: command: description: A single command or a list of commands to learn. example: "Turn on" + command_type: + description: The type of command to be learned. + example: "rf" alternative: description: If code must be stored as alternative (useful for discrete remotes). example: "True" timeout: description: Timeout, in seconds, for the command to be learned. example: "30" + +delete_command: + description: Deletes a command or a list of commands from the database. + fields: + entity_id: + description: Name(s) of the remote entities holding the database. + example: "remote.bedroom" + device: + description: Name of the device from which commands will be deleted. + example: "television" + command: + description: A single command or a list of commands to delete. + example: "Mute" diff --git a/tests/components/remote/common.py b/tests/components/remote/common.py index 1f4a5268440..ef9ca91dada 100644 --- a/tests/components/remote/common.py +++ b/tests/components/remote/common.py @@ -7,11 +7,13 @@ from homeassistant.components.remote import ( ATTR_ACTIVITY, ATTR_ALTERNATIVE, ATTR_COMMAND, + ATTR_COMMAND_TYPE, ATTR_DELAY_SECS, ATTR_DEVICE, ATTR_NUM_REPEATS, ATTR_TIMEOUT, DOMAIN, + SERVICE_DELETE_COMMAND, SERVICE_LEARN_COMMAND, SERVICE_SEND_COMMAND, ) @@ -81,6 +83,7 @@ def learn_command( device=None, command=None, alternative=None, + command_type=None, timeout=None, ): """Learn a command from a device.""" @@ -94,6 +97,9 @@ def learn_command( if command: data[ATTR_COMMAND] = command + if command_type: + data[ATTR_COMMAND_TYPE] = command_type + if alternative: data[ATTR_ALTERNATIVE] = alternative @@ -101,3 +107,24 @@ def learn_command( data[ATTR_TIMEOUT] = timeout hass.services.call(DOMAIN, SERVICE_LEARN_COMMAND, data) + + +@bind_hass +def delete_command( + hass, + entity_id=ENTITY_MATCH_ALL, + device=None, + command=None, +): + """Delete commands from the database.""" + data = {} + if entity_id: + data[ATTR_ENTITY_ID] = entity_id + + if device: + data[ATTR_DEVICE] = device + + if command: + data[ATTR_COMMAND] = command + + hass.services.call(DOMAIN, SERVICE_DELETE_COMMAND, data) diff --git a/tests/components/remote/test_init.py b/tests/components/remote/test_init.py index eb47d365f83..b3c85ae837c 100644 --- a/tests/components/remote/test_init.py +++ b/tests/components/remote/test_init.py @@ -19,6 +19,7 @@ from tests.components.remote import common TEST_PLATFORM = {remote.DOMAIN: {CONF_PLATFORM: "test"}} SERVICE_SEND_COMMAND = "send_command" SERVICE_LEARN_COMMAND = "learn_command" +SERVICE_DELETE_COMMAND = "delete_command" class TestRemote(unittest.TestCase): @@ -101,6 +102,7 @@ class TestRemote(unittest.TestCase): entity_id="entity_id_val", device="test_device", command=["test_command"], + command_type="rf", alternative=True, timeout=20, ) @@ -114,6 +116,28 @@ class TestRemote(unittest.TestCase): assert call.service == SERVICE_LEARN_COMMAND assert call.data[ATTR_ENTITY_ID] == "entity_id_val" + def test_delete_command(self): + """Test delete_command.""" + delete_command_calls = mock_service( + self.hass, remote.DOMAIN, SERVICE_DELETE_COMMAND + ) + + common.delete_command( + self.hass, + entity_id="entity_id_val", + device="test_device", + command=["test_command"], + ) + + self.hass.block_till_done() + + assert len(delete_command_calls) == 1 + call = delete_command_calls[-1] + + assert call.domain == remote.DOMAIN + assert call.service == SERVICE_DELETE_COMMAND + assert call.data[ATTR_ENTITY_ID] == "entity_id_val" + def test_deprecated_base_class(caplog): """Test deprecated base class."""