1 """DataUpdateCoordinator for the Schlage integration."""
3 from __future__
import annotations
6 from collections.abc
import Callable
7 from dataclasses
import dataclass
9 from pyschlage
import Lock, Schlage
10 from pyschlage.exceptions
import Error
as SchlageError, NotAuthorizedError
11 from pyschlage.log
import LockLog
19 from .const
import DOMAIN, LOGGER, UPDATE_INTERVAL
24 """Container for cached lock data from the Schlage API."""
32 """Container for cached data from the Schlage API."""
34 locks: dict[str, LockData]
38 """The Schlage data update coordinator."""
40 config_entry: ConfigEntry
42 def __init__(self, hass: HomeAssistant, username: str, api: Schlage) ->
None:
43 """Initialize the class."""
45 hass, LOGGER, name=f
"{DOMAIN} ({username})", update_interval=UPDATE_INTERVAL
48 self.new_locks_callbacks: list[Callable[[dict[str, LockData]],
None]] = []
52 """Fetch the latest data from the Schlage API."""
54 locks = await self.
hasshass.async_add_executor_job(self.
apiapi.locks)
55 except NotAuthorizedError
as ex:
56 raise ConfigEntryAuthFailed
from ex
57 except SchlageError
as ex:
58 raise UpdateFailed(
"Failed to refresh Schlage data")
from ex
59 lock_data = await asyncio.gather(
65 return SchlageData(locks={ld.lock.device_id: ld
for ld
in lock_data})
68 logs: list[LockLog] = []
69 previous_lock_data =
None
70 if self.
datadata
and (previous_lock_data := self.
datadata.locks.get(lock.device_id)):
73 logs = previous_lock_data.logs
76 except NotAuthorizedError
as ex:
77 raise ConfigEntryAuthFailed
from ex
78 except SchlageError
as ex:
79 LOGGER.debug(
'Failed to read logs for lock "%s": %s', lock.name, ex)
81 return LockData(lock=lock, logs=logs)
85 """Add newly discovered locks and remove nonexistent locks."""
86 if self.
datadata
is None:
89 device_registry = dr.async_get(self.
hasshass)
90 devices = dr.async_entries_for_config_entry(
93 previous_locks = set()
94 previous_locks_by_lock_id = {}
95 for device
in devices:
96 for domain, identifier
in device.identifiers:
98 previous_locks.add(identifier)
99 previous_locks_by_lock_id[identifier] = device
101 current_locks = set(self.
datadata.locks.keys())
103 if removed_locks := previous_locks - current_locks:
104 LOGGER.debug(
"Removed locks: %s",
", ".join(removed_locks))
105 for lock_id
in removed_locks:
106 device_registry.async_update_device(
107 device_id=previous_locks_by_lock_id[lock_id].id,
108 remove_config_entry_id=self.
config_entryconfig_entry.entry_id,
111 if new_lock_ids := current_locks - previous_locks:
112 LOGGER.debug(
"New locks found: %s",
", ".join(new_lock_ids))
113 new_locks = {lock_id: self.
datadata.locks[lock_id]
for lock_id
in new_lock_ids}
114 for new_lock_callback
in self.new_locks_callbacks:
115 new_lock_callback(new_locks)
LockData _get_lock_data(self, Lock lock)
None __init__(self, HomeAssistant hass, str username, Schlage api)
None _add_remove_locks(self)
SchlageData _async_update_data(self)
Callable[[], None] async_add_listener(self, CALLBACK_TYPE update_callback, Any context=None)
Callable[[], None] async_add_listener(self, CALLBACK_TYPE update_callback, Any context=None)