Pyroon discovery (#44811)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
5ee4479151
commit
adab9adbce
6 changed files with 254 additions and 150 deletions
|
@ -2,7 +2,7 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
from roonapi import RoonApi
|
||||
from roonapi import RoonApi, RoonDiscovery
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, core, exceptions
|
||||
|
@ -10,6 +10,7 @@ from homeassistant.const import CONF_API_KEY, CONF_HOST
|
|||
|
||||
from .const import ( # pylint: disable=unused-import
|
||||
AUTHENTICATE_TIMEOUT,
|
||||
CONF_ROON_ID,
|
||||
DEFAULT_NAME,
|
||||
DOMAIN,
|
||||
ROON_APPINFO,
|
||||
|
@ -25,36 +26,79 @@ TIMEOUT = 120
|
|||
class RoonHub:
|
||||
"""Interact with roon during config flow."""
|
||||
|
||||
def __init__(self, host):
|
||||
"""Initialize."""
|
||||
self._host = host
|
||||
def __init__(self, hass):
|
||||
"""Initialise the RoonHub."""
|
||||
self._hass = hass
|
||||
|
||||
async def discover(self):
|
||||
"""Try and discover roon servers."""
|
||||
|
||||
def get_discovered_servers(discovery):
|
||||
servers = discovery.all()
|
||||
discovery.stop()
|
||||
return servers
|
||||
|
||||
discovery = RoonDiscovery(None)
|
||||
servers = await self._hass.async_add_executor_job(
|
||||
get_discovered_servers, discovery
|
||||
)
|
||||
_LOGGER.debug("Servers = %s", servers)
|
||||
return servers
|
||||
|
||||
async def authenticate(self, host, servers):
|
||||
"""Authenticate with one or more roon servers."""
|
||||
|
||||
def stop_apis(apis):
|
||||
for api in apis:
|
||||
api.stop()
|
||||
|
||||
async def authenticate(self, hass) -> bool:
|
||||
"""Test if we can authenticate with the host."""
|
||||
token = None
|
||||
core_id = None
|
||||
secs = 0
|
||||
roonapi = RoonApi(ROON_APPINFO, None, self._host, blocking_init=False)
|
||||
while secs < TIMEOUT:
|
||||
token = roonapi.token
|
||||
if host is None:
|
||||
apis = [
|
||||
RoonApi(ROON_APPINFO, None, server[0], server[1], blocking_init=False)
|
||||
for server in servers
|
||||
]
|
||||
else:
|
||||
apis = [RoonApi(ROON_APPINFO, None, host, blocking_init=False)]
|
||||
|
||||
while secs <= TIMEOUT:
|
||||
# Roon can discover multiple devices - not all of which are proper servers, so try and authenticate with them all.
|
||||
# The user will only enable one - so look for a valid token
|
||||
auth_api = [api for api in apis if api.token is not None]
|
||||
|
||||
secs += AUTHENTICATE_TIMEOUT
|
||||
if token:
|
||||
if auth_api:
|
||||
core_id = auth_api[0].core_id
|
||||
token = auth_api[0].token
|
||||
break
|
||||
|
||||
await asyncio.sleep(AUTHENTICATE_TIMEOUT)
|
||||
|
||||
token = roonapi.token
|
||||
roonapi.stop()
|
||||
return token
|
||||
await self._hass.async_add_executor_job(stop_apis, apis)
|
||||
|
||||
return (token, core_id)
|
||||
|
||||
|
||||
async def authenticate(hass: core.HomeAssistant, host):
|
||||
async def discover(hass):
|
||||
"""Connect and authenticate home assistant."""
|
||||
|
||||
hub = RoonHub(host)
|
||||
token = await hub.authenticate(hass)
|
||||
hub = RoonHub(hass)
|
||||
servers = await hub.discover()
|
||||
|
||||
return servers
|
||||
|
||||
|
||||
async def authenticate(hass: core.HomeAssistant, host, servers):
|
||||
"""Connect and authenticate home assistant."""
|
||||
|
||||
hub = RoonHub(hass)
|
||||
(token, core_id) = await hub.authenticate(host, servers)
|
||||
if token is None:
|
||||
raise InvalidAuth
|
||||
|
||||
return {CONF_HOST: host, CONF_API_KEY: token}
|
||||
return {CONF_HOST: host, CONF_ROON_ID: core_id, CONF_API_KEY: token}
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
@ -66,20 +110,20 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
def __init__(self):
|
||||
"""Initialize the Roon flow."""
|
||||
self._host = None
|
||||
self._servers = []
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle getting host details from the user."""
|
||||
|
||||
errors = {}
|
||||
self._servers = await discover(self.hass)
|
||||
|
||||
# We discovered one or more roon - so skip to authentication
|
||||
if self._servers:
|
||||
return await self.async_step_link()
|
||||
|
||||
if user_input is not None:
|
||||
self._host = user_input["host"]
|
||||
existing = {
|
||||
entry.data[CONF_HOST] for entry in self._async_current_entries()
|
||||
}
|
||||
if self._host in existing:
|
||||
errors["base"] = "duplicate_entry"
|
||||
return self.async_show_form(step_id="user", errors=errors)
|
||||
|
||||
return await self.async_step_link()
|
||||
|
||||
return self.async_show_form(
|
||||
|
@ -92,7 +136,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
errors = {}
|
||||
if user_input is not None:
|
||||
try:
|
||||
info = await authenticate(self.hass, self._host)
|
||||
info = await authenticate(self.hass, self._host, self._servers)
|
||||
except InvalidAuth:
|
||||
errors["base"] = "invalid_auth"
|
||||
except Exception: # pylint: disable=broad-except
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue