Plex discovery on demand (#35303)
* Allow Plex discovery on demand * Add new discovery source * Add tests
This commit is contained in:
parent
ee96ff2846
commit
c12f8bed43
5 changed files with 81 additions and 2 deletions
|
@ -4,6 +4,7 @@ import logging
|
||||||
|
|
||||||
from aiohttp import web_response
|
from aiohttp import web_response
|
||||||
import plexapi.exceptions
|
import plexapi.exceptions
|
||||||
|
from plexapi.gdm import GDM
|
||||||
from plexauth import PlexAuth
|
from plexauth import PlexAuth
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
@ -62,6 +63,18 @@ def configured_servers(hass):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_discover(hass):
|
||||||
|
"""Scan for available Plex servers."""
|
||||||
|
gdm = GDM()
|
||||||
|
await hass.async_add_executor_job(gdm.scan)
|
||||||
|
for server_data in gdm.entries:
|
||||||
|
await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_INTEGRATION_DISCOVERY},
|
||||||
|
data=server_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a Plex config flow."""
|
"""Handle a Plex config flow."""
|
||||||
|
|
||||||
|
@ -266,6 +279,19 @@ class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
_LOGGER.debug("Imported Plex configuration")
|
_LOGGER.debug("Imported Plex configuration")
|
||||||
return await self.async_step_server_validate(import_config)
|
return await self.async_step_server_validate(import_config)
|
||||||
|
|
||||||
|
async def async_step_integration_discovery(self, discovery_info):
|
||||||
|
"""Handle GDM discovery."""
|
||||||
|
machine_identifier = discovery_info["data"]["Resource-Identifier"]
|
||||||
|
await self.async_set_unique_id(machine_identifier)
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
host = f"{discovery_info['from'][0]}:{discovery_info['data']['Port']}"
|
||||||
|
name = discovery_info["data"]["Name"]
|
||||||
|
self.context["title_placeholders"] = { # pylint: disable=no-member
|
||||||
|
"host": host,
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
return await self.async_step_user()
|
||||||
|
|
||||||
async def async_step_plex_website_auth(self):
|
async def async_step_plex_website_auth(self):
|
||||||
"""Begin external auth flow on Plex website."""
|
"""Begin external auth flow on Plex website."""
|
||||||
self.hass.http.register_view(PlexAuthorizationCallbackView)
|
self.hass.http.register_view(PlexAuthorizationCallbackView)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
|
"flow_title": "{name} ({host})",
|
||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Plex Media Server",
|
"title": "Plex Media Server",
|
||||||
|
|
|
@ -22,6 +22,7 @@ _UNDEF: dict = {}
|
||||||
|
|
||||||
SOURCE_DISCOVERY = "discovery"
|
SOURCE_DISCOVERY = "discovery"
|
||||||
SOURCE_IMPORT = "import"
|
SOURCE_IMPORT = "import"
|
||||||
|
SOURCE_INTEGRATION_DISCOVERY = "integration_discovery"
|
||||||
SOURCE_SSDP = "ssdp"
|
SOURCE_SSDP = "ssdp"
|
||||||
SOURCE_USER = "user"
|
SOURCE_USER = "user"
|
||||||
SOURCE_ZEROCONF = "zeroconf"
|
SOURCE_ZEROCONF = "zeroconf"
|
||||||
|
|
|
@ -8,6 +8,32 @@ from homeassistant.const import CONF_URL
|
||||||
|
|
||||||
from .const import DEFAULT_DATA, MOCK_SERVERS, MOCK_USERS
|
from .const import DEFAULT_DATA, MOCK_SERVERS, MOCK_USERS
|
||||||
|
|
||||||
|
GDM_PAYLOAD = [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"Content-Type": "plex/media-server",
|
||||||
|
"Name": "plextest",
|
||||||
|
"Port": "32400",
|
||||||
|
"Resource-Identifier": "1234567890123456789012345678901234567890",
|
||||||
|
"Updated-At": "157762684800",
|
||||||
|
"Version": "1.0",
|
||||||
|
},
|
||||||
|
"from": ("1.2.3.4", 32414),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class MockGDM:
|
||||||
|
"""Mock a GDM instance."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the object."""
|
||||||
|
self.entries = GDM_PAYLOAD
|
||||||
|
|
||||||
|
def scan(self):
|
||||||
|
"""Mock the scan call."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MockResource:
|
class MockResource:
|
||||||
"""Mock a PlexAccount resource."""
|
"""Mock a PlexAccount resource."""
|
||||||
|
|
|
@ -22,7 +22,10 @@ from homeassistant.components.plex.const import (
|
||||||
SERVERS,
|
SERVERS,
|
||||||
)
|
)
|
||||||
from homeassistant.config import async_process_ha_core_config
|
from homeassistant.config import async_process_ha_core_config
|
||||||
from homeassistant.config_entries import ENTRY_STATE_LOADED
|
from homeassistant.config_entries import (
|
||||||
|
ENTRY_STATE_LOADED,
|
||||||
|
SOURCE_INTEGRATION_DISCOVERY,
|
||||||
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
|
@ -34,7 +37,7 @@ from homeassistant.const import (
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from .const import DEFAULT_DATA, DEFAULT_OPTIONS, MOCK_SERVERS, MOCK_TOKEN
|
from .const import DEFAULT_DATA, DEFAULT_OPTIONS, MOCK_SERVERS, MOCK_TOKEN
|
||||||
from .mock_classes import MockPlexAccount, MockPlexServer
|
from .mock_classes import MockGDM, MockPlexAccount, MockPlexServer
|
||||||
|
|
||||||
from tests.async_mock import patch
|
from tests.async_mock import patch
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
@ -746,3 +749,25 @@ async def test_setup_with_limited_credentials(hass):
|
||||||
|
|
||||||
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
|
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
|
||||||
assert entry.state == ENTRY_STATE_LOADED
|
assert entry.state == ENTRY_STATE_LOADED
|
||||||
|
|
||||||
|
|
||||||
|
async def test_integration_discovery(hass):
|
||||||
|
"""Test integration self-discovery."""
|
||||||
|
mock_gdm = MockGDM()
|
||||||
|
|
||||||
|
with patch("homeassistant.components.plex.config_flow.GDM", return_value=mock_gdm):
|
||||||
|
await config_flow.async_discover(hass)
|
||||||
|
|
||||||
|
flows = hass.config_entries.flow.async_progress()
|
||||||
|
|
||||||
|
assert len(flows) == 1
|
||||||
|
|
||||||
|
flow = flows[0]
|
||||||
|
|
||||||
|
assert flow["handler"] == DOMAIN
|
||||||
|
assert flow["context"]["source"] == SOURCE_INTEGRATION_DISCOVERY
|
||||||
|
assert (
|
||||||
|
flow["context"]["unique_id"]
|
||||||
|
== mock_gdm.entries[0]["data"]["Resource-Identifier"]
|
||||||
|
)
|
||||||
|
assert flow["step_id"] == "user"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue