diff --git a/homeassistant/components/broadlink/__init__.py b/homeassistant/components/broadlink/__init__.py index d8b7f60b5b4..fe0c79a0b19 100644 --- a/homeassistant/components/broadlink/__init__.py +++ b/homeassistant/components/broadlink/__init__.py @@ -2,7 +2,6 @@ import asyncio from base64 import b64decode, b64encode from binascii import unhexlify -from datetime import timedelta import logging import re @@ -13,7 +12,7 @@ from homeassistant.const import CONF_HOST import homeassistant.helpers.config_validation as cv from homeassistant.util.dt import utcnow -from .const import CONF_PACKET, DOMAIN, SERVICE_LEARN, SERVICE_SEND +from .const import CONF_PACKET, DOMAIN, LEARNING_TIMEOUT, SERVICE_LEARN, SERVICE_SEND _LOGGER = logging.getLogger(__name__) @@ -84,7 +83,7 @@ async def async_setup_service(hass, host, device): _LOGGER.info("Press the key you want Home Assistant to learn") start_time = utcnow() - while (utcnow() - start_time) < timedelta(seconds=20): + while (utcnow() - start_time) < LEARNING_TIMEOUT: await asyncio.sleep(1) try: packet = await device.async_request(device.api.check_data) diff --git a/homeassistant/components/broadlink/const.py b/homeassistant/components/broadlink/const.py index 3264ec225ca..a8a448a9aff 100644 --- a/homeassistant/components/broadlink/const.py +++ b/homeassistant/components/broadlink/const.py @@ -1,7 +1,8 @@ """Constants for broadlink platform.""" +from datetime import timedelta + CONF_PACKET = "packet" -DEFAULT_LEARNING_TIMEOUT = 20 DEFAULT_NAME = "Broadlink" DEFAULT_PORT = 80 DEFAULT_RETRY = 3 @@ -9,6 +10,8 @@ DEFAULT_TIMEOUT = 5 DOMAIN = "broadlink" +LEARNING_TIMEOUT = timedelta(seconds=30) + SERVICE_LEARN = "learn" SERVICE_SEND = "send" diff --git a/homeassistant/components/broadlink/remote.py b/homeassistant/components/broadlink/remote.py index 03ecb9b7634..d7b4c051bcc 100644 --- a/homeassistant/components/broadlink/remote.py +++ b/homeassistant/components/broadlink/remote.py @@ -24,7 +24,6 @@ from homeassistant.components.remote import ( ATTR_DELAY_SECS, ATTR_DEVICE, ATTR_NUM_REPEATS, - ATTR_TIMEOUT, DEFAULT_DELAY_SECS, DOMAIN as COMPONENT, PLATFORM_SCHEMA, @@ -40,10 +39,10 @@ from homeassistant.util.dt import utcnow from . import DOMAIN, data_packet, hostname, mac_address from .const import ( - DEFAULT_LEARNING_TIMEOUT, DEFAULT_NAME, DEFAULT_PORT, DEFAULT_TIMEOUT, + LEARNING_TIMEOUT, RM4_TYPES, RM_TYPES, ) @@ -74,10 +73,7 @@ SERVICE_SEND_SCHEMA = MINIMUM_SERVICE_SCHEMA.extend( ) SERVICE_LEARN_SCHEMA = MINIMUM_SERVICE_SCHEMA.extend( - { - vol.Optional(ATTR_ALTERNATIVE, default=False): cv.boolean, - vol.Optional(ATTR_TIMEOUT, default=DEFAULT_LEARNING_TIMEOUT): cv.positive_int, - } + {vol.Optional(ATTR_ALTERNATIVE, default=False): cv.boolean} ) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -267,7 +263,6 @@ class BroadlinkRemote(RemoteEntity): commands = kwargs[ATTR_COMMAND] device = kwargs[ATTR_DEVICE] toggle = kwargs[ATTR_ALTERNATIVE] - timeout = kwargs[ATTR_TIMEOUT] if not self._state: return @@ -275,66 +270,47 @@ class BroadlinkRemote(RemoteEntity): should_store = False for command in commands: try: - should_store |= await self._async_learn_code( - command, device, toggle, timeout - ) - except (AuthorizationError, DeviceOfflineError): + code = await self._async_learn_command(command) + if toggle: + code = [code, await self._async_learn_command(command)] + except (AuthorizationError, DeviceOfflineError) as err_msg: + _LOGGER.error("Failed to learn '%s': %s", command, err_msg) break - except BroadlinkException: - pass + except (BroadlinkException, TimeoutError) as err_msg: + _LOGGER.error("Failed to learn '%s': %s", command, err_msg) + continue + else: + self._codes.setdefault(device, {}).update({command: code}) + should_store = True if should_store: await self._code_storage.async_save(self._codes) - async def _async_learn_code(self, command, device, toggle, timeout): - """Learn a code from a remote. - - Capture an additional code for toggle commands. - """ + async def _async_learn_command(self, command): + """Learn a command from a remote.""" try: - if not toggle: - code = await self._async_capture_code(command, timeout) - else: - code = [ - await self._async_capture_code(command, timeout), - await self._async_capture_code(command, timeout), - ] - except TimeoutError: - _LOGGER.error("Failed to learn '%s/%s': No code received", command, device) - return False + await self.device.async_request(self.device.api.enter_learning) except BroadlinkException as err_msg: - _LOGGER.error("Failed to learn '%s/%s': %s", command, device, err_msg) + _LOGGER.debug("Failed to enter learning mode: %s", err_msg) raise - self._codes.setdefault(device, {}).update({command: code}) - return True - - async def _async_capture_code(self, command, timeout): - """Enter learning mode and capture a code from a remote.""" - await self.device.async_request(self.device.api.enter_learning) - self.hass.components.persistent_notification.async_create( f"Press the '{command}' button.", title="Learn command", notification_id="learn_command", ) - code = None - start_time = utcnow() - while (utcnow() - start_time) < timedelta(seconds=timeout): - await asyncio.sleep(1) - try: - code = await self.device.async_request(self.device.api.check_data) - except (ReadError, StorageError): - continue - else: - break - - self.hass.components.persistent_notification.async_dismiss( - notification_id="learn_command" - ) - - if code is None: - raise TimeoutError - - return b64encode(code).decode("utf8") + 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 code received") + finally: + self.hass.components.persistent_notification.async_dismiss( + notification_id="learn_command" + )