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
This commit is contained in:
parent
0a5cde7ac3
commit
05ee15c28c
7 changed files with 52 additions and 13 deletions
|
@ -514,6 +514,7 @@ omit =
|
||||||
homeassistant/components/plex/media_player.py
|
homeassistant/components/plex/media_player.py
|
||||||
homeassistant/components/plex/sensor.py
|
homeassistant/components/plex/sensor.py
|
||||||
homeassistant/components/plex/server.py
|
homeassistant/components/plex/server.py
|
||||||
|
homeassistant/components/plex/websockets.py
|
||||||
homeassistant/components/plugwise/*
|
homeassistant/components/plugwise/*
|
||||||
homeassistant/components/plum_lightpad/*
|
homeassistant/components/plum_lightpad/*
|
||||||
homeassistant/components/pocketcasts/sensor.py
|
homeassistant/components/pocketcasts/sensor.py
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"""Support to embed Plex."""
|
"""Support to embed Plex."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import plexapi.exceptions
|
import plexapi.exceptions
|
||||||
|
from plexwebsocket import PlexWebsocket
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
@ -16,9 +16,14 @@ from homeassistant.const import (
|
||||||
CONF_TOKEN,
|
CONF_TOKEN,
|
||||||
CONF_URL,
|
CONF_URL,
|
||||||
CONF_VERIFY_SSL,
|
CONF_VERIFY_SSL,
|
||||||
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers import config_validation as cv
|
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 (
|
from .const import (
|
||||||
CONF_USE_EPISODE_ART,
|
CONF_USE_EPISODE_ART,
|
||||||
|
@ -33,8 +38,9 @@ from .const import (
|
||||||
PLATFORMS,
|
PLATFORMS,
|
||||||
PLEX_MEDIA_PLAYER_OPTIONS,
|
PLEX_MEDIA_PLAYER_OPTIONS,
|
||||||
PLEX_SERVER_CONFIG,
|
PLEX_SERVER_CONFIG,
|
||||||
REFRESH_LISTENERS,
|
PLEX_UPDATE_PLATFORMS_SIGNAL,
|
||||||
SERVERS,
|
SERVERS,
|
||||||
|
WEBSOCKETS,
|
||||||
)
|
)
|
||||||
from .server import PlexServer
|
from .server import PlexServer
|
||||||
|
|
||||||
|
@ -67,9 +73,7 @@ _LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Set up the Plex component."""
|
"""Set up the Plex component."""
|
||||||
hass.data.setdefault(
|
hass.data.setdefault(PLEX_DOMAIN, {SERVERS: {}, DISPATCHERS: {}, WEBSOCKETS: {}})
|
||||||
PLEX_DOMAIN, {SERVERS: {}, REFRESH_LISTENERS: {}, DISPATCHERS: {}}
|
|
||||||
)
|
|
||||||
|
|
||||||
plex_config = config.get(PLEX_DOMAIN, {})
|
plex_config = config.get(PLEX_DOMAIN, {})
|
||||||
if plex_config:
|
if plex_config:
|
||||||
|
@ -136,7 +140,6 @@ async def async_setup_entry(hass, entry):
|
||||||
)
|
)
|
||||||
server_id = plex_server.machine_identifier
|
server_id = plex_server.machine_identifier
|
||||||
hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
|
hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
|
||||||
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id] = []
|
|
||||||
|
|
||||||
for platform in PLATFORMS:
|
for platform in PLATFORMS:
|
||||||
hass.async_create_task(
|
hass.async_create_task(
|
||||||
|
@ -145,9 +148,29 @@ async def async_setup_entry(hass, entry):
|
||||||
|
|
||||||
entry.add_update_listener(async_options_updated)
|
entry.add_update_listener(async_options_updated)
|
||||||
|
|
||||||
hass.data[PLEX_DOMAIN][REFRESH_LISTENERS][server_id] = async_track_time_interval(
|
unsub = async_dispatcher_connect(
|
||||||
hass, lambda now: plex_server.update_platforms(), timedelta(seconds=10)
|
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
|
return True
|
||||||
|
|
||||||
|
@ -156,8 +179,8 @@ async def async_unload_entry(hass, entry):
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
server_id = entry.data[CONF_SERVER_IDENTIFIER]
|
server_id = entry.data[CONF_SERVER_IDENTIFIER]
|
||||||
|
|
||||||
cancel = hass.data[PLEX_DOMAIN][REFRESH_LISTENERS].pop(server_id)
|
websocket = hass.data[PLEX_DOMAIN][WEBSOCKETS].pop(server_id)
|
||||||
cancel()
|
websocket.close()
|
||||||
|
|
||||||
dispatchers = hass.data[PLEX_DOMAIN][DISPATCHERS].pop(server_id)
|
dispatchers = hass.data[PLEX_DOMAIN][DISPATCHERS].pop(server_id)
|
||||||
for unsub in dispatchers:
|
for unsub in dispatchers:
|
||||||
|
|
|
@ -10,8 +10,8 @@ DEFAULT_VERIFY_SSL = True
|
||||||
|
|
||||||
DISPATCHERS = "dispatchers"
|
DISPATCHERS = "dispatchers"
|
||||||
PLATFORMS = ["media_player", "sensor"]
|
PLATFORMS = ["media_player", "sensor"]
|
||||||
REFRESH_LISTENERS = "refresh_listeners"
|
|
||||||
SERVERS = "servers"
|
SERVERS = "servers"
|
||||||
|
WEBSOCKETS = "websockets"
|
||||||
|
|
||||||
PLEX_CONFIG_FILE = "plex.conf"
|
PLEX_CONFIG_FILE = "plex.conf"
|
||||||
PLEX_MEDIA_PLAYER_OPTIONS = "plex_mp_options"
|
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_NEW_MP_SIGNAL = "plex_new_mp_signal.{}"
|
||||||
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL = "plex_update_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.{}"
|
PLEX_UPDATE_SENSOR_SIGNAL = "plex_update_sensor_signal.{}"
|
||||||
|
|
||||||
CONF_CLIENT_IDENTIFIER = "client_id"
|
CONF_CLIENT_IDENTIFIER = "client_id"
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/plex",
|
"documentation": "https://www.home-assistant.io/integrations/plex",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"plexapi==3.0.6",
|
"plexapi==3.0.6",
|
||||||
"plexauth==0.0.5"
|
"plexauth==0.0.5",
|
||||||
|
"plexwebsocket==0.0.1"
|
||||||
],
|
],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"http"
|
"http"
|
||||||
|
|
|
@ -103,6 +103,8 @@ class PlexServer:
|
||||||
|
|
||||||
def update_platforms(self):
|
def update_platforms(self):
|
||||||
"""Update the platform entities."""
|
"""Update the platform entities."""
|
||||||
|
_LOGGER.debug("Updating devices")
|
||||||
|
|
||||||
available_clients = {}
|
available_clients = {}
|
||||||
new_clients = set()
|
new_clients = set()
|
||||||
|
|
||||||
|
@ -164,6 +166,11 @@ class PlexServer:
|
||||||
sessions,
|
sessions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def plex_server(self):
|
||||||
|
"""Return the plexapi PlexServer instance."""
|
||||||
|
return self._plex_server
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def friendly_name(self):
|
def friendly_name(self):
|
||||||
"""Return name of connected Plex server."""
|
"""Return name of connected Plex server."""
|
||||||
|
|
|
@ -973,6 +973,9 @@ plexapi==3.0.6
|
||||||
# homeassistant.components.plex
|
# homeassistant.components.plex
|
||||||
plexauth==0.0.5
|
plexauth==0.0.5
|
||||||
|
|
||||||
|
# homeassistant.components.plex
|
||||||
|
plexwebsocket==0.0.1
|
||||||
|
|
||||||
# homeassistant.components.plum_lightpad
|
# homeassistant.components.plum_lightpad
|
||||||
plumlightpad==0.0.11
|
plumlightpad==0.0.11
|
||||||
|
|
||||||
|
|
|
@ -345,6 +345,9 @@ plexapi==3.0.6
|
||||||
# homeassistant.components.plex
|
# homeassistant.components.plex
|
||||||
plexauth==0.0.5
|
plexauth==0.0.5
|
||||||
|
|
||||||
|
# homeassistant.components.plex
|
||||||
|
plexwebsocket==0.0.1
|
||||||
|
|
||||||
# homeassistant.components.mhz19
|
# homeassistant.components.mhz19
|
||||||
# homeassistant.components.serial_pm
|
# homeassistant.components.serial_pm
|
||||||
pmsensor==0.4
|
pmsensor==0.4
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue