Fix bug in which SimpliSafe websocket won't reconnect on error (#62241)
This commit is contained in:
parent
cb26862d7a
commit
8eb33ede43
1 changed files with 38 additions and 10 deletions
|
@ -12,6 +12,7 @@ from simplipy.errors import (
|
||||||
EndpointUnavailableError,
|
EndpointUnavailableError,
|
||||||
InvalidCredentialsError,
|
InvalidCredentialsError,
|
||||||
SimplipyError,
|
SimplipyError,
|
||||||
|
WebsocketError,
|
||||||
)
|
)
|
||||||
from simplipy.system import SystemNotification
|
from simplipy.system import SystemNotification
|
||||||
from simplipy.system.v3 import (
|
from simplipy.system.v3 import (
|
||||||
|
@ -473,6 +474,7 @@ class SimpliSafe:
|
||||||
self._api = api
|
self._api = api
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._system_notifications: dict[int, set[SystemNotification]] = {}
|
self._system_notifications: dict[int, set[SystemNotification]] = {}
|
||||||
|
self._websocket_reconnect_task: asyncio.Task | None = None
|
||||||
self.entry = entry
|
self.entry = entry
|
||||||
self.initial_event_to_use: dict[int, dict[str, Any]] = {}
|
self.initial_event_to_use: dict[int, dict[str, Any]] = {}
|
||||||
self.systems: dict[int, SystemType] = {}
|
self.systems: dict[int, SystemType] = {}
|
||||||
|
@ -517,11 +519,29 @@ class SimpliSafe:
|
||||||
|
|
||||||
self._system_notifications[system.system_id] = latest_notifications
|
self._system_notifications[system.system_id] = latest_notifications
|
||||||
|
|
||||||
async def _async_websocket_on_connect(self) -> None:
|
async def _async_start_websocket_loop(self) -> None:
|
||||||
"""Define a callback for connecting to the websocket."""
|
"""Define a callback for connecting to the websocket."""
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert self._api.websocket
|
assert self._api.websocket
|
||||||
|
|
||||||
|
should_reconnect = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
await self._api.websocket.async_reconnect()
|
||||||
await self._api.websocket.async_listen()
|
await self._api.websocket.async_listen()
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
LOGGER.debug("Request to cancel websocket loop received")
|
||||||
|
raise
|
||||||
|
except WebsocketError as err:
|
||||||
|
LOGGER.error("Failed to connect to websocket: %s", err)
|
||||||
|
except Exception as err: # pylint: disable=broad-except
|
||||||
|
LOGGER.error("Unknown exception while connecting to websocket: %s", err)
|
||||||
|
|
||||||
|
if should_reconnect:
|
||||||
|
LOGGER.info("Disconnected from websocket; reconnecting")
|
||||||
|
self._websocket_reconnect_task = self._hass.async_create_task(
|
||||||
|
self._async_start_websocket_loop()
|
||||||
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_websocket_on_event(self, event: WebsocketEvent) -> None:
|
def _async_websocket_on_event(self, event: WebsocketEvent) -> None:
|
||||||
|
@ -561,16 +581,24 @@ class SimpliSafe:
|
||||||
assert self._api.refresh_token
|
assert self._api.refresh_token
|
||||||
assert self._api.websocket
|
assert self._api.websocket
|
||||||
|
|
||||||
self._api.websocket.add_connect_callback(self._async_websocket_on_connect)
|
|
||||||
self._api.websocket.add_event_callback(self._async_websocket_on_event)
|
self._api.websocket.add_event_callback(self._async_websocket_on_event)
|
||||||
asyncio.create_task(self._api.websocket.async_connect())
|
self._websocket_reconnect_task = asyncio.create_task(
|
||||||
|
self._async_start_websocket_loop()
|
||||||
|
)
|
||||||
|
|
||||||
async def async_websocket_disconnect_listener(_: Event) -> None:
|
async def async_websocket_disconnect_listener(_: Event) -> None:
|
||||||
"""Define an event handler to disconnect from the websocket."""
|
"""Define an event handler to disconnect from the websocket."""
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert self._api.websocket
|
assert self._api.websocket
|
||||||
|
|
||||||
if self._api.websocket.connected:
|
if self._websocket_reconnect_task:
|
||||||
|
self._websocket_reconnect_task.cancel()
|
||||||
|
try:
|
||||||
|
await self._websocket_reconnect_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
LOGGER.debug("Websocket reconnection task successfully canceled")
|
||||||
|
self._websocket_reconnect_task = None
|
||||||
|
|
||||||
await self._api.websocket.async_disconnect()
|
await self._api.websocket.async_disconnect()
|
||||||
|
|
||||||
self.entry.async_on_unload(
|
self.entry.async_on_unload(
|
||||||
|
@ -621,10 +649,10 @@ class SimpliSafe:
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
assert self._api.websocket
|
assert self._api.websocket
|
||||||
|
|
||||||
if self._api.websocket.connected:
|
# Open a new websocket connection with the fresh token:
|
||||||
# If a websocket connection is open, reconnect it to use the
|
self._websocket_reconnect_task = self._hass.async_create_task(
|
||||||
# new access token:
|
self._async_start_websocket_loop()
|
||||||
asyncio.create_task(self._api.websocket.async_reconnect())
|
)
|
||||||
|
|
||||||
self.entry.async_on_unload(
|
self.entry.async_on_unload(
|
||||||
self._api.add_refresh_token_callback(async_handle_refresh_token)
|
self._api.add_refresh_token_callback(async_handle_refresh_token)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue