Skip to content

Commit 134269e

Browse files
authored
Merge pull request #150 from awarecan/read-timeout
Add read timeout
2 parents 7a95445 + f3b0d0b commit 134269e

File tree

1 file changed

+38
-27
lines changed

1 file changed

+38
-27
lines changed

nest/nest.py

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,11 @@ def online(self):
269269

270270
@property
271271
def structure(self):
272-
return Structure(self._device['structure_id'],
273-
self._nest_api)
272+
if 'structure_id' in self._device:
273+
return Structure(self._device['structure_id'],
274+
self._nest_api)
275+
else:
276+
return None
274277

275278
@property
276279
def where(self):
@@ -299,7 +302,7 @@ def where(self, value):
299302

300303
@property
301304
def description(self):
302-
return self._device['name_long']
305+
return self._device.get('name_long')
303306

304307
@property
305308
def is_thermostat(self):
@@ -321,7 +324,7 @@ def is_thermostat(self):
321324

322325
@property
323326
def _device(self):
324-
return self._devices[THERMOSTATS][self._serial]
327+
return self._devices.get(THERMOSTATS, {}).get(self._serial, {})
325328

326329
@property
327330
def _shared(self):
@@ -335,7 +338,7 @@ def _track(self):
335338

336339
@property
337340
def software_version(self):
338-
return self._device['software_version']
341+
return self._device.get('software_version')
339342

340343
@property
341344
def fan(self):
@@ -509,7 +512,7 @@ def _round_temp(self, temp):
509512

510513
@property
511514
def temperature_scale(self):
512-
return self._device['temperature_scale']
515+
return self._device.get('temperature_scale')
513516

514517
@property
515518
def is_locked(self):
@@ -552,11 +555,11 @@ def temperature(self, value):
552555
@property
553556
def target(self):
554557
if self.mode == 'heat-cool':
555-
low = self._device[self._temp_key('target_temperature_low')]
556-
high = self._device[self._temp_key('target_temperature_high')]
558+
low = self._device.get(self._temp_key('target_temperature_low'))
559+
high = self._device.get(self._temp_key('target_temperature_high'))
557560
return LowHighTuple(low, high)
558561

559-
return self._device[self._temp_key('target_temperature')]
562+
return self._device.get(self._temp_key('target_temperature'))
560563

561564
@target.setter
562565
def target(self, value):
@@ -677,7 +680,7 @@ def is_smoke_co_alarm(self):
677680

678681
@property
679682
def _device(self):
680-
return self._devices[SMOKE_CO_ALARMS][self._serial]
683+
return self._devices.get(SMOKE_CO_ALARMS, {}).get(self._serial, {})
681684

682685
@property
683686
def auto_away(self):
@@ -1104,7 +1107,7 @@ def is_camera(self):
11041107

11051108
@property
11061109
def _device(self):
1107-
return self._devices[CAMERAS][self._serial]
1110+
return self._devices.get(CAMERAS, {}).get(self._serial, {})
11081111

11091112
@property
11101113
def ongoing_event(self):
@@ -1348,7 +1351,8 @@ def web_url(http://github.com/self):
13481351
class Structure(NestBase):
13491352
@property
13501353
def _structure(self):
1351-
return self._nest_api._status[STRUCTURES][self._serial]
1354+
return self._nest_api._status.get(
1355+
STRUCTURES, {}).get(self._serial, {})
13521356

13531357
def __repr__(self):
13541358
return str(self._structure)
@@ -1725,8 +1729,13 @@ def _open_data_stream(self, path="/"):
17251729

17261730
# Opens the data stream
17271731
headers = {'Accept': 'text/event-stream'}
1732+
# Set Connection Timeout to 30 seconds
1733+
# Set Read Timeout to 5 mintues, Nest Stream API will send
1734+
# keep alive event every 30 seconds, 5 mintues is long enough
1735+
# for us to belive network issue occurred
17281736
response = self._session.get(url, stream=True, headers=headers,
1729-
allow_redirects=False)
1737+
allow_redirects=False,
1738+
timeout=(30, 300))
17301739

17311740
_LOGGER.debug("<< %s", response.status_code)
17321741
if response.status_code == 401:
@@ -1742,10 +1751,12 @@ def _open_data_stream(self, path="/"):
17421751
if response.status_code == 307:
17431752
redirect_url = response.headers['Location']
17441753
_LOGGER.debug(">> STREAM %s", redirect_url)
1754+
# For stream API, we have to deal redirect manually
17451755
response = self._session.get(redirect_url,
17461756
allow_redirects=False,
17471757
headers=headers,
1748-
stream=True)
1758+
stream=True,
1759+
timeout=(30, 300))
17491760
_LOGGER.debug("<< %s", response.status_code)
17501761
if response.status_code == 429:
17511762
response = self._handle_ratelimit(response, 'GET', url, None,
@@ -1785,6 +1796,8 @@ def _start_event_loop(self, response, queue, ready_event, update_event):
17851796

17861797
if not ready_event.is_set():
17871798
ready_event.set()
1799+
except requests.exceptions.ConnectionError:
1800+
_LOGGER.warning("Haven't received data from Nest in 5 mintues")
17881801
finally:
17891802
_LOGGER.debug("Stopping event loop.")
17901803
queue.clear()
@@ -1867,30 +1880,28 @@ def _status(self):
18671880
except AuthorizationError as authorization_error:
18681881
self._queue_lock.release()
18691882
raise authorization_error
1870-
except Exception:
1871-
# other error will fall back to pull mode
1872-
pass
1883+
except Exception as error:
1884+
# other error still set update_event to trigger retry
1885+
_LOGGER.debug("Exception occurred in processing stream:"
1886+
" %s", error)
1887+
self._queue.clear()
1888+
self._update_event.set()
18731889
self._queue_lock.release()
18741890

1875-
value = self._queue[0]['data'] if len(self._queue) > 0 else None
1876-
if value is None:
1877-
# fall back to pull mode
1878-
_LOGGER.info("Fall back to pull mode")
1879-
value = self._get("/")
1880-
1891+
value = self._queue[0]['data'] if len(self._queue) > 0 else {}
18811892
return value
18821893

18831894
@property
18841895
def _metadata(self):
1885-
return self._status[METADATA]
1896+
return self._status.get(METADATA, {})
18861897

18871898
@property
18881899
def client_version(self):
1889-
return self._metadata['client_version']
1900+
return self._metadata.get('client_version')
18901901

18911902
@property
18921903
def _devices(self):
1893-
return self._status[DEVICES]
1904+
return self._status.get(DEVICES, {})
18941905

18951906
@property
18961907
def devices(self):
@@ -1922,7 +1933,7 @@ def cameras(self):
19221933
@property
19231934
def structures(self):
19241935
return [Structure(stid, self)
1925-
for stid in self._status[STRUCTURES]]
1936+
for stid in self._status.get(STRUCTURES, [])]
19261937

19271938
@property
19281939
def urls(self):

0 commit comments

Comments
 (0)