mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Remove simplisafe websocket (#50213)
This commit is contained in:
parent
86393bdbba
commit
d4601e00fd
@ -3,18 +3,7 @@ import asyncio
|
||||
from uuid import UUID
|
||||
|
||||
from simplipy import API
|
||||
from simplipy.entity import EntityTypes
|
||||
from simplipy.errors import EndpointUnavailable, InvalidCredentialsError, SimplipyError
|
||||
from simplipy.websocket import (
|
||||
EVENT_CAMERA_MOTION_DETECTED,
|
||||
EVENT_CONNECTION_LOST,
|
||||
EVENT_CONNECTION_RESTORED,
|
||||
EVENT_DOORBELL_DETECTED,
|
||||
EVENT_ENTRY_DELAY,
|
||||
EVENT_LOCK_LOCKED,
|
||||
EVENT_LOCK_UNLOCKED,
|
||||
EVENT_SECRET_ALERT_TRIGGERED,
|
||||
)
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import ATTR_CODE, CONF_CODE, CONF_TOKEN, CONF_USERNAME
|
||||
@ -25,10 +14,6 @@ from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
from homeassistant.helpers.service import (
|
||||
async_register_admin_service,
|
||||
verify_domain_control,
|
||||
@ -57,9 +42,7 @@ from .const import (
|
||||
)
|
||||
|
||||
DATA_LISTENER = "listener"
|
||||
TOPIC_UPDATE_WEBSOCKET = "simplisafe_update_websocket_{0}"
|
||||
|
||||
EVENT_SIMPLISAFE_EVENT = "SIMPLISAFE_EVENT"
|
||||
EVENT_SIMPLISAFE_NOTIFICATION = "SIMPLISAFE_NOTIFICATION"
|
||||
|
||||
DEFAULT_SOCKET_MIN_RETRY = 15
|
||||
@ -71,23 +54,7 @@ PLATFORMS = (
|
||||
"sensor",
|
||||
)
|
||||
|
||||
WEBSOCKET_EVENTS_REQUIRING_SERIAL = [EVENT_LOCK_LOCKED, EVENT_LOCK_UNLOCKED]
|
||||
WEBSOCKET_EVENTS_TO_TRIGGER_HASS_EVENT = [
|
||||
EVENT_CAMERA_MOTION_DETECTED,
|
||||
EVENT_DOORBELL_DETECTED,
|
||||
EVENT_ENTRY_DELAY,
|
||||
EVENT_SECRET_ALERT_TRIGGERED,
|
||||
]
|
||||
|
||||
ATTR_CATEGORY = "category"
|
||||
ATTR_LAST_EVENT_CHANGED_BY = "last_event_changed_by"
|
||||
ATTR_LAST_EVENT_INFO = "last_event_info"
|
||||
ATTR_LAST_EVENT_SENSOR_NAME = "last_event_sensor_name"
|
||||
ATTR_LAST_EVENT_SENSOR_SERIAL = "last_event_sensor_serial"
|
||||
ATTR_LAST_EVENT_SENSOR_TYPE = "last_event_sensor_type"
|
||||
ATTR_LAST_EVENT_TIMESTAMP = "last_event_timestamp"
|
||||
ATTR_LAST_EVENT_TYPE = "last_event_type"
|
||||
ATTR_LAST_EVENT_TYPE = "last_event_type"
|
||||
ATTR_MESSAGE = "message"
|
||||
ATTR_PIN_LABEL = "label"
|
||||
ATTR_PIN_LABEL_OR_VALUE = "label_or_pin"
|
||||
@ -337,66 +304,6 @@ async def async_reload_entry(hass, config_entry):
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
|
||||
class SimpliSafeWebsocket:
|
||||
"""Define a SimpliSafe websocket "manager" object."""
|
||||
|
||||
def __init__(self, hass, websocket):
|
||||
"""Initialize."""
|
||||
self._hass = hass
|
||||
self._websocket = websocket
|
||||
|
||||
@staticmethod
|
||||
def _on_connect():
|
||||
"""Define a handler to fire when the websocket is connected."""
|
||||
LOGGER.info("Connected to websocket")
|
||||
|
||||
@staticmethod
|
||||
def _on_disconnect():
|
||||
"""Define a handler to fire when the websocket is disconnected."""
|
||||
LOGGER.info("Disconnected from websocket")
|
||||
|
||||
def _on_event(self, event):
|
||||
"""Define a handler to fire when a new SimpliSafe event arrives."""
|
||||
LOGGER.debug("New websocket event: %s", event)
|
||||
async_dispatcher_send(
|
||||
self._hass, TOPIC_UPDATE_WEBSOCKET.format(event.system_id), event
|
||||
)
|
||||
|
||||
if event.event_type not in WEBSOCKET_EVENTS_TO_TRIGGER_HASS_EVENT:
|
||||
return
|
||||
|
||||
if event.sensor_type:
|
||||
sensor_type = event.sensor_type.name
|
||||
else:
|
||||
sensor_type = None
|
||||
|
||||
self._hass.bus.async_fire(
|
||||
EVENT_SIMPLISAFE_EVENT,
|
||||
event_data={
|
||||
ATTR_LAST_EVENT_CHANGED_BY: event.changed_by,
|
||||
ATTR_LAST_EVENT_TYPE: event.event_type,
|
||||
ATTR_LAST_EVENT_INFO: event.info,
|
||||
ATTR_LAST_EVENT_SENSOR_NAME: event.sensor_name,
|
||||
ATTR_LAST_EVENT_SENSOR_SERIAL: event.sensor_serial,
|
||||
ATTR_LAST_EVENT_SENSOR_TYPE: sensor_type,
|
||||
ATTR_SYSTEM_ID: event.system_id,
|
||||
ATTR_LAST_EVENT_TIMESTAMP: event.timestamp,
|
||||
},
|
||||
)
|
||||
|
||||
async def async_connect(self):
|
||||
"""Register handlers and connect to the websocket."""
|
||||
self._websocket.on_connect(self._on_connect)
|
||||
self._websocket.on_disconnect(self._on_disconnect)
|
||||
self._websocket.on_event(self._on_event)
|
||||
|
||||
await self._websocket.async_connect()
|
||||
|
||||
async def async_disconnect(self):
|
||||
"""Disconnect from the websocket."""
|
||||
await self._websocket.async_disconnect()
|
||||
|
||||
|
||||
class SimpliSafe:
|
||||
"""Define a SimpliSafe data object."""
|
||||
|
||||
@ -408,9 +315,7 @@ class SimpliSafe:
|
||||
self._system_notifications = {}
|
||||
self.config_entry = config_entry
|
||||
self.coordinator = None
|
||||
self.initial_event_to_use = {}
|
||||
self.systems = {}
|
||||
self.websocket = SimpliSafeWebsocket(hass, api.websocket)
|
||||
|
||||
@callback
|
||||
def _async_process_new_notifications(self, system):
|
||||
@ -451,22 +356,6 @@ class SimpliSafe:
|
||||
|
||||
async def async_init(self):
|
||||
"""Initialize the data class."""
|
||||
# 2021-04-29: Disabling connection to the websocket due to the SimpliSafe cloud
|
||||
# removing it (and not providing a clear alternative).
|
||||
# asyncio.create_task(self.websocket.async_connect())
|
||||
|
||||
# async def async_websocket_disconnect(_):
|
||||
# """Define an event handler to disconnect from the websocket."""
|
||||
# await self.websocket.async_disconnect()
|
||||
|
||||
# 2021-04-29: Disabling disconnection from the websocket due to the SimpliSafe
|
||||
# cloud removing it (and not providing a clear alternative).
|
||||
# self._hass.data[DOMAIN][DATA_LISTENER][self.config_entry.entry_id].append(
|
||||
# self._hass.bus.async_listen_once(
|
||||
# EVENT_HOMEASSISTANT_STOP, async_websocket_disconnect
|
||||
# )
|
||||
# )
|
||||
|
||||
self.systems = await self._api.get_systems()
|
||||
for system in self.systems.values():
|
||||
self._system_notifications[system.system_id] = set()
|
||||
@ -477,17 +366,6 @@ class SimpliSafe:
|
||||
)
|
||||
)
|
||||
|
||||
# Future events will come from the websocket, but since subscription to the
|
||||
# websocket doesn't provide the most recent event, we grab it from the REST
|
||||
# API to ensure event-related attributes aren't empty on startup:
|
||||
try:
|
||||
self.initial_event_to_use[
|
||||
system.system_id
|
||||
] = await system.get_latest_event()
|
||||
except SimplipyError as err:
|
||||
LOGGER.error("Error while fetching initial event: %s", err)
|
||||
self.initial_event_to_use[system.system_id] = {}
|
||||
|
||||
self.coordinator = DataUpdateCoordinator(
|
||||
self._hass,
|
||||
LOGGER,
|
||||
@ -557,36 +435,13 @@ class SimpliSafeEntity(CoordinatorEntity):
|
||||
self._online = True
|
||||
self._simplisafe = simplisafe
|
||||
self._system = system
|
||||
self.websocket_events_to_listen_for = [
|
||||
EVENT_CONNECTION_LOST,
|
||||
EVENT_CONNECTION_RESTORED,
|
||||
]
|
||||
|
||||
if serial:
|
||||
self._serial = serial
|
||||
else:
|
||||
self._serial = system.serial
|
||||
|
||||
try:
|
||||
sensor_type = EntityTypes(
|
||||
simplisafe.initial_event_to_use[system.system_id].get("sensorType")
|
||||
)
|
||||
except ValueError:
|
||||
sensor_type = EntityTypes.unknown
|
||||
|
||||
self._attrs = {
|
||||
ATTR_LAST_EVENT_INFO: simplisafe.initial_event_to_use[system.system_id].get(
|
||||
"info"
|
||||
),
|
||||
ATTR_LAST_EVENT_SENSOR_NAME: simplisafe.initial_event_to_use[
|
||||
system.system_id
|
||||
].get("sensorName"),
|
||||
ATTR_LAST_EVENT_SENSOR_TYPE: sensor_type.name,
|
||||
ATTR_LAST_EVENT_TIMESTAMP: simplisafe.initial_event_to_use[
|
||||
system.system_id
|
||||
].get("eventTimestamp"),
|
||||
ATTR_SYSTEM_ID: system.system_id,
|
||||
}
|
||||
self._attrs = {ATTR_SYSTEM_ID: system.system_id}
|
||||
|
||||
self._device_info = {
|
||||
"identifiers": {(DOMAIN, system.system_id)},
|
||||
@ -626,76 +481,15 @@ class SimpliSafeEntity(CoordinatorEntity):
|
||||
"""Return the unique ID of the entity."""
|
||||
return self._serial
|
||||
|
||||
@callback
|
||||
def _async_internal_update_from_websocket_event(self, event):
|
||||
"""Perform internal websocket handling prior to handing off."""
|
||||
if event.event_type == EVENT_CONNECTION_LOST:
|
||||
self._online = False
|
||||
elif event.event_type == EVENT_CONNECTION_RESTORED:
|
||||
self._online = True
|
||||
|
||||
# It's uncertain whether SimpliSafe events will still propagate down the
|
||||
# websocket when the base station is offline. Just in case, we guard against
|
||||
# further action until connection is restored:
|
||||
if not self._online:
|
||||
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)
|
||||
|
||||
@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):
|
||||
"""Register callbacks."""
|
||||
await super().async_added_to_hass()
|
||||
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
TOPIC_UPDATE_WEBSOCKET.format(self._system.system_id),
|
||||
self._handle_websocket_update,
|
||||
)
|
||||
)
|
||||
|
||||
self.async_update_from_rest_api()
|
||||
|
||||
@callback
|
||||
@ -703,10 +497,6 @@ class SimpliSafeEntity(CoordinatorEntity):
|
||||
"""Update the entity with the provided REST API data."""
|
||||
raise NotImplementedError()
|
||||
|
||||
@callback
|
||||
def async_update_from_websocket_event(self, event):
|
||||
"""Update the entity with the provided websocket event."""
|
||||
|
||||
|
||||
class SimpliSafeBaseSensor(SimpliSafeEntity):
|
||||
"""Define a SimpliSafe base (binary) sensor."""
|
||||
|
@ -3,19 +3,6 @@ import re
|
||||
|
||||
from simplipy.errors import SimplipyError
|
||||
from simplipy.system import SystemStates
|
||||
from simplipy.websocket import (
|
||||
EVENT_ALARM_CANCELED,
|
||||
EVENT_ALARM_TRIGGERED,
|
||||
EVENT_ARMED_AWAY,
|
||||
EVENT_ARMED_AWAY_BY_KEYPAD,
|
||||
EVENT_ARMED_AWAY_BY_REMOTE,
|
||||
EVENT_ARMED_HOME,
|
||||
EVENT_AWAY_EXIT_DELAY_BY_KEYPAD,
|
||||
EVENT_AWAY_EXIT_DELAY_BY_REMOTE,
|
||||
EVENT_DISARMED_BY_MASTER_PIN,
|
||||
EVENT_DISARMED_BY_REMOTE,
|
||||
EVENT_HOME_EXIT_DELAY,
|
||||
)
|
||||
|
||||
from homeassistant.components.alarm_control_panel import (
|
||||
FORMAT_NUMBER,
|
||||
@ -96,21 +83,6 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
||||
else:
|
||||
self._state = None
|
||||
|
||||
for event_type in (
|
||||
EVENT_ALARM_CANCELED,
|
||||
EVENT_ALARM_TRIGGERED,
|
||||
EVENT_ARMED_AWAY,
|
||||
EVENT_ARMED_AWAY_BY_KEYPAD,
|
||||
EVENT_ARMED_AWAY_BY_REMOTE,
|
||||
EVENT_ARMED_HOME,
|
||||
EVENT_AWAY_EXIT_DELAY_BY_KEYPAD,
|
||||
EVENT_AWAY_EXIT_DELAY_BY_REMOTE,
|
||||
EVENT_DISARMED_BY_MASTER_PIN,
|
||||
EVENT_DISARMED_BY_REMOTE,
|
||||
EVENT_HOME_EXIT_DELAY,
|
||||
):
|
||||
self.websocket_events_to_listen_for.append(event_type)
|
||||
|
||||
@property
|
||||
def changed_by(self):
|
||||
"""Return info about who changed the alarm last."""
|
||||
@ -237,33 +209,3 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity):
|
||||
self._state = STATE_ALARM_DISARMED
|
||||
else:
|
||||
self._state = None
|
||||
|
||||
@callback
|
||||
def async_update_from_websocket_event(self, event):
|
||||
"""Update the entity with the provided websocket API event data."""
|
||||
if event.event_type in (
|
||||
EVENT_ALARM_CANCELED,
|
||||
EVENT_DISARMED_BY_MASTER_PIN,
|
||||
EVENT_DISARMED_BY_REMOTE,
|
||||
):
|
||||
self._state = STATE_ALARM_DISARMED
|
||||
elif event.event_type == EVENT_ALARM_TRIGGERED:
|
||||
self._state = STATE_ALARM_TRIGGERED
|
||||
elif event.event_type in (
|
||||
EVENT_ARMED_AWAY,
|
||||
EVENT_ARMED_AWAY_BY_KEYPAD,
|
||||
EVENT_ARMED_AWAY_BY_REMOTE,
|
||||
):
|
||||
self._state = STATE_ALARM_ARMED_AWAY
|
||||
elif event.event_type == EVENT_ARMED_HOME:
|
||||
self._state = STATE_ALARM_ARMED_HOME
|
||||
elif event.event_type in (
|
||||
EVENT_AWAY_EXIT_DELAY_BY_KEYPAD,
|
||||
EVENT_AWAY_EXIT_DELAY_BY_REMOTE,
|
||||
EVENT_HOME_EXIT_DELAY,
|
||||
):
|
||||
self._state = STATE_ALARM_ARMING
|
||||
else:
|
||||
self._state = None
|
||||
|
||||
self._changed_by = event.changed_by
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""Support for SimpliSafe locks."""
|
||||
from simplipy.errors import SimplipyError
|
||||
from simplipy.lock import LockStates
|
||||
from simplipy.websocket import EVENT_LOCK_LOCKED, EVENT_LOCK_UNLOCKED
|
||||
|
||||
from homeassistant.components.lock import LockEntity
|
||||
from homeassistant.core import callback
|
||||
@ -39,9 +38,6 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
||||
self._lock = lock
|
||||
self._is_locked = None
|
||||
|
||||
for event_type in (EVENT_LOCK_LOCKED, EVENT_LOCK_UNLOCKED):
|
||||
self.websocket_events_to_listen_for.append(event_type)
|
||||
|
||||
@property
|
||||
def is_locked(self):
|
||||
"""Return true if the lock is locked."""
|
||||
@ -81,11 +77,3 @@ class SimpliSafeLock(SimpliSafeEntity, LockEntity):
|
||||
)
|
||||
|
||||
self._is_locked = self._lock.state == LockStates.locked
|
||||
|
||||
@callback
|
||||
def async_update_from_websocket_event(self, event):
|
||||
"""Update the entity with the provided websocket event data."""
|
||||
if event.event_type == EVENT_LOCK_LOCKED:
|
||||
self._is_locked = True
|
||||
else:
|
||||
self._is_locked = False
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "SimpliSafe",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
||||
"requirements": ["simplisafe-python==9.6.10"],
|
||||
"requirements": ["simplisafe-python==10.0.0"],
|
||||
"codeowners": ["@bachya"],
|
||||
"iot_class": "cloud_polling"
|
||||
}
|
||||
|
@ -2067,7 +2067,7 @@ simplehound==0.3
|
||||
simplepush==1.1.4
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==9.6.10
|
||||
simplisafe-python==10.0.0
|
||||
|
||||
# homeassistant.components.sisyphus
|
||||
sisyphus-control==3.0
|
||||
|
@ -1101,7 +1101,7 @@ sharkiqpy==0.1.8
|
||||
simplehound==0.3
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==9.6.10
|
||||
simplisafe-python==10.0.0
|
||||
|
||||
# homeassistant.components.slack
|
||||
slackclient==2.5.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user