Update Plex via websockets (#28158)

* Save client identifier from auth for future use

* Use websocket events to update Plex

* Handle websocket disconnections

* Use aiohttp, shut down socket cleanly

* Bad rebase fix

* Don't connect websocket during config_flow validation, fix tests

* Move websocket handling to external library

* Close websocket session on HA stop

* Use external library, revert unnecessary test change

* Async & lint fixes

* Clean up websocket stopper on entry unload

* Setup websocket in component, pass actual needed object to library
pull/28217/head
jjlawren 2019-10-25 11:37:50 -05:00 committed by Martin Hjelmare
parent 9153729b21
commit 43c7b57d1e
7 changed files with 52 additions and 13 deletions

View File

@ -514,6 +514,7 @@ omit =
homeassistant/components/plex/media_player.py
homeassistant/components/plex/sensor.py
homeassistant/components/plex/server.py
homeassistant/components/plex/websockets.py
homeassistant/components/plugwise/*
homeassistant/components/plum_lightpad/*
homeassistant/components/pocketcasts/sensor.py

View File

@ -1,9 +1,9 @@
"""Support to embed Plex."""
import asyncio
from datetime import timedelta
import logging
import plexapi.exceptions
from plexwebsocket import PlexWebsocket
import requests.exceptions
import voluptuous as vol
@ -16,9 +16,14 @@ from homeassistant.const import (
CONF_TOKEN,
CONF_URL,
CONF_VERIFY_SSL,
EVENT_HOMEASSISTANT_STOP,
)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from .const import (
CONF_USE_EPISODE_ART,
@ -33,8 +38,9 @@ from .const import (
PLATFORMS,
PLEX_MEDIA_PLAYER_OPTIONS,
PLEX_SERVER_CONFIG,
REFRESH_LISTENERS,
PLEX_UPDATE_PLATFORMS_SIGNAL,
SERVERS,
WEBSOCKETS,
)
from .server import PlexServer
@ -67,9 +73,7 @@ _LOGGER = logging.getLogger(__package__)
def setup(hass, config):
"""Set up the Plex component."""
hass.data.setdefault(
PLEX_DOMAIN, {SERVERS: {}, REFRESH_LISTENERS: {}, DISPATCHERS: {}}
)
hass.data.setdefault(PLEX_DOMAIN, {SERVERS: {}, DISPATCHERS: {}, WEBSOCKETS: {}})
plex_config = config.get(PLEX_DOMAIN, {})
if plex_config:
@ -136,7 +140,6 @@ async def async_setup_entry(hass, entry):
)
server_id = plex_server.machine_identifier
hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id] = []
for platform in PLATFORMS:
hass.async_create_task(
@ -145,9 +148,29 @@ async def async_setup_entry(hass, entry):
entry.add_update_listener(async_options_updated)
hass.data[PLEX_DOMAIN][REFRESH_LISTENERS][server_id] = async_track_time_interval(
hass, lambda now: plex_server.update_platforms(), timedelta(seconds=10)
unsub = async_dispatcher_connect(
hass,
PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
plex_server.update_platforms,
)
hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)
def update_plex():
async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id))
session = async_get_clientsession(hass)
websocket = PlexWebsocket(plex_server.plex_server, update_plex, session)
hass.loop.create_task(websocket.listen())
hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket
def close_websocket_session(_):
websocket.close()
unsub = hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, close_websocket_session
)
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)
return True
@ -156,8 +179,8 @@ async def async_unload_entry(hass, entry):
"""Unload a config entry."""
server_id = entry.data[CONF_SERVER_IDENTIFIER]
cancel = hass.data[PLEX_DOMAIN][REFRESH_LISTENERS].pop(server_id)
cancel()
websocket = hass.data[PLEX_DOMAIN][WEBSOCKETS].pop(server_id)
websocket.close()
dispatchers = hass.data[PLEX_DOMAIN][DISPATCHERS].pop(server_id)
for unsub in dispatchers:

View File

@ -10,8 +10,8 @@ DEFAULT_VERIFY_SSL = True
DISPATCHERS = "dispatchers"
PLATFORMS = ["media_player", "sensor"]
REFRESH_LISTENERS = "refresh_listeners"
SERVERS = "servers"
WEBSOCKETS = "websockets"
PLEX_CONFIG_FILE = "plex.conf"
PLEX_MEDIA_PLAYER_OPTIONS = "plex_mp_options"
@ -19,6 +19,7 @@ PLEX_SERVER_CONFIG = "server_config"
PLEX_NEW_MP_SIGNAL = "plex_new_mp_signal.{}"
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL = "plex_update_mp_signal.{}"
PLEX_UPDATE_PLATFORMS_SIGNAL = "plex_update_platforms_signal.{}"
PLEX_UPDATE_SENSOR_SIGNAL = "plex_update_sensor_signal.{}"
CONF_CLIENT_IDENTIFIER = "client_id"

View File

@ -5,7 +5,8 @@
"documentation": "https://www.home-assistant.io/integrations/plex",
"requirements": [
"plexapi==3.0.6",
"plexauth==0.0.5"
"plexauth==0.0.5",
"plexwebsocket==0.0.1"
],
"dependencies": [
"http"

View File

@ -103,6 +103,8 @@ class PlexServer:
def update_platforms(self):
"""Update the platform entities."""
_LOGGER.debug("Updating devices")
available_clients = {}
new_clients = set()
@ -164,6 +166,11 @@ class PlexServer:
sessions,
)
@property
def plex_server(self):
"""Return the plexapi PlexServer instance."""
return self._plex_server
@property
def friendly_name(self):
"""Return name of connected Plex server."""

View File

@ -973,6 +973,9 @@ plexapi==3.0.6
# homeassistant.components.plex
plexauth==0.0.5
# homeassistant.components.plex
plexwebsocket==0.0.1
# homeassistant.components.plum_lightpad
plumlightpad==0.0.11

View File

@ -346,6 +346,9 @@ plexapi==3.0.6
# homeassistant.components.plex
plexauth==0.0.5
# homeassistant.components.plex
plexwebsocket==0.0.1
# homeassistant.components.mhz19
# homeassistant.components.serial_pm
pmsensor==0.4