Use push updates in Apple TV (#6323)
* Use push updates in Apple TV * Fix review comments
This commit is contained in:
parent
a08539d88d
commit
bae6333c26
2 changed files with 58 additions and 28 deletions
|
@ -8,7 +8,6 @@ import asyncio
|
|||
import logging
|
||||
import hashlib
|
||||
|
||||
import aiohttp
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
|
@ -19,13 +18,13 @@ from homeassistant.components.media_player import (
|
|||
MEDIA_TYPE_VIDEO, MEDIA_TYPE_TVSHOW)
|
||||
from homeassistant.const import (
|
||||
STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_STANDBY, CONF_HOST,
|
||||
STATE_OFF, CONF_NAME)
|
||||
STATE_OFF, CONF_NAME, EVENT_HOMEASSISTANT_STOP)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
|
||||
REQUIREMENTS = ['pyatv==0.1.4']
|
||||
REQUIREMENTS = ['pyatv==0.2.1']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -73,7 +72,14 @@ def async_setup_platform(hass, config, async_add_entities,
|
|||
atv = pyatv.connect_to_apple_tv(details, hass.loop, session=session)
|
||||
entity = AppleTvDevice(atv, name, start_off)
|
||||
|
||||
yield from async_add_entities([entity], update_before_add=True)
|
||||
@callback
|
||||
def on_hass_stop(event):
|
||||
"""Stop push updates when hass stops."""
|
||||
atv.push_updater.stop()
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop)
|
||||
|
||||
yield from async_add_entities([entity])
|
||||
|
||||
|
||||
class AppleTvDevice(MediaPlayerDevice):
|
||||
|
@ -86,18 +92,34 @@ class AppleTvDevice(MediaPlayerDevice):
|
|||
self._is_off = is_off
|
||||
self._playing = None
|
||||
self._artwork_hash = None
|
||||
self._atv.push_updater.listener = self
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Called when entity is about to be added to HASS."""
|
||||
self._atv.push_updater.start()
|
||||
|
||||
@callback
|
||||
def _set_power_off(self, is_off):
|
||||
self._playing = None
|
||||
self._artwork_hash = None
|
||||
self._is_off = is_off
|
||||
if is_off:
|
||||
self._atv.push_updater.stop()
|
||||
else:
|
||||
self._atv.push_updater.start()
|
||||
self.hass.async_add_job(self.async_update_ha_state())
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
|
@ -120,29 +142,19 @@ class AppleTvDevice(MediaPlayerDevice):
|
|||
else:
|
||||
return STATE_STANDBY # Bad or unknown state?
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Retrieve latest state."""
|
||||
if self._is_off:
|
||||
return
|
||||
@callback
|
||||
def playstatus_update(self, updater, playing):
|
||||
"""Print what is currently playing when it changes."""
|
||||
if self.state == STATE_IDLE:
|
||||
self._artwork_hash = None
|
||||
elif 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()
|
||||
|
||||
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')
|
||||
self._playing = playing
|
||||
self.hass.async_add_job(self.async_update_ha_state())
|
||||
|
||||
def _has_playing_media_changed(self, new_playing):
|
||||
if self._playing is None:
|
||||
|
@ -151,6 +163,21 @@ class AppleTvDevice(MediaPlayerDevice):
|
|||
return new_playing.media_type != old_playing.media_type or \
|
||||
new_playing.title != old_playing.title
|
||||
|
||||
@callback
|
||||
def playstatus_error(self, updater, exception):
|
||||
"""Inform about an error and restart push updates."""
|
||||
_LOGGER.warning('A %s error occurred: %s',
|
||||
exception.__class__, exception)
|
||||
|
||||
# This will wait 10 seconds before restarting push updates. If the
|
||||
# connection continues to fail, it will flood the log (every 10
|
||||
# seconds) until it succeeds. A better approach should probably be
|
||||
# implemented here later.
|
||||
updater.start(initial_delay=10)
|
||||
self._playing = None
|
||||
self._artwork_hash = None
|
||||
self.hass.async_add_job(self.async_update_ha_state())
|
||||
|
||||
@property
|
||||
def media_content_type(self):
|
||||
"""Content type of current playing media."""
|
||||
|
@ -191,7 +218,8 @@ class AppleTvDevice(MediaPlayerDevice):
|
|||
@property
|
||||
def media_image_hash(self):
|
||||
"""Hash value for media image."""
|
||||
return self._artwork_hash
|
||||
if self.state != STATE_IDLE:
|
||||
return self._artwork_hash
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_get_media_image(self):
|
||||
|
@ -207,6 +235,8 @@ class AppleTvDevice(MediaPlayerDevice):
|
|||
title = self._playing.title
|
||||
return title if title else "No title"
|
||||
|
||||
return 'Not connected to Apple TV'
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag media player features that are supported."""
|
||||
|
|
|
@ -454,7 +454,7 @@ pyasn1-modules==0.0.8
|
|||
pyasn1==0.2.2
|
||||
|
||||
# homeassistant.components.media_player.apple_tv
|
||||
pyatv==0.1.4
|
||||
pyatv==0.2.1
|
||||
|
||||
# homeassistant.components.device_tracker.bbox
|
||||
# homeassistant.components.sensor.bbox
|
||||
|
|
Loading…
Add table
Reference in a new issue