Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 95 additions & 8 deletions homeassistant/components/broadlink/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from homeassistant.components.remote import (
ATTR_ALTERNATIVE,
ATTR_COMMAND,
ATTR_COMMAND_TYPE,
ATTR_DELAY_SECS,
ATTR_DEVICE,
ATTR_NUM_REPEATS,
Expand All @@ -41,6 +42,10 @@

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
Expand All @@ -64,6 +69,7 @@
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,
}
)
Expand Down Expand Up @@ -266,11 +272,11 @@ async def async_send_command(self, command, **kwargs):
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

Expand All @@ -284,6 +290,7 @@ async def async_learn_command(self, **kwargs):
"""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]

Expand All @@ -293,13 +300,18 @@ async def async_learn_command(self, **kwargs):
)
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)
Expand All @@ -315,8 +327,8 @@ async def async_learn_command(self, **kwargs):
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)

Expand All @@ -336,12 +348,87 @@ async def _async_learn_command(self, command):
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 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 code received")

raise TimeoutError(
"No radiofrequency code received within "
f"{LEARNING_TIMEOUT.seconds} seconds"
)

finally:
self.hass.components.persistent_notification.async_dismiss(
Expand Down