Clean up command learning in the Broadlink integration (#36318)

This commit is contained in:
Felipe Martins Diel 2020-06-09 09:15:46 -03:00 committed by GitHub
parent 7cc3102209
commit 38bb8ef4d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 59 deletions

View File

@ -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)

View File

@ -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"

View File

@ -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"
)