-
-
Notifications
You must be signed in to change notification settings - Fork 37.8k
Add fake support for turn on/off for Apple TV #5962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,11 +13,12 @@ | |
|
|
||
| from homeassistant.components.media_player import ( | ||
| SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, | ||
| SUPPORT_STOP, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, MediaPlayerDevice, | ||
| PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC, MEDIA_TYPE_VIDEO, MEDIA_TYPE_TVSHOW) | ||
| SUPPORT_STOP, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_TURN_ON, | ||
| SUPPORT_TURN_OFF, MediaPlayerDevice, PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC, | ||
| MEDIA_TYPE_VIDEO, MEDIA_TYPE_TVSHOW) | ||
| from homeassistant.const import ( | ||
| STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_STANDBY, CONF_HOST, | ||
| CONF_NAME) | ||
| STATE_OFF, CONF_NAME) | ||
| from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||
| import homeassistant.helpers.config_validation as cv | ||
| import homeassistant.util.dt as dt_util | ||
|
|
@@ -28,6 +29,7 @@ | |
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| CONF_LOGIN_ID = 'login_id' | ||
| CONF_START_OFF = 'start_off' | ||
|
|
||
| DEFAULT_NAME = 'Apple TV' | ||
|
|
||
|
|
@@ -37,6 +39,7 @@ | |
| vol.Required(CONF_HOST): cv.string, | ||
| vol.Required(CONF_LOGIN_ID): cv.string, | ||
| vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, | ||
| vol.Optional(CONF_START_OFF, default=False): cv.boolean | ||
| }) | ||
|
|
||
|
|
||
|
|
@@ -50,10 +53,12 @@ def async_setup_platform(hass, config, async_add_entities, | |
| name = discovery_info['name'] | ||
| host = discovery_info['host'] | ||
| login_id = discovery_info['hsgid'] | ||
| start_off = False | ||
| else: | ||
| name = config.get(CONF_NAME) | ||
| host = config.get(CONF_HOST) | ||
| login_id = config.get(CONF_LOGIN_ID) | ||
| start_off = config.get(CONF_START_OFF) | ||
|
|
||
| if DATA_APPLE_TV not in hass.data: | ||
| hass.data[DATA_APPLE_TV] = [] | ||
|
|
@@ -65,18 +70,23 @@ def async_setup_platform(hass, config, async_add_entities, | |
| details = pyatv.AppleTVDevice(name, host, login_id) | ||
| session = async_get_clientsession(hass) | ||
| atv = pyatv.connect_to_apple_tv(details, hass.loop, session=session) | ||
| entity = AppleTvDevice(atv, name) | ||
| entity = AppleTvDevice(atv, name, start_off) | ||
|
|
||
| yield from async_add_entities([entity], update_before_add=True) | ||
|
|
||
|
|
||
| class AppleTvDevice(MediaPlayerDevice): | ||
| """Representation of an Apple TV device.""" | ||
|
|
||
| def __init__(self, atv, name): | ||
| def __init__(self, atv, name, is_off): | ||
| """Initialize the Apple TV device.""" | ||
| self._name = name | ||
| self._atv = atv | ||
| self._name = name | ||
| self._is_off = is_off | ||
| self._playing = None | ||
| self._artwork_hash = None | ||
|
|
||
| def _reset(self): | ||
| self._playing = None | ||
| self._artwork_hash = None | ||
|
|
||
|
|
@@ -88,6 +98,9 @@ def name(self): | |
| @property | ||
| def state(self): | ||
| """Return the state of the device.""" | ||
| if self._is_off: | ||
| return STATE_OFF | ||
|
|
||
| if self._playing is not None: | ||
| from pyatv import const | ||
| state = self._playing.play_state | ||
|
|
@@ -107,23 +120,24 @@ def state(self): | |
| @asyncio.coroutine | ||
| def async_update(self): | ||
| """Retrieve latest state.""" | ||
| from pyatv import exceptions | ||
| try: | ||
| playing = yield from self._atv.metadata.playing() | ||
|
|
||
| if self._has_playing_media_changed(playing): | ||
| base = str(playing.title) + str(playing.artist) + \ | ||
| str(playing.album) + str(playing.total_time) | ||
| self._artwork_hash = hashlib.md5( | ||
| base.encode('utf-8')).hexdigest() | ||
|
|
||
| self._playing = playing | ||
| except exceptions.AuthenticationError as ex: | ||
| _LOGGER.warning('%s (bad login id?)', str(ex)) | ||
| except aiohttp.errors.ClientOSError as ex: | ||
| _LOGGER.error('failed to connect to Apple TV (%s)', str(ex)) | ||
| except asyncio.TimeoutError: | ||
| _LOGGER.warning('timed out while connecting to Apple TV') | ||
| if not self._is_off: | ||
| from pyatv import exceptions | ||
| try: | ||
| playing = yield from self._atv.metadata.playing() | ||
|
|
||
| if self._has_playing_media_changed(playing): | ||
| base = str(playing.title) + str(playing.artist) + \ | ||
| str(playing.album) + str(playing.total_time) | ||
| self._artwork_hash = hashlib.md5( | ||
| base.encode('utf-8')).hexdigest() | ||
|
|
||
| self._playing = playing | ||
| except exceptions.AuthenticationError as ex: | ||
| _LOGGER.warning('%s (bad login id?)', str(ex)) | ||
| except aiohttp.errors.ClientOSError as ex: | ||
| _LOGGER.error('failed to connect to Apple TV (%s)', str(ex)) | ||
| except asyncio.TimeoutError: | ||
| _LOGGER.warning('timed out while connecting to Apple TV') | ||
|
|
||
| def _has_playing_media_changed(self, new_playing): | ||
| if self._playing is None: | ||
|
|
@@ -132,6 +146,18 @@ def _has_playing_media_changed(self, new_playing): | |
| return new_playing.media_type != old_playing.media_type or \ | ||
| new_playing.title != old_playing.title | ||
|
|
||
| def turn_on(self): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this only sets simple variables, please turn this into it's async variant |
||
| """Turn the media player on.""" | ||
| self._is_off = False | ||
| self._reset() | ||
| self.schedule_update_ha_state() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need to call this. Your device does not overwrite |
||
|
|
||
| def turn_off(self): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same |
||
| """Turn the media player off.""" | ||
| self._is_off = True | ||
| self._reset() | ||
| self.schedule_update_ha_state() | ||
|
|
||
| @property | ||
| def media_content_type(self): | ||
| """Content type of current playing media.""" | ||
|
|
@@ -183,20 +209,24 @@ def async_get_media_image(self): | |
| def media_title(self): | ||
| """Title of current playing media.""" | ||
| if self._playing is not None: | ||
| if self.state == STATE_IDLE: | ||
| return 'Nothing playing' | ||
| title = self._playing.title | ||
| return title if title else "No title" | ||
|
|
||
| @property | ||
| def supported_features(self): | ||
| """Flag media player features that are supported.""" | ||
| features = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | ||
| if self._playing is not None: | ||
| if self.state != STATE_IDLE: | ||
| return SUPPORT_PAUSE | SUPPORT_PLAY | \ | ||
| features |= SUPPORT_PAUSE | SUPPORT_PLAY | \ | ||
| SUPPORT_SEEK | SUPPORT_STOP | \ | ||
| SUPPORT_NEXT_TRACK | SUPPORT_PREVIOUS_TRACK | \ | ||
| SUPPORT_PLAY_MEDIA | ||
| else: | ||
| return SUPPORT_PLAY_MEDIA | ||
| features |= SUPPORT_PLAY_MEDIA | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can move |
||
| return features | ||
|
|
||
| def async_media_play_pause(self): | ||
| """Pause media on media player. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a guard clause:
It will save you from indentation hell 👍