From 3d4ff747612b348c74ee9101dd19bafe8dedcc15 Mon Sep 17 00:00:00 2001 From: ehendrix23 Date: Mon, 5 Nov 2018 08:19:03 -0700 Subject: [PATCH] Add available property to DirecTV (#18168) * Enhancements for DirecTV media player Following enhancements have been made: 1. Added debug logging 2. Added ability to change channel using select_source service of the remote platform. 3. State will now show paused if a recorded program is paused, for live TV playing will always be returned. 4. Added the following attributes: a. media_position: current position of the media (in seconds) b. media_position_updated_at: timestamp when media_position was updated. c. source: current source (channel). d. media_isbeingrecorded: if current media is being recorded or not. e. media_rating: TV/Movie rating of the media f. media_recorded: if current media is recorded or live TV g. media_starttime: Timestamp media was aired Reordered properties to follow same order as how they are in __init__.py of remote platform. * Fixed error and cleaned up few items Fixed an issue when determining if a program is recorded or not. Cleaned up some coding. * Fix issue in checking if DTV device is already configured If a DTV device was configured before, then discovery would add this device again seperately if the name specified in the configuration is different from the name on the DTV. This issue is fixed now. Part of the fix also ensure to allow multiple "primary" devices on the network to be discovered. Further also added debug logging to the setup_platform. * Further improvements Some additional improvements related to handling the DATA_DIRECTV in hass.data. * Fixed flake8 issue Fixed flake8 issue * Added available property Added available property * Updated to use get_locations() Replaced doing the request for getLocations with the get_locations() API from DirectPy instead. * Fix for checking if device is available Fix for checking if device is available and small update to debug log message. * Fixed lint issue Fixed lint issue with unused variable by adding ingore for it as this is for a enumerate * Updated try/except and removed available Updated tr/except having the except by the statement we're doing except on. Removed available, will be a different PR. * Add available property Add the available property to the entiry. --- .../components/media_player/directv.py | 116 +++++++++++++----- 1 file changed, 82 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/media_player/directv.py b/homeassistant/components/media_player/directv.py index 4767428894b..009a720276e 100644 --- a/homeassistant/components/media_player/directv.py +++ b/homeassistant/components/media_player/directv.py @@ -48,12 +48,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DirecTV platform.""" - known_devices = hass.data.get(DATA_DIRECTV) - if not known_devices: - known_devices = [] + known_devices = hass.data.get(DATA_DIRECTV, []) hosts = [] if CONF_HOST in config: + _LOGGER.debug("Adding configured device %s with client address %s ", + config.get(CONF_NAME), config.get(CONF_DEVICE)) hosts.append([ config.get(CONF_NAME), config.get(CONF_HOST), config.get(CONF_PORT), config.get(CONF_DEVICE) @@ -64,29 +64,57 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name = 'DirecTV_{}'.format(discovery_info.get('serial', '')) # Attempt to discover additional RVU units - try: - resp = requests.get( - 'http://%s:%d/info/getLocations' % (host, DEFAULT_PORT)).json() - if "locations" in resp: - for loc in resp["locations"]: - if("locationName" in loc and "clientAddr" in loc - and loc["clientAddr"] not in known_devices): - hosts.append([str.title(loc["locationName"]), host, - DEFAULT_PORT, loc["clientAddr"]]) + _LOGGER.debug("Doing discovery of DirecTV devices on %s", host) - except requests.exceptions.RequestException: + from DirectPy import DIRECTV + dtv = DIRECTV(host, DEFAULT_PORT) + try: + resp = dtv.get_locations() + except requests.exceptions.RequestException as ex: # Bail out and just go forward with uPnP data - if DEFAULT_DEVICE not in known_devices: - hosts.append([name, host, DEFAULT_PORT, DEFAULT_DEVICE]) + # Make sure that this device is not already configured + # Comparing based on host (IP) and clientAddr. + _LOGGER.debug("Request exception %s trying to get locations", ex) + resp = { + 'locations': [{ + 'locationName': name, + 'clientAddr': DEFAULT_DEVICE + }] + } + + _LOGGER.debug("Known devices: %s", known_devices) + for loc in resp.get("locations") or []: + if "locationName" not in loc or "clientAddr" not in loc: + continue + + # Make sure that this device is not already configured + # Comparing based on host (IP) and clientAddr. + device_unknown = True + for device in known_devices: + if host in device and loc["clientAddr"] in device: + device_unknown = False + _LOGGER.debug("Discovered device %s on host %s with " + "client address %s is already " + "configured", + str.title(loc["locationName"]), + host, loc["clientAddr"]) + break + + if device_unknown: + _LOGGER.debug("Adding discovered device %s with" + " client address %s", + str.title(loc["locationName"]), + loc["clientAddr"]) + hosts.append([str.title(loc["locationName"]), host, + DEFAULT_PORT, loc["clientAddr"]]) dtvs = [] for host in hosts: dtvs.append(DirecTvDevice(*host)) - known_devices.append(host[-1]) + hass.data.setdefault(DATA_DIRECTV, []).append(host) add_entities(dtvs) - hass.data[DATA_DIRECTV] = known_devices class DirecTvDevice(MediaPlayerDevice): @@ -104,28 +132,43 @@ class DirecTvDevice(MediaPlayerDevice): self._last_position = None self._is_recorded = None self._assumed_state = None + self._available = False _LOGGER.debug("Created DirecTV device for %s", self._name) def update(self): """Retrieve latest state.""" - _LOGGER.debug("Updating state for %s", self._name) - self._is_standby = self.dtv.get_standby() - if self._is_standby: - self._current = None - self._is_recorded = None - self._paused = None - self._assumed_state = False - self._last_position = None - self._last_update = None - else: - self._current = self.dtv.get_tuned() - self._is_recorded = self._current.get('uniqueId') is not None - self._paused = self._last_position == self._current['offset'] - self._assumed_state = self._is_recorded - self._last_position = self._current['offset'] - self._last_update = dt_util.now() if not self._paused or\ - self._last_update is None else self._last_update + _LOGGER.debug("Updating status for %s", self._name) + try: + self._available = True + self._is_standby = self.dtv.get_standby() + if self._is_standby: + self._current = None + self._is_recorded = None + self._paused = None + self._assumed_state = False + self._last_position = None + self._last_update = None + else: + self._current = self.dtv.get_tuned() + if self._current['status']['code'] == 200: + self._is_recorded = self._current.get('uniqueId')\ + is not None + self._paused = self._last_position == \ + self._current['offset'] + self._assumed_state = self._is_recorded + self._last_position = self._current['offset'] + self._last_update = dt_util.now() if not self._paused or\ + self._last_update is None else self._last_update + else: + self._available = False + except requests.RequestException as ex: + _LOGGER.error("Request error trying to update current status for" + " %s. %s", self._name, ex) + self._available = False + except Exception: + self._available = False + raise @property def device_state_attributes(self): @@ -160,6 +203,11 @@ class DirecTvDevice(MediaPlayerDevice): return STATE_PLAYING + @property + def available(self): + """Return if able to retrieve information from DVR or not.""" + return self._available + @property def assumed_state(self): """Return if we assume the state or not."""