mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 13:57:10 +00:00
Move SimpliSafe REST API to DataUpdateCoordinator (#41919)
* Mirgrate SimpliSafe REST API to DataUpdateCoordinator * Docstring * More work * Good to go * Linting * Restore previous initial event check * Linting * Comment * Simplify listener * Code review * Cleanup
This commit is contained in:
parent
183f94364a
commit
8b6336a91a
@ -35,15 +35,17 @@ from homeassistant.helpers.dispatcher import (
|
|||||||
async_dispatcher_connect,
|
async_dispatcher_connect,
|
||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.entity import Entity
|
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
|
||||||
from homeassistant.helpers.service import (
|
from homeassistant.helpers.service import (
|
||||||
async_register_admin_service,
|
async_register_admin_service,
|
||||||
verify_domain_control,
|
verify_domain_control,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
CoordinatorEntity,
|
||||||
|
DataUpdateCoordinator,
|
||||||
|
UpdateFailed,
|
||||||
|
)
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
_LOGGER,
|
|
||||||
ATTR_ALARM_DURATION,
|
ATTR_ALARM_DURATION,
|
||||||
ATTR_ALARM_VOLUME,
|
ATTR_ALARM_VOLUME,
|
||||||
ATTR_CHIME_VOLUME,
|
ATTR_CHIME_VOLUME,
|
||||||
@ -56,11 +58,11 @@ from .const import (
|
|||||||
DATA_CLIENT,
|
DATA_CLIENT,
|
||||||
DEFAULT_SCAN_INTERVAL,
|
DEFAULT_SCAN_INTERVAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
LOGGER,
|
||||||
VOLUMES,
|
VOLUMES,
|
||||||
)
|
)
|
||||||
|
|
||||||
DATA_LISTENER = "listener"
|
DATA_LISTENER = "listener"
|
||||||
TOPIC_UPDATE_REST_API = "simplisafe_update_rest_api_{0}"
|
|
||||||
TOPIC_UPDATE_WEBSOCKET = "simplisafe_update_websocket_{0}"
|
TOPIC_UPDATE_WEBSOCKET = "simplisafe_update_websocket_{0}"
|
||||||
|
|
||||||
EVENT_SIMPLISAFE_EVENT = "SIMPLISAFE_EVENT"
|
EVENT_SIMPLISAFE_EVENT = "SIMPLISAFE_EVENT"
|
||||||
@ -147,9 +149,11 @@ def _async_save_refresh_token(hass, config_entry, token):
|
|||||||
|
|
||||||
|
|
||||||
async def async_get_client_id(hass):
|
async def async_get_client_id(hass):
|
||||||
"""Get a client ID (based on the HASS unique ID) for the SimpliSafe API."""
|
"""Get a client ID (based on the HASS unique ID) for the SimpliSafe API.
|
||||||
|
|
||||||
|
Note that SimpliSafe requires full, "dashed" versions of UUIDs.
|
||||||
|
"""
|
||||||
hass_id = await hass.helpers.instance_id.async_get()
|
hass_id = await hass.helpers.instance_id.async_get()
|
||||||
# SimpliSafe requires full, "dashed" versions of UUIDs:
|
|
||||||
return str(UUID(hass_id))
|
return str(UUID(hass_id))
|
||||||
|
|
||||||
|
|
||||||
@ -173,8 +177,6 @@ async def async_setup(hass, config):
|
|||||||
|
|
||||||
async def async_setup_entry(hass, config_entry):
|
async def async_setup_entry(hass, config_entry):
|
||||||
"""Set up SimpliSafe as config entry."""
|
"""Set up SimpliSafe as config entry."""
|
||||||
hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = []
|
|
||||||
|
|
||||||
entry_updates = {}
|
entry_updates = {}
|
||||||
if not config_entry.unique_id:
|
if not config_entry.unique_id:
|
||||||
# If the config entry doesn't already have a unique ID, set one:
|
# If the config entry doesn't already have a unique ID, set one:
|
||||||
@ -201,17 +203,18 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
config_entry.data[CONF_TOKEN], client_id=client_id, session=websession
|
config_entry.data[CONF_TOKEN], client_id=client_id, session=websession
|
||||||
)
|
)
|
||||||
except InvalidCredentialsError:
|
except InvalidCredentialsError:
|
||||||
_LOGGER.error("Invalid credentials provided")
|
LOGGER.error("Invalid credentials provided")
|
||||||
return False
|
return False
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error("Config entry failed: %s", err)
|
LOGGER.error("Config entry failed: %s", err)
|
||||||
raise ConfigEntryNotReady from err
|
raise ConfigEntryNotReady from err
|
||||||
|
|
||||||
_async_save_refresh_token(hass, config_entry, api.refresh_token)
|
_async_save_refresh_token(hass, config_entry, api.refresh_token)
|
||||||
|
|
||||||
simplisafe = SimpliSafe(hass, api, config_entry)
|
simplisafe = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = SimpliSafe(
|
||||||
|
hass, api, config_entry
|
||||||
|
)
|
||||||
await simplisafe.async_init()
|
await simplisafe.async_init()
|
||||||
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = simplisafe
|
|
||||||
|
|
||||||
for platform in SUPPORTED_PLATFORMS:
|
for platform in SUPPORTED_PLATFORMS:
|
||||||
hass.async_create_task(
|
hass.async_create_task(
|
||||||
@ -226,7 +229,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
"""Decorate."""
|
"""Decorate."""
|
||||||
system_id = int(call.data[ATTR_SYSTEM_ID])
|
system_id = int(call.data[ATTR_SYSTEM_ID])
|
||||||
if system_id not in simplisafe.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)
|
||||||
|
|
||||||
@ -240,7 +243,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
"""Decorate."""
|
"""Decorate."""
|
||||||
system = simplisafe.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
|
||||||
await coro(call)
|
await coro(call)
|
||||||
|
|
||||||
@ -254,7 +257,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
try:
|
try:
|
||||||
await system.clear_notifications()
|
await system.clear_notifications()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error("Error during service call: %s", err)
|
LOGGER.error("Error during service call: %s", err)
|
||||||
return
|
return
|
||||||
|
|
||||||
@verify_system_exists
|
@verify_system_exists
|
||||||
@ -265,7 +268,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
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:
|
||||||
_LOGGER.error("Error during service call: %s", err)
|
LOGGER.error("Error during service call: %s", err)
|
||||||
return
|
return
|
||||||
|
|
||||||
@verify_system_exists
|
@verify_system_exists
|
||||||
@ -276,7 +279,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
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:
|
||||||
_LOGGER.error("Error during service call: %s", err)
|
LOGGER.error("Error during service call: %s", err)
|
||||||
return
|
return
|
||||||
|
|
||||||
@verify_system_exists
|
@verify_system_exists
|
||||||
@ -294,7 +297,7 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error("Error during service call: %s", err)
|
LOGGER.error("Error during service call: %s", err)
|
||||||
return
|
return
|
||||||
|
|
||||||
for service, method, schema in [
|
for service, method, schema in [
|
||||||
@ -326,9 +329,8 @@ async def async_unload_entry(hass, entry):
|
|||||||
)
|
)
|
||||||
if unload_ok:
|
if unload_ok:
|
||||||
hass.data[DOMAIN][DATA_CLIENT].pop(entry.entry_id)
|
hass.data[DOMAIN][DATA_CLIENT].pop(entry.entry_id)
|
||||||
for remove_listener in hass.data[DOMAIN][DATA_LISTENER][entry.entry_id]:
|
remove_listener = hass.data[DOMAIN][DATA_LISTENER].pop(entry.entry_id)
|
||||||
remove_listener()
|
remove_listener()
|
||||||
hass.data[DOMAIN][DATA_LISTENER].pop(entry.entry_id)
|
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
@ -349,16 +351,16 @@ class SimpliSafeWebsocket:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _on_connect():
|
def _on_connect():
|
||||||
"""Define a handler to fire when the websocket is connected."""
|
"""Define a handler to fire when the websocket is connected."""
|
||||||
_LOGGER.info("Connected to websocket")
|
LOGGER.info("Connected to websocket")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _on_disconnect():
|
def _on_disconnect():
|
||||||
"""Define a handler to fire when the websocket is disconnected."""
|
"""Define a handler to fire when the websocket is disconnected."""
|
||||||
_LOGGER.info("Disconnected from websocket")
|
LOGGER.info("Disconnected from websocket")
|
||||||
|
|
||||||
def _on_event(self, event):
|
def _on_event(self, event):
|
||||||
"""Define a handler to fire when a new SimpliSafe event arrives."""
|
"""Define a handler to fire when a new SimpliSafe event arrives."""
|
||||||
_LOGGER.debug("New websocket event: %s", event)
|
LOGGER.debug("New websocket event: %s", event)
|
||||||
async_dispatcher_send(
|
async_dispatcher_send(
|
||||||
self._hass, TOPIC_UPDATE_WEBSOCKET.format(event.system_id), event
|
self._hass, TOPIC_UPDATE_WEBSOCKET.format(event.system_id), event
|
||||||
)
|
)
|
||||||
@ -408,6 +410,7 @@ class SimpliSafe:
|
|||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._system_notifications = {}
|
self._system_notifications = {}
|
||||||
self.config_entry = config_entry
|
self.config_entry = config_entry
|
||||||
|
self.coordinator = None
|
||||||
self.initial_event_to_use = {}
|
self.initial_event_to_use = {}
|
||||||
self.systems = {}
|
self.systems = {}
|
||||||
self.websocket = SimpliSafeWebsocket(hass, api.websocket)
|
self.websocket = SimpliSafeWebsocket(hass, api.websocket)
|
||||||
@ -430,7 +433,7 @@ class SimpliSafe:
|
|||||||
if not to_add:
|
if not to_add:
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug("New system notifications: %s", to_add)
|
LOGGER.debug("New system notifications: %s", to_add)
|
||||||
|
|
||||||
self._system_notifications[system.system_id].update(to_add)
|
self._system_notifications[system.system_id].update(to_add)
|
||||||
|
|
||||||
@ -457,10 +460,10 @@ class SimpliSafe:
|
|||||||
"""Define an event handler to disconnect from the websocket."""
|
"""Define an event handler to disconnect from the websocket."""
|
||||||
await self.websocket.async_disconnect()
|
await self.websocket.async_disconnect()
|
||||||
|
|
||||||
self._hass.data[DOMAIN][DATA_LISTENER][self.config_entry.entry_id].append(
|
self._hass.data[DOMAIN][DATA_LISTENER][
|
||||||
self._hass.bus.async_listen_once(
|
self.config_entry.entry_id
|
||||||
EVENT_HOMEASSISTANT_STOP, async_websocket_disconnect
|
] = self._hass.bus.async_listen_once(
|
||||||
)
|
EVENT_HOMEASSISTANT_STOP, async_websocket_disconnect
|
||||||
)
|
)
|
||||||
|
|
||||||
self.systems = await self._api.get_systems()
|
self.systems = await self._api.get_systems()
|
||||||
@ -481,34 +484,28 @@ class SimpliSafe:
|
|||||||
system.system_id
|
system.system_id
|
||||||
] = await system.get_latest_event()
|
] = await system.get_latest_event()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error("Error while fetching initial event: %s", err)
|
LOGGER.error("Error while fetching initial event: %s", err)
|
||||||
self.initial_event_to_use[system.system_id] = {}
|
self.initial_event_to_use[system.system_id] = {}
|
||||||
|
|
||||||
async def refresh(event_time):
|
self.coordinator = DataUpdateCoordinator(
|
||||||
"""Refresh data from the SimpliSafe account."""
|
self._hass,
|
||||||
await self.async_update()
|
LOGGER,
|
||||||
|
name=self.config_entry.data[CONF_USERNAME],
|
||||||
self._hass.data[DOMAIN][DATA_LISTENER][self.config_entry.entry_id].append(
|
update_interval=DEFAULT_SCAN_INTERVAL,
|
||||||
async_track_time_interval(self._hass, refresh, DEFAULT_SCAN_INTERVAL)
|
update_method=self.async_update,
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.async_update()
|
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Get updated data from SimpliSafe."""
|
"""Get updated data from SimpliSafe."""
|
||||||
|
|
||||||
async def update_system(system):
|
async def async_update_system(system):
|
||||||
"""Update a system."""
|
"""Update a system."""
|
||||||
await system.update(cached=False)
|
await system.update(cached=False)
|
||||||
self._async_process_new_notifications(system)
|
self._async_process_new_notifications(system)
|
||||||
_LOGGER.debug('Updated REST API data for "%s"', system.address)
|
|
||||||
async_dispatcher_send(
|
|
||||||
self._hass, TOPIC_UPDATE_REST_API.format(system.system_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
tasks = [update_system(system) for system in self.systems.values()]
|
|
||||||
|
|
||||||
|
tasks = [async_update_system(system) for system in self.systems.values()]
|
||||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
if isinstance(result, InvalidCredentialsError):
|
if isinstance(result, InvalidCredentialsError):
|
||||||
if self._emergency_refresh_token_used:
|
if self._emergency_refresh_token_used:
|
||||||
@ -532,9 +529,10 @@ class SimpliSafe:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
LOGGER.error("Update failed with stored refresh token")
|
||||||
|
raise UpdateFailed from result
|
||||||
|
|
||||||
_LOGGER.warning("SimpliSafe cloud error; trying stored refresh token")
|
LOGGER.warning("SimpliSafe cloud error; trying stored refresh token")
|
||||||
self._emergency_refresh_token_used = True
|
self._emergency_refresh_token_used = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -543,23 +541,23 @@ class SimpliSafe:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error("Error while using stored refresh token: %s", err)
|
LOGGER.error("Error while using stored refresh token: %s", err)
|
||||||
return
|
raise UpdateFailed from err
|
||||||
|
|
||||||
if isinstance(result, EndpointUnavailable):
|
if isinstance(result, EndpointUnavailable):
|
||||||
# In case the user attempt an action not allowed in their current plan,
|
# In case the user attempt an action not allowed in their current plan,
|
||||||
# we merely log that message at INFO level (so the user is aware,
|
# we merely log that message at INFO level (so the user is aware,
|
||||||
# but not spammed with ERROR messages that they cannot change):
|
# but not spammed with ERROR messages that they cannot change):
|
||||||
_LOGGER.info(result)
|
LOGGER.info(result)
|
||||||
return
|
raise UpdateFailed from result
|
||||||
|
|
||||||
if isinstance(result, SimplipyError):
|
if isinstance(result, SimplipyError):
|
||||||
_LOGGER.error("SimpliSafe error while updating: %s", result)
|
LOGGER.error("SimpliSafe error while updating: %s", result)
|
||||||
return
|
raise UpdateFailed from result
|
||||||
|
|
||||||
if isinstance(result, Exception):
|
if isinstance(result, Exception):
|
||||||
_LOGGER.error("Unknown error while updating: %s", result)
|
LOGGER.error("Unknown error while updating: %s", result)
|
||||||
return
|
raise UpdateFailed from result
|
||||||
|
|
||||||
if self._api.refresh_token != self.config_entry.data[CONF_TOKEN]:
|
if self._api.refresh_token != self.config_entry.data[CONF_TOKEN]:
|
||||||
_async_save_refresh_token(
|
_async_save_refresh_token(
|
||||||
@ -572,11 +570,12 @@ class SimpliSafe:
|
|||||||
self._emergency_refresh_token_used = False
|
self._emergency_refresh_token_used = False
|
||||||
|
|
||||||
|
|
||||||
class SimpliSafeEntity(Entity):
|
class SimpliSafeEntity(CoordinatorEntity):
|
||||||
"""Define a base SimpliSafe entity."""
|
"""Define a base SimpliSafe entity."""
|
||||||
|
|
||||||
def __init__(self, simplisafe, system, name, *, serial=None):
|
def __init__(self, simplisafe, system, name, *, serial=None):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
|
super().__init__(simplisafe.coordinator)
|
||||||
self._name = name
|
self._name = name
|
||||||
self._online = True
|
self._online = True
|
||||||
self._simplisafe = simplisafe
|
self._simplisafe = simplisafe
|
||||||
@ -619,11 +618,15 @@ class SimpliSafeEntity(Entity):
|
|||||||
def available(self):
|
def available(self):
|
||||||
"""Return whether the entity is available."""
|
"""Return whether the entity is available."""
|
||||||
# We can easily detect if the V3 system is offline, but no simple check exists
|
# We can easily detect if the V3 system is offline, but no simple check exists
|
||||||
# for the V2 system. Therefore, we mark the entity as available if:
|
# for the V2 system. Therefore, assuming the coordinator hasn't failed, we mark
|
||||||
|
# the entity as available if:
|
||||||
# 1. We can verify that the system is online (assuming True if we can't)
|
# 1. We can verify that the system is online (assuming True if we can't)
|
||||||
# 2. We can verify that the entity is online
|
# 2. We can verify that the entity is online
|
||||||
system_offline = self._system.version == 3 and self._system.offline
|
return (
|
||||||
return not system_offline and self._online
|
self.coordinator.last_update_success
|
||||||
|
and not (self._system.version == 3 and self._system.offline)
|
||||||
|
and self._online
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
@ -675,50 +678,43 @@ class SimpliSafeEntity(Entity):
|
|||||||
|
|
||||||
self.async_update_from_websocket_event(event)
|
self.async_update_from_websocket_event(event)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_coordinator_update(self):
|
||||||
|
"""Update the entity with new REST API data."""
|
||||||
|
self.async_update_from_rest_api()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_websocket_update(self, event):
|
||||||
|
"""Update the entity with new websocket data."""
|
||||||
|
# Ignore this event if it belongs to a system other than this one:
|
||||||
|
if event.system_id != self._system.system_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ignore this event if this entity hasn't expressed interest in its type:
|
||||||
|
if event.event_type not in self.websocket_events_to_listen_for:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ignore this event if it belongs to a entity with a different serial
|
||||||
|
# number from this one's:
|
||||||
|
if (
|
||||||
|
event.event_type in WEBSOCKET_EVENTS_REQUIRING_SERIAL
|
||||||
|
and event.sensor_serial != self._serial
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
self._async_internal_update_from_websocket_event(event)
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
|
await super().async_added_to_hass()
|
||||||
@callback
|
|
||||||
def rest_api_update():
|
|
||||||
"""Update the entity with new REST API data."""
|
|
||||||
self.async_update_from_rest_api()
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.async_on_remove(
|
|
||||||
async_dispatcher_connect(
|
|
||||||
self.hass,
|
|
||||||
TOPIC_UPDATE_REST_API.format(self._system.system_id),
|
|
||||||
rest_api_update,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def websocket_update(event):
|
|
||||||
"""Update the entity with new websocket data."""
|
|
||||||
# Ignore this event if it belongs to a system other than this one:
|
|
||||||
if event.system_id != self._system.system_id:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Ignore this event if this entity hasn't expressed interest in its type:
|
|
||||||
if event.event_type not in self.websocket_events_to_listen_for:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Ignore this event if it belongs to a entity with a different serial
|
|
||||||
# number from this one's:
|
|
||||||
if (
|
|
||||||
event.event_type in WEBSOCKET_EVENTS_REQUIRING_SERIAL
|
|
||||||
and event.sensor_serial != self._serial
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
self._async_internal_update_from_websocket_event(event)
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_dispatcher_connect(
|
async_dispatcher_connect(
|
||||||
self.hass,
|
self.hass,
|
||||||
TOPIC_UPDATE_WEBSOCKET.format(self._system.system_id),
|
TOPIC_UPDATE_WEBSOCKET.format(self._system.system_id),
|
||||||
websocket_update,
|
self._handle_websocket_update,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ from homeassistant.core import callback
|
|||||||
|
|
||||||
from . import SimpliSafeEntity
|
from . import SimpliSafeEntity
|
||||||
from .const import (
|
from .const import (
|
||||||
_LOGGER,
|
|
||||||
ATTR_ALARM_DURATION,
|
ATTR_ALARM_DURATION,
|
||||||
ATTR_ALARM_VOLUME,
|
ATTR_ALARM_VOLUME,
|
||||||
ATTR_CHIME_VOLUME,
|
ATTR_CHIME_VOLUME,
|
||||||
@ -50,6 +49,7 @@ from .const import (
|
|||||||
ATTR_VOICE_PROMPT_VOLUME,
|
ATTR_VOICE_PROMPT_VOLUME,
|
||||||
DATA_CLIENT,
|
DATA_CLIENT,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
LOGGER,
|
||||||
VOLUME_STRING_MAP,
|
VOLUME_STRING_MAP,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if not code or code != self._simplisafe.config_entry.options[CONF_CODE]:
|
if not code or code != self._simplisafe.config_entry.options[CONF_CODE]:
|
||||||
_LOGGER.warning(
|
LOGGER.warning(
|
||||||
"Incorrect alarm code entered (target state: %s): %s", state, code
|
"Incorrect alarm code entered (target state: %s): %s", state, code
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
@ -159,7 +159,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
|||||||
try:
|
try:
|
||||||
await self._system.set_off()
|
await self._system.set_off()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error('Error while disarming "%s": %s', self._system.name, err)
|
LOGGER.error('Error while disarming "%s": %s', self._system.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._state = STATE_ALARM_DISARMED
|
self._state = STATE_ALARM_DISARMED
|
||||||
@ -172,7 +172,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
|||||||
try:
|
try:
|
||||||
await self._system.set_home()
|
await self._system.set_home()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error('Error while arming "%s" (home): %s', self._system.name, err)
|
LOGGER.error('Error while arming "%s" (home): %s', self._system.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._state = STATE_ALARM_ARMED_HOME
|
self._state = STATE_ALARM_ARMED_HOME
|
||||||
@ -185,7 +185,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
|||||||
try:
|
try:
|
||||||
await self._system.set_away()
|
await self._system.set_away()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error('Error while arming "%s" (away): %s', self._system.name, err)
|
LOGGER.error('Error while arming "%s" (away): %s', self._system.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._state = STATE_ALARM_ARMING
|
self._state = STATE_ALARM_ARMING
|
||||||
|
@ -13,7 +13,7 @@ from homeassistant.core import callback
|
|||||||
from homeassistant.helpers import aiohttp_client
|
from homeassistant.helpers import aiohttp_client
|
||||||
|
|
||||||
from . import async_get_client_id
|
from . import async_get_client_id
|
||||||
from .const import _LOGGER, DOMAIN # pylint: disable=unused-import
|
from .const import DOMAIN, LOGGER # pylint: disable=unused-import
|
||||||
|
|
||||||
|
|
||||||
class SimpliSafeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
class SimpliSafeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
@ -62,12 +62,12 @@ class SimpliSafeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
try:
|
try:
|
||||||
simplisafe = await self._async_get_simplisafe_api()
|
simplisafe = await self._async_get_simplisafe_api()
|
||||||
except PendingAuthorizationError:
|
except PendingAuthorizationError:
|
||||||
_LOGGER.info("Awaiting confirmation of MFA email click")
|
LOGGER.info("Awaiting confirmation of MFA email click")
|
||||||
return await self.async_step_mfa()
|
return await self.async_step_mfa()
|
||||||
except InvalidCredentialsError:
|
except InvalidCredentialsError:
|
||||||
errors = {"base": "invalid_credentials"}
|
errors = {"base": "invalid_credentials"}
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error("Unknown error while logging into SimpliSafe: %s", err)
|
LOGGER.error("Unknown error while logging into SimpliSafe: %s", err)
|
||||||
errors = {"base": "unknown"}
|
errors = {"base": "unknown"}
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
@ -101,7 +101,7 @@ class SimpliSafeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
try:
|
try:
|
||||||
simplisafe = await self._async_get_simplisafe_api()
|
simplisafe = await self._async_get_simplisafe_api()
|
||||||
except PendingAuthorizationError:
|
except PendingAuthorizationError:
|
||||||
_LOGGER.error("Still awaiting confirmation of MFA email click")
|
LOGGER.error("Still awaiting confirmation of MFA email click")
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="mfa", errors={"base": "still_awaiting_mfa"}
|
step_id="mfa", errors={"base": "still_awaiting_mfa"}
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
|
|
||||||
from simplipy.system.v3 import VOLUME_HIGH, VOLUME_LOW, VOLUME_MEDIUM, VOLUME_OFF
|
from simplipy.system.v3 import VOLUME_HIGH, VOLUME_LOW, VOLUME_MEDIUM, VOLUME_OFF
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__package__)
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
DOMAIN = "simplisafe"
|
DOMAIN = "simplisafe"
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from homeassistant.components.lock import LockEntity
|
|||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
|
||||||
from . import SimpliSafeEntity
|
from . import SimpliSafeEntity
|
||||||
from .const import _LOGGER, DATA_CLIENT, DOMAIN
|
from .const import DATA_CLIENT, DOMAIN, LOGGER
|
||||||
|
|
||||||
ATTR_LOCK_LOW_BATTERY = "lock_low_battery"
|
ATTR_LOCK_LOW_BATTERY = "lock_low_battery"
|
||||||
ATTR_JAMMED = "jammed"
|
ATTR_JAMMED = "jammed"
|
||||||
@ -48,7 +48,7 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
|||||||
try:
|
try:
|
||||||
await self._lock.lock()
|
await self._lock.lock()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error('Error while locking "%s": %s', self._lock.name, err)
|
LOGGER.error('Error while locking "%s": %s', self._lock.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._is_locked = True
|
self._is_locked = True
|
||||||
@ -58,7 +58,7 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
|||||||
try:
|
try:
|
||||||
await self._lock.unlock()
|
await self._lock.unlock()
|
||||||
except SimplipyError as err:
|
except SimplipyError as err:
|
||||||
_LOGGER.error('Error while unlocking "%s": %s', self._lock.name, err)
|
LOGGER.error('Error while unlocking "%s": %s', self._lock.name, err)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._is_locked = False
|
self._is_locked = False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user