Set directv unavailable state when errors returned for longer then a minute (#19014)

* Fix unavailable

Change setting to unavailable when getting request exceptions only after 1 minute has past since 1st occurrence.

* Put common code in _check_state_available

Put common code to determine if available should be set to False in method _check_state_available
This commit is contained in:
ehendrix23 2018-12-06 23:26:49 -07:00 committed by Martin Hjelmare
parent ce736e7ba1
commit 8a62bc9237
2 changed files with 57 additions and 7 deletions

View File

@ -133,6 +133,7 @@ class DirecTvDevice(MediaPlayerDevice):
self._is_client = device != '0' self._is_client = device != '0'
self._assumed_state = None self._assumed_state = None
self._available = False self._available = False
self._first_error_timestamp = None
if self._is_client: if self._is_client:
_LOGGER.debug("Created DirecTV client %s for device %s", _LOGGER.debug("Created DirecTV client %s for device %s",
@ -142,7 +143,7 @@ class DirecTvDevice(MediaPlayerDevice):
def update(self): def update(self):
"""Retrieve latest state.""" """Retrieve latest state."""
_LOGGER.debug("Updating status for %s", self._name) _LOGGER.debug("%s: Updating status", self.entity_id)
try: try:
self._available = True self._available = True
self._is_standby = self.dtv.get_standby() self._is_standby = self.dtv.get_standby()
@ -156,6 +157,7 @@ class DirecTvDevice(MediaPlayerDevice):
else: else:
self._current = self.dtv.get_tuned() self._current = self.dtv.get_tuned()
if self._current['status']['code'] == 200: if self._current['status']['code'] == 200:
self._first_error_timestamp = None
self._is_recorded = self._current.get('uniqueId')\ self._is_recorded = self._current.get('uniqueId')\
is not None is not None
self._paused = self._last_position == \ self._paused = self._last_position == \
@ -165,15 +167,41 @@ class DirecTvDevice(MediaPlayerDevice):
self._last_update = dt_util.utcnow() if not self._paused \ self._last_update = dt_util.utcnow() if not self._paused \
or self._last_update is None else self._last_update or self._last_update is None else self._last_update
else: else:
self._available = False # If an error is received then only set to unavailable if
# this started at least 1 minute ago.
log_message = "{}: Invalid status {} received".format(
self.entity_id,
self._current['status']['code']
)
if self._check_state_available():
_LOGGER.debug(log_message)
else:
_LOGGER.error(log_message)
except requests.RequestException as ex: except requests.RequestException as ex:
_LOGGER.error("Request error trying to update current status for" _LOGGER.error("%s: Request error trying to update current status: "
" %s. %s", self._name, ex) "%s", self.entity_id, ex)
self._available = False self._check_state_available()
except Exception:
except Exception as ex:
_LOGGER.error("%s: Exception trying to update current status: %s",
self.entity_id, ex)
self._available = False self._available = False
if not self._first_error_timestamp:
self._first_error_timestamp = dt_util.utcnow()
raise raise
def _check_state_available(self):
"""Set to unavailable if issue been occurring over 1 minute."""
if not self._first_error_timestamp:
self._first_error_timestamp = dt_util.utcnow()
else:
tdelta = dt_util.utcnow() - self._first_error_timestamp
if tdelta.total_seconds() >= 60:
self._available = False
return self._available
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return device specific state attributes.""" """Return device specific state attributes."""

View File

@ -515,7 +515,7 @@ async def test_available(hass, platforms, main_dtv, mock_now):
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state.state != STATE_UNAVAILABLE assert state.state != STATE_UNAVAILABLE
# Make update fail (i.e. DVR offline) # Make update fail 1st time
next_update = next_update + timedelta(minutes=5) next_update = next_update + timedelta(minutes=5)
with patch.object( with patch.object(
main_dtv, 'get_standby', side_effect=requests.RequestException), \ main_dtv, 'get_standby', side_effect=requests.RequestException), \
@ -523,6 +523,28 @@ async def test_available(hass, platforms, main_dtv, mock_now):
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(MAIN_ENTITY_ID)
assert state.state != STATE_UNAVAILABLE
# Make update fail 2nd time within 1 minute
next_update = next_update + timedelta(seconds=30)
with patch.object(
main_dtv, 'get_standby', side_effect=requests.RequestException), \
patch('homeassistant.util.dt.utcnow', return_value=next_update):
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
state = hass.states.get(MAIN_ENTITY_ID)
assert state.state != STATE_UNAVAILABLE
# Make update fail 3rd time more then a minute after 1st failure
next_update = next_update + timedelta(minutes=1)
with patch.object(
main_dtv, 'get_standby', side_effect=requests.RequestException), \
patch('homeassistant.util.dt.utcnow', return_value=next_update):
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE