mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Properly demarcate websocket and REST API callbacks in SimpliS… (#33706)
* Properly demarcate websocket and REST API callbacks in SimpliSafe * Docstring * Method names * Cleanup * Remove spurious logging * Remove redundant method * Fix comment * Code review
This commit is contained in:
parent
b3b770476d
commit
6ca2c4da3a
@ -63,7 +63,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
CONF_ACCOUNTS = "accounts"
|
CONF_ACCOUNTS = "accounts"
|
||||||
|
|
||||||
DATA_LISTENER = "listener"
|
DATA_LISTENER = "listener"
|
||||||
TOPIC_UPDATE = "simplisafe_update_data_{0}"
|
TOPIC_UPDATE_REST_API = "simplisafe_update_rest_api_{0}"
|
||||||
|
TOPIC_UPDATE_WEBSOCKET = "simplisafe_update_websocket_{0}"
|
||||||
|
|
||||||
EVENT_SIMPLISAFE_EVENT = "SIMPLISAFE_EVENT"
|
EVENT_SIMPLISAFE_EVENT = "SIMPLISAFE_EVENT"
|
||||||
EVENT_SIMPLISAFE_NOTIFICATION = "SIMPLISAFE_NOTIFICATION"
|
EVENT_SIMPLISAFE_NOTIFICATION = "SIMPLISAFE_NOTIFICATION"
|
||||||
@ -354,7 +355,6 @@ class SimpliSafeWebsocket:
|
|||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._websocket = websocket
|
self._websocket = websocket
|
||||||
self.last_events = {}
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _on_connect():
|
def _on_connect():
|
||||||
@ -369,8 +369,9 @@ class SimpliSafeWebsocket:
|
|||||||
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)
|
||||||
self.last_events[event.system_id] = event
|
async_dispatcher_send(
|
||||||
async_dispatcher_send(self._hass, TOPIC_UPDATE.format(event.system_id))
|
self._hass, TOPIC_UPDATE_WEBSOCKET.format(event.system_id), event
|
||||||
|
)
|
||||||
|
|
||||||
if event.event_type not in WEBSOCKET_EVENTS_TO_TRIGGER_HASS_EVENT:
|
if event.event_type not in WEBSOCKET_EVENTS_TO_TRIGGER_HASS_EVENT:
|
||||||
return
|
return
|
||||||
@ -491,7 +492,9 @@ class SimpliSafe:
|
|||||||
await system.update()
|
await system.update()
|
||||||
self._async_process_new_notifications(system)
|
self._async_process_new_notifications(system)
|
||||||
_LOGGER.debug('Updated REST API data for "%s"', system.address)
|
_LOGGER.debug('Updated REST API data for "%s"', system.address)
|
||||||
async_dispatcher_send(self._hass, TOPIC_UPDATE.format(system.system_id))
|
async_dispatcher_send(
|
||||||
|
self._hass, TOPIC_UPDATE_REST_API.format(system.system_id)
|
||||||
|
)
|
||||||
|
|
||||||
tasks = [update_system(system) for system in self.systems.values()]
|
tasks = [update_system(system) for system in self.systems.values()]
|
||||||
|
|
||||||
@ -538,8 +541,6 @@ class SimpliSafeEntity(Entity):
|
|||||||
|
|
||||||
def __init__(self, simplisafe, system, name, *, serial=None):
|
def __init__(self, simplisafe, system, name, *, serial=None):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self._async_unsub_dispatcher_connect = None
|
|
||||||
self._last_processed_websocket_event = None
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._online = True
|
self._online = True
|
||||||
self._simplisafe = simplisafe
|
self._simplisafe = simplisafe
|
||||||
@ -606,90 +607,9 @@ class SimpliSafeEntity(Entity):
|
|||||||
"""Return the unique ID of the entity."""
|
"""Return the unique ID of the entity."""
|
||||||
return self._serial
|
return self._serial
|
||||||
|
|
||||||
@callback
|
|
||||||
def _async_should_ignore_websocket_event(self, event):
|
|
||||||
"""Return whether this entity should ignore a particular websocket event.
|
|
||||||
|
|
||||||
Note that we can't check for a final condition – whether the event belongs to
|
|
||||||
a particular entity, like a lock – because some events (like arming the system
|
|
||||||
from a keypad _or_ from the website) should impact the same entity.
|
|
||||||
"""
|
|
||||||
# We've already processed this event:
|
|
||||||
if self._last_processed_websocket_event == event:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# This is an event for a system other than the one this entity belongs to:
|
|
||||||
if event.system_id != self._system.system_id:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# This isn't an event that this entity cares about:
|
|
||||||
if event.event_type not in self.websocket_events_to_listen_for:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# This event is targeted at a specific entity whose serial number is different
|
|
||||||
# from this one's:
|
|
||||||
if (
|
|
||||||
event.event_type in WEBSOCKET_EVENTS_REQUIRING_SERIAL
|
|
||||||
and event.sensor_serial != self._serial
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Register callbacks."""
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def update():
|
|
||||||
"""Update the state."""
|
|
||||||
self.update_from_latest_data()
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self._async_unsub_dispatcher_connect = async_dispatcher_connect(
|
|
||||||
self.hass, TOPIC_UPDATE.format(self._system.system_id), update
|
|
||||||
)
|
|
||||||
|
|
||||||
self.update_from_latest_data()
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def update_from_latest_data(self):
|
|
||||||
"""Update the entity."""
|
|
||||||
self.async_update_from_rest_api()
|
|
||||||
|
|
||||||
last_websocket_event = self._simplisafe.websocket.last_events.get(
|
|
||||||
self._system.system_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._async_should_ignore_websocket_event(last_websocket_event):
|
|
||||||
return
|
|
||||||
|
|
||||||
self._last_processed_websocket_event = last_websocket_event
|
|
||||||
|
|
||||||
if last_websocket_event.sensor_type:
|
|
||||||
sensor_type = last_websocket_event.sensor_type.name
|
|
||||||
else:
|
|
||||||
sensor_type = None
|
|
||||||
|
|
||||||
self._attrs.update(
|
|
||||||
{
|
|
||||||
ATTR_LAST_EVENT_INFO: last_websocket_event.info,
|
|
||||||
ATTR_LAST_EVENT_SENSOR_NAME: last_websocket_event.sensor_name,
|
|
||||||
ATTR_LAST_EVENT_SENSOR_TYPE: sensor_type,
|
|
||||||
ATTR_LAST_EVENT_TIMESTAMP: last_websocket_event.timestamp,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self._async_internal_update_from_websocket_event(last_websocket_event)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_update_from_rest_api(self):
|
|
||||||
"""Update the entity with the provided REST API data."""
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_internal_update_from_websocket_event(self, event):
|
def _async_internal_update_from_websocket_event(self, event):
|
||||||
"""Check for connection events and set offline appropriately.
|
"""Perform internal websocket handling prior to handing off."""
|
||||||
|
|
||||||
Should not be called directly.
|
|
||||||
"""
|
|
||||||
if event.event_type == EVENT_CONNECTION_LOST:
|
if event.event_type == EVENT_CONNECTION_LOST:
|
||||||
self._online = False
|
self._online = False
|
||||||
elif event.event_type == EVENT_CONNECTION_RESTORED:
|
elif event.event_type == EVENT_CONNECTION_RESTORED:
|
||||||
@ -701,13 +621,77 @@ class SimpliSafeEntity(Entity):
|
|||||||
if not self._online:
|
if not self._online:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if event.sensor_type:
|
||||||
|
sensor_type = event.sensor_type.name
|
||||||
|
else:
|
||||||
|
sensor_type = None
|
||||||
|
|
||||||
|
self._attrs.update(
|
||||||
|
{
|
||||||
|
ATTR_LAST_EVENT_INFO: event.info,
|
||||||
|
ATTR_LAST_EVENT_SENSOR_NAME: event.sensor_name,
|
||||||
|
ATTR_LAST_EVENT_SENSOR_TYPE: sensor_type,
|
||||||
|
ATTR_LAST_EVENT_TIMESTAMP: event.timestamp,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
self.async_update_from_websocket_event(event)
|
self.async_update_from_websocket_event(event)
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Register callbacks."""
|
||||||
|
|
||||||
|
@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(
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass,
|
||||||
|
TOPIC_UPDATE_WEBSOCKET.format(self._system.system_id),
|
||||||
|
websocket_update,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.async_update_from_rest_api()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_update_from_rest_api(self):
|
||||||
|
"""Update the entity with the provided REST API data."""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_from_websocket_event(self, event):
|
def async_update_from_websocket_event(self, event):
|
||||||
"""Update the entity with the provided websocket API data."""
|
"""Update the entity with the provided websocket event."""
|
||||||
|
raise NotImplementedError()
|
||||||
async def async_will_remove_from_hass(self) -> None:
|
|
||||||
"""Disconnect dispatcher listener when removed."""
|
|
||||||
if self._async_unsub_dispatcher_connect:
|
|
||||||
self._async_unsub_dispatcher_connect()
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user