Skip to content

Commit 11acd6e

Browse files
committed
Merge branch 'async' into PyISY_beta
2 parents f9a75e7 + 2757354 commit 11acd6e

File tree

1 file changed

+24
-6
lines changed

1 file changed

+24
-6
lines changed

pyisy/events.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"Sec-WebSocket-Version": "13",
4949
"Origin": "com.universal-devices.websockets.isy",
5050
}
51-
WS_HEARTBEAT = 30
51+
WS_HEARTBEAT = 60
5252
WS_TIMEOUT = aiohttp.ClientTimeout(total=60, connect=60, sock_connect=60, sock_read=60)
5353
WS_MAX_RETRIES = 4
5454
WS_RETRY_BACKOFF = [0.01, 1, 10, 30, 60] # Seconds
@@ -335,6 +335,7 @@ def __init__(
335335
self.use_https = use_https
336336
self._status = ES_NOT_STARTED
337337
self._lasthb = None
338+
self._hbwait = WS_HEARTBEAT
338339
self._sid = None
339340
self._program_key = None
340341
self.websocket_task = None
@@ -349,12 +350,13 @@ def __init__(
349350
self._url = "wss://" if self.use_https else "ws://"
350351
self._url += f"{self._address}:{self._port}{self._webroot}/rest/subscribe"
351352

352-
def start(self):
353+
def start(self, retries=0):
353354
"""Start the websocket connection."""
354355
if self.status != ES_CONNECTED:
355356
_LOGGER.info("Starting websocket connection.")
356357
self.status = ES_INITIALIZING
357-
self.websocket_task = self._loop.create_task(self.websocket())
358+
self.websocket_task = self._loop.create_task(self.websocket(retries))
359+
self._loop.create_task(self._websocket_guardian())
358360

359361
def stop(self):
360362
"""Close websocket connection."""
@@ -366,13 +368,12 @@ async def reconnect(self, delay=RECONNECT_DELAY, retries=0):
366368
"""Reconnect to a disconnected websocket."""
367369
if self.status == ES_CONNECTED:
368370
return
369-
if self.websocket_task is not None and not self.websocket_task.done():
370-
self.websocket_task.cancel()
371+
self.stop()
371372
self.status = ES_RECONNECTING
372373
_LOGGER.info("PyISY attempting stream reconnect in %ss.", delay)
373374
await asyncio.sleep(delay)
374375
retries = (retries + 1) if retries < WS_MAX_RETRIES else WS_MAX_RETRIES
375-
self.websocket_task = self._loop.create_task(self.websocket(retries))
376+
self.start(retries=retries)
376377

377378
@property
378379
def status(self):
@@ -392,6 +393,23 @@ def last_heartbeat(self):
392393
"""Return the last received heartbeat time from the ISY."""
393394
return self._lasthb
394395

396+
@property
397+
def heartbeat_time(self):
398+
"""Return the time since the last ISY Heartbeat."""
399+
if self._lasthb is not None:
400+
return (now() - self._lasthb).seconds
401+
return 0.0
402+
403+
async def _websocket_guardian(self):
404+
"""Watch and reset websocket connection if no messages received."""
405+
while self.status != ES_STOP_UPDATES:
406+
asyncio.sleep(self._hbwait)
407+
if self.heartbeat_time > self._hbwait:
408+
_LOGGER.debug("Websocket missed a heartbeat, resetting connection.")
409+
self.status = ES_LOST_STREAM_CONNECTION
410+
await self.reconnect()
411+
return
412+
395413
async def _route_message(self, msg):
396414
"""Route a received message from the event stream."""
397415
# check xml formatting

0 commit comments

Comments
 (0)