1 """Support for Broadlink devices."""
3 from contextlib
import suppress
4 from functools
import partial
6 from typing
import Generic
8 import broadlink
as blk
9 from broadlink.exceptions
import (
13 ConnectionClosedError,
16 from typing_extensions
import TypeVar
31 from .const
import DEFAULT_PORT, DOMAIN, DOMAINS_AND_TYPES
32 from .updater
import BroadlinkUpdateManager, get_update_manager
34 _ApiT = TypeVar(
"_ApiT", bound=blk.Device, default=blk.Device)
36 _LOGGER = logging.getLogger(__name__)
40 """Return the domains available for a device type."""
41 return {d
for d, t
in DOMAINS_AND_TYPES.items()
if device_type
in t}
45 """Manages a Broadlink device."""
49 def __init__(self, hass: HomeAssistant, config: ConfigEntry) ->
None:
50 """Initialize the device."""
53 self.
update_managerupdate_manager: BroadlinkUpdateManager[_ApiT] |
None =
None
56 self.reset_jobs: list[CALLBACK_TYPE] = []
60 """Return the name of the device."""
61 return self.
configconfig.title
65 """Return the unique id of the device."""
66 return self.
configconfig.unique_id
70 """Return the mac address of the device."""
71 return self.
configconfig.data[CONF_MAC]
75 """Return True if the device is available."""
81 async
def async_update(hass: HomeAssistant, entry: ConfigEntry) ->
None:
82 """Update the device and related entities.
84 Triggered when the device is renamed on the frontend.
86 device_registry = dr.async_get(hass)
87 assert entry.unique_id
88 device_entry = device_registry.async_get_device(
89 identifiers={(DOMAIN, entry.unique_id)}
92 device_registry.async_update_device(device_entry.id, name=entry.title)
93 await hass.config_entries.async_reload(entry.entry_id)
96 """Get firmware version."""
98 with suppress(BroadlinkException, OSError):
99 return self.
apiapi.get_fwversion()
103 """Set up the device and related entities."""
104 config = self.
configconfig
107 config.data[CONF_TYPE],
108 (config.data[CONF_HOST], DEFAULT_PORT),
109 bytes.fromhex(config.data[CONF_MAC]),
112 api.timeout = config.data[CONF_TIMEOUT]
120 except AuthenticationError:
124 except (NetworkTimeoutError, OSError)
as err:
125 raise ConfigEntryNotReady
from err
127 except BroadlinkException
as err:
129 "Failed to authenticate to the device at %s: %s", api.host[0], err
136 coordinator = update_manager.coordinator
137 await coordinator.async_config_entry_first_refresh()
140 self.
hasshass.data[DOMAIN].devices[config.entry_id] = self
141 self.reset_jobs.append(config.add_update_listener(self.
async_updateasync_update))
144 await self.
hasshass.config_entries.async_forward_entry_setups(
151 """Unload the device and related entities."""
155 while self.reset_jobs:
156 self.reset_jobs.pop()()
158 return await self.
hasshass.config_entries.async_unload_platforms(
163 """Authenticate to the device."""
165 await self.
hasshass.async_add_executor_job(self.
apiapi.auth)
166 except (BroadlinkException, OSError)
as err:
168 "Failed to authenticate to the device at %s: %s", self.
apiapi.host[0], err
170 if isinstance(err, AuthenticationError):
176 """Send a request to the device."""
177 request = partial(function, *args, **kwargs)
179 return await self.
hasshass.async_add_executor_job(request)
180 except (AuthorizationError, ConnectionClosedError):
183 return await self.
hasshass.async_add_executor_job(request)
186 """Handle an authentication error."""
194 "%s (%s at %s) is locked. Click Configuration in the sidebar, "
195 "click Integrations, click Configure on the device and follow "
196 "the instructions to unlock it"
203 self.
configconfig.async_start_reauth(self.
hasshass, data={CONF_NAME: self.
namename})
bool|None available(self)
None __init__(self, HomeAssistant hass, ConfigEntry config)
def async_request(self, function, *args, **kwargs)
int|None _get_firmware_version(self)
None _async_handle_auth_error(self)
None async_update(HomeAssistant hass, ConfigEntry entry)
set[Platform] get_domains(str device_type)
BroadlinkUpdateManager[_ApiT] get_update_manager(BroadlinkDevice[_ApiT] device)