Add support for learning RF commands with Broadlink remotes (#39671)

* Add support for learning RF codes with Broadlink remotes

* Rename INFRARED and RADIOFREQUENCY to COMMAND_TYPE_IR and COMMAND_TYPE_RF

* Rewrite if expression as normal if statement

* Use COMMAND_TYPE_IR directly and improve error messages
This commit is contained in:
Felipe Martins Diel 2020-11-12 15:10:29 -03:00 committed by GitHub
parent 7921be1b5f
commit c620fa344e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -18,6 +18,7 @@ import voluptuous as vol
from homeassistant.components.remote import (
ATTR_ALTERNATIVE,
ATTR_COMMAND,
ATTR_COMMAND_TYPE,
ATTR_DELAY_SECS,
ATTR_DEVICE,
ATTR_NUM_REPEATS,
@ -41,6 +42,10 @@ _LOGGER = logging.getLogger(__name__)
LEARNING_TIMEOUT = timedelta(seconds=30)
COMMAND_TYPE_IR = "ir"
COMMAND_TYPE_RF = "rf"
COMMAND_TYPES = [COMMAND_TYPE_IR, COMMAND_TYPE_RF]
CODE_STORAGE_VERSION = 1
FLAG_STORAGE_VERSION = 1
FLAG_SAVE_DELAY = 15
@ -64,6 +69,7 @@ SERVICE_SEND_SCHEMA = COMMAND_SCHEMA.extend(
SERVICE_LEARN_SCHEMA = COMMAND_SCHEMA.extend(
{
vol.Required(ATTR_DEVICE): vol.All(cv.string, vol.Length(min=1)),
vol.Optional(ATTR_COMMAND_TYPE, default=COMMAND_TYPE_IR): vol.In(COMMAND_TYPES),
vol.Optional(ATTR_ALTERNATIVE, default=False): cv.boolean,
}
)
@ -266,11 +272,11 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
await self._device.async_request(self._device.api.send_data, code)
except (AuthorizationError, NetworkTimeoutError, OSError) as err:
_LOGGER.error("Failed to send '%s': %s", command, err)
_LOGGER.error("Failed to send '%s': %s", cmd, err)
break
except BroadlinkException as err:
_LOGGER.error("Failed to send '%s': %s", command, err)
_LOGGER.error("Failed to send '%s': %s", cmd, err)
should_delay = False
continue
@ -284,6 +290,7 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
"""Learn a list of commands from a remote."""
kwargs = SERVICE_LEARN_SCHEMA(kwargs)
commands = kwargs[ATTR_COMMAND]
command_type = kwargs[ATTR_COMMAND_TYPE]
device = kwargs[ATTR_DEVICE]
toggle = kwargs[ATTR_ALTERNATIVE]
@ -293,13 +300,18 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
)
return
if command_type == COMMAND_TYPE_IR:
learn_command = self._async_learn_ir_command
else:
learn_command = self._async_learn_rf_command
should_store = False
for command in commands:
try:
code = await self._async_learn_command(command)
code = await learn_command(command)
if toggle:
code = [code, await self._async_learn_command(command)]
code = [code, await learn_command(command)]
except (AuthorizationError, NetworkTimeoutError, OSError) as err:
_LOGGER.error("Failed to learn '%s': %s", command, err)
@ -315,8 +327,8 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
if should_store:
await self._code_storage.async_save(self._codes)
async def _async_learn_command(self, command):
"""Learn a command from a remote."""
async def _async_learn_ir_command(self, command):
"""Learn an infrared command."""
try:
await self._device.async_request(self._device.api.enter_learning)
@ -336,12 +348,87 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
await asyncio.sleep(1)
try:
code = await self._device.async_request(self._device.api.check_data)
except (ReadError, StorageError):
continue
return b64encode(code).decode("utf8")
raise TimeoutError("No code received")
raise TimeoutError(
"No infrared code received within "
f"{LEARNING_TIMEOUT.seconds} seconds"
)
finally:
self.hass.components.persistent_notification.async_dismiss(
notification_id="learn_command"
)
async def _async_learn_rf_command(self, command):
"""Learn a radiofrequency command."""
try:
await self._device.async_request(self._device.api.sweep_frequency)
except (BroadlinkException, OSError) as err:
_LOGGER.debug("Failed to sweep frequency: %s", err)
raise
self.hass.components.persistent_notification.async_create(
f"Press and hold the '{command}' button.",
title="Sweep frequency",
notification_id="sweep_frequency",
)
try:
start_time = utcnow()
while (utcnow() - start_time) < LEARNING_TIMEOUT:
await asyncio.sleep(1)
found = await self._device.async_request(
self._device.api.check_frequency
)
if found:
break
else:
await self._device.async_request(
self._device.api.cancel_sweep_frequency
)
raise TimeoutError(
"No radiofrequency found within "
f"{LEARNING_TIMEOUT.seconds} seconds"
)
finally:
self.hass.components.persistent_notification.async_dismiss(
notification_id="sweep_frequency"
)
await asyncio.sleep(1)
try:
await self._device.async_request(self._device.api.find_rf_packet)
except (BroadlinkException, OSError) as err:
_LOGGER.debug("Failed to enter learning mode: %s", err)
raise
self.hass.components.persistent_notification.async_create(
f"Press the '{command}' button again.",
title="Learn command",
notification_id="learn_command",
)
try:
start_time = utcnow()
while (utcnow() - start_time) < LEARNING_TIMEOUT:
await asyncio.sleep(1)
try:
code = await self._device.async_request(self._device.api.check_data)
except (ReadError, StorageError):
continue
return b64encode(code).decode("utf8")
raise TimeoutError(
"No radiofrequency code received within "
f"{LEARNING_TIMEOUT.seconds} seconds"
)
finally:
self.hass.components.persistent_notification.async_dismiss(