mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 09:47:52 +00:00
Bump broadlink from 0.16.0 to 0.17.0 (#47779)
This commit is contained in:
parent
92852b9c10
commit
9ca0cd5464
@ -39,11 +39,7 @@ class BroadlinkFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
async def async_set_device(self, device, raise_on_progress=True):
|
||||
"""Define a device for the config flow."""
|
||||
supported_types = {
|
||||
device_type
|
||||
for device_types in DOMAINS_AND_TYPES
|
||||
for device_type in device_types[1]
|
||||
}
|
||||
supported_types = set.union(*DOMAINS_AND_TYPES.values())
|
||||
if device.type not in supported_types:
|
||||
_LOGGER.error(
|
||||
"Unsupported device: %s. If it worked before, please open "
|
||||
|
@ -5,11 +5,26 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
|
||||
DOMAIN = "broadlink"
|
||||
|
||||
DOMAINS_AND_TYPES = (
|
||||
(REMOTE_DOMAIN, ("RM2", "RM4")),
|
||||
(SENSOR_DOMAIN, ("A1", "RM2", "RM4")),
|
||||
(SWITCH_DOMAIN, ("BG1", "MP1", "RM2", "RM4", "SP1", "SP2", "SP4", "SP4B")),
|
||||
)
|
||||
DOMAINS_AND_TYPES = {
|
||||
REMOTE_DOMAIN: {"RM4MINI", "RM4PRO", "RMMINI", "RMMINIB", "RMPRO"},
|
||||
SENSOR_DOMAIN: {"A1", "RM4MINI", "RM4PRO", "RMPRO"},
|
||||
SWITCH_DOMAIN: {
|
||||
"BG1",
|
||||
"MP1",
|
||||
"RM4MINI",
|
||||
"RM4PRO",
|
||||
"RMMINI",
|
||||
"RMMINIB",
|
||||
"RMPRO",
|
||||
"SP1",
|
||||
"SP2",
|
||||
"SP2S",
|
||||
"SP3",
|
||||
"SP3S",
|
||||
"SP4",
|
||||
"SP4B",
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
DEFAULT_TIMEOUT = 5
|
||||
|
@ -22,9 +22,9 @@ from .updater import get_update_manager
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_domains(device_type):
|
||||
def get_domains(dev_type):
|
||||
"""Return the domains available for a device type."""
|
||||
return {domain for domain, types in DOMAINS_AND_TYPES if device_type in types}
|
||||
return {d for d, t in DOMAINS_AND_TYPES.items() if dev_type in t}
|
||||
|
||||
|
||||
class BroadlinkDevice:
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "broadlink",
|
||||
"name": "Broadlink",
|
||||
"documentation": "https://www.home-assistant.io/integrations/broadlink",
|
||||
"requirements": ["broadlink==0.16.0"],
|
||||
"requirements": ["broadlink==0.17.0"],
|
||||
"codeowners": ["@danielhiversen", "@felipediel"],
|
||||
"config_flow": true
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ from homeassistant.components.remote import (
|
||||
DOMAIN as RM_DOMAIN,
|
||||
PLATFORM_SCHEMA,
|
||||
SERVICE_DELETE_COMMAND,
|
||||
SERVICE_LEARN_COMMAND,
|
||||
SERVICE_SEND_COMMAND,
|
||||
SUPPORT_DELETE_COMMAND,
|
||||
SUPPORT_LEARN_COMMAND,
|
||||
RemoteEntity,
|
||||
@ -129,6 +131,7 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
|
||||
self._codes = {}
|
||||
self._flags = defaultdict(int)
|
||||
self._state = True
|
||||
self._lock = asyncio.Lock()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@ -171,39 +174,44 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
|
||||
"sw_version": self._device.fw_version,
|
||||
}
|
||||
|
||||
def get_code(self, command, device):
|
||||
"""Return a code and a boolean indicating a toggle command.
|
||||
def _extract_codes(self, commands, device=None):
|
||||
"""Extract a list of codes.
|
||||
|
||||
If the command starts with `b64:`, extract the code from it.
|
||||
Otherwise, extract the code from the dictionary, using the device
|
||||
and command as keys.
|
||||
Otherwise, extract the code from storage, using the command and
|
||||
device as keys.
|
||||
|
||||
You need to change the flag whenever a toggle command is sent
|
||||
successfully. Use `self._flags[device] ^= 1`.
|
||||
The codes are returned in sublists. For toggle commands, the
|
||||
sublist contains two codes that must be sent alternately with
|
||||
each call.
|
||||
"""
|
||||
if command.startswith("b64:"):
|
||||
code, is_toggle_cmd = command[4:], False
|
||||
code_list = []
|
||||
for cmd in commands:
|
||||
if cmd.startswith("b64:"):
|
||||
codes = [cmd[4:]]
|
||||
|
||||
else:
|
||||
if device is None:
|
||||
raise KeyError("You need to specify a device")
|
||||
raise ValueError("You need to specify a device")
|
||||
|
||||
try:
|
||||
code = self._codes[device][command]
|
||||
codes = self._codes[device][cmd]
|
||||
except KeyError as err:
|
||||
raise KeyError("Command not found") from err
|
||||
raise ValueError(f"Command not found: {repr(cmd)}") from err
|
||||
|
||||
# For toggle commands, alternate between codes in a list.
|
||||
if isinstance(code, list):
|
||||
code = code[self._flags[device]]
|
||||
is_toggle_cmd = True
|
||||
if isinstance(codes, list):
|
||||
codes = codes[:]
|
||||
else:
|
||||
is_toggle_cmd = False
|
||||
codes = [codes]
|
||||
|
||||
for idx, code in enumerate(codes):
|
||||
try:
|
||||
return data_packet(code), is_toggle_cmd
|
||||
codes[idx] = data_packet(code)
|
||||
except ValueError as err:
|
||||
raise ValueError("Invalid code") from err
|
||||
raise ValueError(f"Invalid code: {repr(code)}") from err
|
||||
|
||||
code_list.append(codes)
|
||||
return code_list
|
||||
|
||||
@callback
|
||||
def get_codes(self):
|
||||
@ -261,43 +269,49 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
|
||||
device = kwargs.get(ATTR_DEVICE)
|
||||
repeat = kwargs[ATTR_NUM_REPEATS]
|
||||
delay = kwargs[ATTR_DELAY_SECS]
|
||||
service = f"{RM_DOMAIN}.{SERVICE_SEND_COMMAND}"
|
||||
|
||||
if not self._state:
|
||||
_LOGGER.warning(
|
||||
"remote.send_command canceled: %s entity is turned off", self.entity_id
|
||||
"%s canceled: %s entity is turned off", service, self.entity_id
|
||||
)
|
||||
return
|
||||
|
||||
should_delay = False
|
||||
try:
|
||||
code_list = self._extract_codes(commands, device)
|
||||
except ValueError as err:
|
||||
_LOGGER.error("Failed to call %s: %s", service, err)
|
||||
raise
|
||||
|
||||
for _, cmd in product(range(repeat), commands):
|
||||
if should_delay:
|
||||
rf_flags = {0xB2, 0xD7}
|
||||
if not hasattr(self._device.api, "sweep_frequency") and any(
|
||||
c[0] in rf_flags for codes in code_list for c in codes
|
||||
):
|
||||
err_msg = f"{self.entity_id} doesn't support sending RF commands"
|
||||
_LOGGER.error("Failed to call %s: %s", service, err_msg)
|
||||
raise ValueError(err_msg)
|
||||
|
||||
at_least_one_sent = False
|
||||
for _, codes in product(range(repeat), code_list):
|
||||
if at_least_one_sent:
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
try:
|
||||
code, is_toggle_cmd = self.get_code(cmd, device)
|
||||
|
||||
except (KeyError, ValueError) as err:
|
||||
_LOGGER.error("Failed to send '%s': %s", cmd, err)
|
||||
should_delay = False
|
||||
continue
|
||||
if len(codes) > 1:
|
||||
code = codes[self._flags[device]]
|
||||
else:
|
||||
code = codes[0]
|
||||
|
||||
try:
|
||||
await self._device.async_request(self._device.api.send_data, code)
|
||||
|
||||
except (AuthorizationError, NetworkTimeoutError, OSError) as err:
|
||||
_LOGGER.error("Failed to send '%s': %s", cmd, err)
|
||||
except (BroadlinkException, OSError) as err:
|
||||
_LOGGER.error("Error during %s: %s", service, err)
|
||||
break
|
||||
|
||||
except BroadlinkException as err:
|
||||
_LOGGER.error("Failed to send '%s': %s", cmd, err)
|
||||
should_delay = False
|
||||
continue
|
||||
|
||||
should_delay = True
|
||||
if is_toggle_cmd:
|
||||
if len(codes) > 1:
|
||||
self._flags[device] ^= 1
|
||||
at_least_one_sent = True
|
||||
|
||||
if at_least_one_sent:
|
||||
self._flag_storage.async_delay_save(self.get_flags, FLAG_SAVE_DELAY)
|
||||
|
||||
async def async_learn_command(self, **kwargs):
|
||||
@ -307,18 +321,26 @@ class BroadlinkRemote(RemoteEntity, RestoreEntity):
|
||||
command_type = kwargs[ATTR_COMMAND_TYPE]
|
||||
device = kwargs[ATTR_DEVICE]
|
||||
toggle = kwargs[ATTR_ALTERNATIVE]
|
||||
service = f"{RM_DOMAIN}.{SERVICE_LEARN_COMMAND}"
|
||||
|
||||
if not self._state:
|
||||
_LOGGER.warning(
|
||||
"remote.learn_command canceled: %s entity is turned off", self.entity_id
|
||||
"%s canceled: %s entity is turned off", service, self.entity_id
|
||||
)
|
||||
return
|
||||
|
||||
async with self._lock:
|
||||
if command_type == COMMAND_TYPE_IR:
|
||||
learn_command = self._async_learn_ir_command
|
||||
else:
|
||||
|
||||
elif hasattr(self._device.api, "sweep_frequency"):
|
||||
learn_command = self._async_learn_rf_command
|
||||
|
||||
else:
|
||||
err_msg = f"{self.entity_id} doesn't support learning RF commands"
|
||||
_LOGGER.error("Failed to call %s: %s", service, err_msg)
|
||||
raise ValueError(err_msg)
|
||||
|
||||
should_store = False
|
||||
|
||||
for command in commands:
|
||||
|
@ -109,7 +109,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Broadlink switch."""
|
||||
device = hass.data[DOMAIN].devices[config_entry.entry_id]
|
||||
|
||||
if device.api.type in {"RM2", "RM4"}:
|
||||
if device.api.type in {"RM4MINI", "RM4PRO", "RMMINI", "RMMINIB", "RMPRO"}:
|
||||
platform_data = hass.data[DOMAIN].platforms.get(SWITCH_DOMAIN, {})
|
||||
user_defined_switches = platform_data.get(device.api.mac, {})
|
||||
switches = [
|
||||
@ -119,12 +119,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
elif device.api.type == "SP1":
|
||||
switches = [BroadlinkSP1Switch(device)]
|
||||
|
||||
elif device.api.type == "SP2":
|
||||
elif device.api.type in {"SP2", "SP2S", "SP3", "SP3S", "SP4", "SP4B"}:
|
||||
switches = [BroadlinkSP2Switch(device)]
|
||||
|
||||
elif device.api.type in {"SP4", "SP4B"}:
|
||||
switches = [BroadlinkSP4Switch(device)]
|
||||
|
||||
elif device.api.type == "BG1":
|
||||
switches = [BroadlinkBG1Slot(device, slot) for slot in range(1, 3)]
|
||||
|
||||
@ -143,7 +140,6 @@ class BroadlinkSwitch(SwitchEntity, RestoreEntity, ABC):
|
||||
self._command_on = command_on
|
||||
self._command_off = command_off
|
||||
self._coordinator = device.update_manager.coordinator
|
||||
self._device_class = None
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
@ -174,7 +170,7 @@ class BroadlinkSwitch(SwitchEntity, RestoreEntity, ABC):
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return device class."""
|
||||
return self._device_class
|
||||
return DEVICE_CLASS_SWITCH
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
@ -254,7 +250,6 @@ class BroadlinkSP1Switch(BroadlinkSwitch):
|
||||
def __init__(self, device):
|
||||
"""Initialize the switch."""
|
||||
super().__init__(device, 1, 0)
|
||||
self._device_class = DEVICE_CLASS_OUTLET
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
@ -277,10 +272,8 @@ class BroadlinkSP2Switch(BroadlinkSP1Switch):
|
||||
def __init__(self, device, *args, **kwargs):
|
||||
"""Initialize the switch."""
|
||||
super().__init__(device, *args, **kwargs)
|
||||
self._state = self._coordinator.data["state"]
|
||||
self._load_power = self._coordinator.data["load_power"]
|
||||
if device.api.model == "SC1":
|
||||
self._device_class = DEVICE_CLASS_SWITCH
|
||||
self._state = self._coordinator.data["pwr"]
|
||||
self._load_power = self._coordinator.data.get("power")
|
||||
|
||||
@property
|
||||
def assumed_state(self):
|
||||
@ -292,33 +285,12 @@ class BroadlinkSP2Switch(BroadlinkSP1Switch):
|
||||
"""Return the current power usage in Watt."""
|
||||
return self._load_power
|
||||
|
||||
@callback
|
||||
def update_data(self):
|
||||
"""Update data."""
|
||||
if self._coordinator.last_update_success:
|
||||
self._state = self._coordinator.data["state"]
|
||||
self._load_power = self._coordinator.data["load_power"]
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class BroadlinkSP4Switch(BroadlinkSP1Switch):
|
||||
"""Representation of a Broadlink SP4 switch."""
|
||||
|
||||
def __init__(self, device, *args, **kwargs):
|
||||
"""Initialize the switch."""
|
||||
super().__init__(device, *args, **kwargs)
|
||||
self._state = self._coordinator.data["pwr"]
|
||||
|
||||
@property
|
||||
def assumed_state(self):
|
||||
"""Return True if unable to access real state of the switch."""
|
||||
return False
|
||||
|
||||
@callback
|
||||
def update_data(self):
|
||||
"""Update data."""
|
||||
if self._coordinator.last_update_success:
|
||||
self._state = self._coordinator.data["pwr"]
|
||||
self._load_power = self._coordinator.data.get("power")
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -330,7 +302,6 @@ class BroadlinkMP1Slot(BroadlinkSwitch):
|
||||
super().__init__(device, 1, 0)
|
||||
self._slot = slot
|
||||
self._state = self._coordinator.data[f"s{slot}"]
|
||||
self._device_class = DEVICE_CLASS_OUTLET
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
@ -374,7 +345,6 @@ class BroadlinkBG1Slot(BroadlinkSwitch):
|
||||
super().__init__(device, 1, 0)
|
||||
self._slot = slot
|
||||
self._state = self._coordinator.data[f"pwr{slot}"]
|
||||
self._device_class = DEVICE_CLASS_OUTLET
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
@ -391,6 +361,11 @@ class BroadlinkBG1Slot(BroadlinkSwitch):
|
||||
"""Return True if unable to access real state of the switch."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return device class."""
|
||||
return DEVICE_CLASS_OUTLET
|
||||
|
||||
@callback
|
||||
def update_data(self):
|
||||
"""Update data."""
|
||||
|
@ -1,17 +1,9 @@
|
||||
"""Support for fetching data from Broadlink devices."""
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import timedelta
|
||||
from functools import partial
|
||||
import logging
|
||||
|
||||
import broadlink as blk
|
||||
from broadlink.exceptions import (
|
||||
AuthorizationError,
|
||||
BroadlinkException,
|
||||
CommandNotSupportedError,
|
||||
NetworkTimeoutError,
|
||||
StorageError,
|
||||
)
|
||||
from broadlink.exceptions import AuthorizationError, BroadlinkException
|
||||
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
from homeassistant.util import dt
|
||||
@ -21,17 +13,20 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
def get_update_manager(device):
|
||||
"""Return an update manager for a given Broadlink device."""
|
||||
if device.api.model.startswith("RM mini"):
|
||||
return BroadlinkRMMini3UpdateManager(device)
|
||||
|
||||
update_managers = {
|
||||
"A1": BroadlinkA1UpdateManager,
|
||||
"BG1": BroadlinkBG1UpdateManager,
|
||||
"MP1": BroadlinkMP1UpdateManager,
|
||||
"RM2": BroadlinkRMUpdateManager,
|
||||
"RM4": BroadlinkRMUpdateManager,
|
||||
"RM4MINI": BroadlinkRMUpdateManager,
|
||||
"RM4PRO": BroadlinkRMUpdateManager,
|
||||
"RMMINI": BroadlinkRMUpdateManager,
|
||||
"RMMINIB": BroadlinkRMUpdateManager,
|
||||
"RMPRO": BroadlinkRMUpdateManager,
|
||||
"SP1": BroadlinkSP1UpdateManager,
|
||||
"SP2": BroadlinkSP2UpdateManager,
|
||||
"SP2S": BroadlinkSP2UpdateManager,
|
||||
"SP3": BroadlinkSP2UpdateManager,
|
||||
"SP3S": BroadlinkSP2UpdateManager,
|
||||
"SP4": BroadlinkSP4UpdateManager,
|
||||
"SP4B": BroadlinkSP4UpdateManager,
|
||||
}
|
||||
@ -114,28 +109,18 @@ class BroadlinkMP1UpdateManager(BroadlinkUpdateManager):
|
||||
return await self.device.async_request(self.device.api.check_power)
|
||||
|
||||
|
||||
class BroadlinkRMMini3UpdateManager(BroadlinkUpdateManager):
|
||||
"""Manages updates for Broadlink RM mini 3 devices."""
|
||||
|
||||
async def async_fetch_data(self):
|
||||
"""Fetch data from the device."""
|
||||
hello = partial(
|
||||
blk.discover,
|
||||
discover_ip_address=self.device.api.host[0],
|
||||
timeout=self.device.api.timeout,
|
||||
)
|
||||
devices = await self.device.hass.async_add_executor_job(hello)
|
||||
if not devices:
|
||||
raise NetworkTimeoutError("The device is offline")
|
||||
return {}
|
||||
|
||||
|
||||
class BroadlinkRMUpdateManager(BroadlinkUpdateManager):
|
||||
"""Manages updates for Broadlink RM2 and RM4 devices."""
|
||||
"""Manages updates for Broadlink remotes."""
|
||||
|
||||
async def async_fetch_data(self):
|
||||
"""Fetch data from the device."""
|
||||
return await self.device.async_request(self.device.api.check_sensors)
|
||||
device = self.device
|
||||
|
||||
if hasattr(device.api, "check_sensors"):
|
||||
return await device.async_request(device.api.check_sensors)
|
||||
|
||||
await device.async_request(device.api.update)
|
||||
return {}
|
||||
|
||||
|
||||
class BroadlinkSP1UpdateManager(BroadlinkUpdateManager):
|
||||
@ -151,14 +136,14 @@ class BroadlinkSP2UpdateManager(BroadlinkUpdateManager):
|
||||
|
||||
async def async_fetch_data(self):
|
||||
"""Fetch data from the device."""
|
||||
device = self.device
|
||||
|
||||
data = {}
|
||||
data["state"] = await self.device.async_request(self.device.api.check_power)
|
||||
try:
|
||||
data["load_power"] = await self.device.async_request(
|
||||
self.device.api.get_energy
|
||||
)
|
||||
except (CommandNotSupportedError, StorageError):
|
||||
data["load_power"] = None
|
||||
data["pwr"] = await device.async_request(device.api.check_power)
|
||||
|
||||
if hasattr(device.api, "get_energy"):
|
||||
data["power"] = await device.async_request(device.api.get_energy)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
@ -381,7 +381,7 @@ boto3==1.9.252
|
||||
bravia-tv==1.0.8
|
||||
|
||||
# homeassistant.components.broadlink
|
||||
broadlink==0.16.0
|
||||
broadlink==0.17.0
|
||||
|
||||
# homeassistant.components.brother
|
||||
brother==0.2.1
|
||||
|
@ -211,7 +211,7 @@ bond-api==0.1.11
|
||||
bravia-tv==1.0.8
|
||||
|
||||
# homeassistant.components.broadlink
|
||||
broadlink==0.16.0
|
||||
broadlink==0.17.0
|
||||
|
||||
# homeassistant.components.brother
|
||||
brother==0.2.1
|
||||
|
@ -12,7 +12,7 @@ BROADLINK_DEVICES = {
|
||||
"34ea34befc25",
|
||||
"RM mini 3",
|
||||
"Broadlink",
|
||||
"RM2",
|
||||
"RMMINI",
|
||||
0x2737,
|
||||
57,
|
||||
8,
|
||||
@ -22,7 +22,7 @@ BROADLINK_DEVICES = {
|
||||
"34ea34b43b5a",
|
||||
"RM mini 3",
|
||||
"Broadlink",
|
||||
"RM4",
|
||||
"RMMINIB",
|
||||
0x5F36,
|
||||
44017,
|
||||
10,
|
||||
@ -32,7 +32,7 @@ BROADLINK_DEVICES = {
|
||||
"34ea34b43d22",
|
||||
"RM pro",
|
||||
"Broadlink",
|
||||
"RM2",
|
||||
"RMPRO",
|
||||
0x2787,
|
||||
20025,
|
||||
7,
|
||||
@ -42,7 +42,7 @@ BROADLINK_DEVICES = {
|
||||
"34ea34c43f31",
|
||||
"RM4 pro",
|
||||
"Broadlink",
|
||||
"RM4",
|
||||
"RM4PRO",
|
||||
0x6026,
|
||||
52,
|
||||
4,
|
||||
@ -62,7 +62,7 @@ BROADLINK_DEVICES = {
|
||||
"34ea34b61d2c",
|
||||
"LB1",
|
||||
"Broadlink",
|
||||
"SmartBulb",
|
||||
"LB1",
|
||||
0x504E,
|
||||
57,
|
||||
5,
|
||||
@ -96,9 +96,6 @@ class BroadlinkDevice:
|
||||
with patch(
|
||||
"homeassistant.components.broadlink.device.blk.gendevice",
|
||||
return_value=mock_api,
|
||||
), patch(
|
||||
"homeassistant.components.broadlink.updater.blk.discover",
|
||||
return_value=[mock_api],
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
Loading…
x
Reference in New Issue
Block a user