mirror of
https://github.com/home-assistant/core.git
synced 2025-07-10 06:47:09 +00:00
Streamline SimpliSafe data and token management (#31324)
* Streamline SimpliSafe API usage * Streamline SimpliSafe data and token management * Correctly define self.systems * Inline update method
This commit is contained in:
parent
7687ac8b91
commit
2610415501
@ -176,9 +176,8 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
|
|
||||||
_async_save_refresh_token(hass, config_entry, api.refresh_token)
|
_async_save_refresh_token(hass, config_entry, api.refresh_token)
|
||||||
|
|
||||||
systems = await api.get_systems()
|
simplisafe = SimpliSafe(hass, api, config_entry)
|
||||||
simplisafe = SimpliSafe(hass, api, systems, config_entry)
|
await simplisafe.async_init()
|
||||||
await simplisafe.async_update()
|
|
||||||
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = simplisafe
|
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = simplisafe
|
||||||
|
|
||||||
for component in ("alarm_control_panel", "lock"):
|
for component in ("alarm_control_panel", "lock"):
|
||||||
@ -186,22 +185,6 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
hass.config_entries.async_forward_entry_setup(config_entry, component)
|
hass.config_entries.async_forward_entry_setup(config_entry, component)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def refresh(event_time):
|
|
||||||
"""Refresh data from the SimpliSafe account."""
|
|
||||||
await simplisafe.async_update()
|
|
||||||
_LOGGER.debug("Updated data for all SimpliSafe systems")
|
|
||||||
async_dispatcher_send(hass, TOPIC_UPDATE)
|
|
||||||
|
|
||||||
hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = async_track_time_interval(
|
|
||||||
hass, refresh, DEFAULT_SCAN_INTERVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
# Register the base station for each system:
|
|
||||||
for system in systems.values():
|
|
||||||
hass.async_create_task(
|
|
||||||
async_register_base_station(hass, system, config_entry.entry_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def verify_system_exists(coro):
|
def verify_system_exists(coro):
|
||||||
"""Log an error if a service call uses an invalid system ID."""
|
"""Log an error if a service call uses an invalid system ID."""
|
||||||
@ -209,7 +192,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
async def decorator(call):
|
async def decorator(call):
|
||||||
"""Decorate."""
|
"""Decorate."""
|
||||||
system_id = int(call.data[ATTR_SYSTEM_ID])
|
system_id = int(call.data[ATTR_SYSTEM_ID])
|
||||||
if system_id not in systems:
|
if system_id not in simplisafe.systems:
|
||||||
_LOGGER.error("Unknown system ID in service call: %s", system_id)
|
_LOGGER.error("Unknown system ID in service call: %s", system_id)
|
||||||
return
|
return
|
||||||
await coro(call)
|
await coro(call)
|
||||||
@ -222,7 +205,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
|
|
||||||
async def decorator(call):
|
async def decorator(call):
|
||||||
"""Decorate."""
|
"""Decorate."""
|
||||||
system = systems[int(call.data[ATTR_SYSTEM_ID])]
|
system = simplisafe.systems[int(call.data[ATTR_SYSTEM_ID])]
|
||||||
if system.version != 3:
|
if system.version != 3:
|
||||||
_LOGGER.error("Service only available on V3 systems")
|
_LOGGER.error("Service only available on V3 systems")
|
||||||
return
|
return
|
||||||
@ -234,7 +217,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
@_verify_domain_control
|
@_verify_domain_control
|
||||||
async def remove_pin(call):
|
async def remove_pin(call):
|
||||||
"""Remove a PIN."""
|
"""Remove a PIN."""
|
||||||
system = systems[call.data[ATTR_SYSTEM_ID]]
|
system = simplisafe.systems[call.data[ATTR_SYSTEM_ID]]
|
||||||
try:
|
try:
|
||||||
await system.remove_pin(call.data[ATTR_PIN_LABEL_OR_VALUE])
|
await system.remove_pin(call.data[ATTR_PIN_LABEL_OR_VALUE])
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
@ -245,7 +228,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
@_verify_domain_control
|
@_verify_domain_control
|
||||||
async def set_pin(call):
|
async def set_pin(call):
|
||||||
"""Set a PIN."""
|
"""Set a PIN."""
|
||||||
system = systems[call.data[ATTR_SYSTEM_ID]]
|
system = simplisafe.systems[call.data[ATTR_SYSTEM_ID]]
|
||||||
try:
|
try:
|
||||||
await system.set_pin(call.data[ATTR_PIN_LABEL], call.data[ATTR_PIN_VALUE])
|
await system.set_pin(call.data[ATTR_PIN_LABEL], call.data[ATTR_PIN_VALUE])
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
@ -257,7 +240,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
@_verify_domain_control
|
@_verify_domain_control
|
||||||
async def set_system_properties(call):
|
async def set_system_properties(call):
|
||||||
"""Set one or more system parameters."""
|
"""Set one or more system parameters."""
|
||||||
system = systems[call.data[ATTR_SYSTEM_ID]]
|
system = simplisafe.systems[call.data[ATTR_SYSTEM_ID]]
|
||||||
try:
|
try:
|
||||||
await system.set_properties(
|
await system.set_properties(
|
||||||
{
|
{
|
||||||
@ -303,29 +286,58 @@ async def async_unload_entry(hass, entry):
|
|||||||
class SimpliSafe:
|
class SimpliSafe:
|
||||||
"""Define a SimpliSafe API object."""
|
"""Define a SimpliSafe API object."""
|
||||||
|
|
||||||
def __init__(self, hass, api, systems, config_entry):
|
def __init__(self, hass, api, config_entry):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self._api = api
|
self._api = api
|
||||||
self._config_entry = config_entry
|
self._config_entry = config_entry
|
||||||
self._emergency_refresh_token_used = False
|
self._emergency_refresh_token_used = False
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self.last_event_data = {}
|
self.last_event_data = {}
|
||||||
self.systems = systems
|
self.systems = None
|
||||||
|
|
||||||
async def _update_system(self, system):
|
async def async_init(self):
|
||||||
"""Update a system."""
|
"""Initialize the data class."""
|
||||||
try:
|
self.systems = await self._api.get_systems()
|
||||||
|
|
||||||
|
# Register the base station for each system:
|
||||||
|
for system in self.systems.values():
|
||||||
|
self._hass.async_create_task(
|
||||||
|
async_register_base_station(
|
||||||
|
self._hass, system, self._config_entry.entry_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def refresh(event_time):
|
||||||
|
"""Refresh data from the SimpliSafe account."""
|
||||||
|
await self.async_update()
|
||||||
|
|
||||||
|
self._hass.data[DOMAIN][DATA_LISTENER][
|
||||||
|
self._config_entry.entry_id
|
||||||
|
] = async_track_time_interval(self._hass, refresh, DEFAULT_SCAN_INTERVAL)
|
||||||
|
|
||||||
|
await self.async_update()
|
||||||
|
|
||||||
|
async def async_update(self):
|
||||||
|
"""Get updated data from SimpliSafe."""
|
||||||
|
|
||||||
|
async def update_system(system):
|
||||||
|
"""Update a system."""
|
||||||
await system.update()
|
await system.update()
|
||||||
|
self.last_event_data[system.system_id] = await system.get_latest_event()
|
||||||
|
|
||||||
|
tasks = [update_system(system) for system in self.systems.values()]
|
||||||
|
|
||||||
|
def cancel_tasks():
|
||||||
|
"""Cancel tasks and ensure their cancellation is processed."""
|
||||||
|
for task in tasks:
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
except InvalidCredentialsError:
|
except InvalidCredentialsError:
|
||||||
# SimpliSafe's cloud is a little shaky. At times, a 500 or 502 will
|
cancel_tasks()
|
||||||
# seemingly harm simplisafe-python's existing access token _and_ refresh
|
|
||||||
# token, thus preventing the integration from recovering. However, the
|
|
||||||
# refresh token stored in the config entry escapes unscathed (again,
|
|
||||||
# apparently); so, if we detect that we're in such a situation, try a last-
|
|
||||||
# ditch effort by re-authenticating with the stored token:
|
|
||||||
if self._emergency_refresh_token_used:
|
if self._emergency_refresh_token_used:
|
||||||
# If we've already tried this, log the error, suggest a HASS restart,
|
|
||||||
# and stop the time tracker:
|
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"SimpliSafe authentication disconnected. Please restart HASS."
|
"SimpliSafe authentication disconnected. Please restart HASS."
|
||||||
)
|
)
|
||||||
@ -341,31 +353,26 @@ class SimpliSafe:
|
|||||||
self._config_entry.data[CONF_TOKEN]
|
self._config_entry.data[CONF_TOKEN]
|
||||||
)
|
)
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error(
|
cancel_tasks()
|
||||||
'SimpliSafe error while updating "%s": %s', system.address, err
|
_LOGGER.error("SimpliSafe error while updating: %s", err)
|
||||||
)
|
|
||||||
return
|
return
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
_LOGGER.error('Unknown error while updating "%s": %s', system.address, err)
|
cancel_tasks()
|
||||||
|
_LOGGER.error("Unknown error while updating: %s", err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.last_event_data[system.system_id] = await system.get_latest_event()
|
if self._api.refresh_token_dirty:
|
||||||
|
_async_save_refresh_token(
|
||||||
|
self._hass, self._config_entry, self._api.refresh_token
|
||||||
|
)
|
||||||
|
|
||||||
# If we've reached this point using an emergency refresh token, we're in the
|
# If we've reached this point using an emergency refresh token, we're in the
|
||||||
# clear and we can discard it:
|
# clear and we can discard it:
|
||||||
if self._emergency_refresh_token_used:
|
if self._emergency_refresh_token_used:
|
||||||
self._emergency_refresh_token_used = False
|
self._emergency_refresh_token_used = False
|
||||||
|
|
||||||
async def async_update(self):
|
_LOGGER.debug("Updated data for all SimpliSafe systems")
|
||||||
"""Get updated data from SimpliSafe."""
|
async_dispatcher_send(self._hass, TOPIC_UPDATE)
|
||||||
tasks = [self._update_system(system) for system in self.systems.values()]
|
|
||||||
|
|
||||||
await asyncio.gather(*tasks)
|
|
||||||
|
|
||||||
if self._api.refresh_token_dirty:
|
|
||||||
_async_save_refresh_token(
|
|
||||||
self._hass, self._config_entry, self._api.refresh_token
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SimpliSafeEntity(Entity):
|
class SimpliSafeEntity(Entity):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user