Migrate ssdp to config_flow for frontier_silicon (#89496)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
47a2598b66
commit
e3cad8baac
7 changed files with 221 additions and 45 deletions
|
@ -3,15 +3,24 @@ from __future__ import annotations
|
|||
|
||||
import logging
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from afsapi import AFSAPI, ConnectionError as FSConnectionError, InvalidPinException
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import ssdp
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import CONF_PIN, CONF_WEBFSAPI_URL, DEFAULT_PIN, DEFAULT_PORT, DOMAIN
|
||||
from .const import (
|
||||
CONF_PIN,
|
||||
CONF_WEBFSAPI_URL,
|
||||
DEFAULT_PIN,
|
||||
DEFAULT_PORT,
|
||||
DOMAIN,
|
||||
SSDP_ATTR_SPEAKER_NAME,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -32,11 +41,17 @@ STEP_DEVICE_CONFIG_DATA_SCHEMA = vol.Schema(
|
|||
)
|
||||
|
||||
|
||||
def hostname_from_url(url: str) -> str:
|
||||
"""Return the hostname from a url."""
|
||||
return str(urlparse(url).hostname)
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for Frontier Silicon Media Player."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
_name: str
|
||||
_webfsapi_url: str
|
||||
|
||||
async def async_step_import(self, import_info: dict[str, Any]) -> FlowResult:
|
||||
|
@ -101,6 +116,46 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
step_id="user", data_schema=data_schema, errors=errors
|
||||
)
|
||||
|
||||
async def async_step_ssdp(self, discovery_info: ssdp.SsdpServiceInfo) -> FlowResult:
|
||||
"""Process entity discovered via SSDP."""
|
||||
|
||||
device_url = discovery_info.ssdp_location
|
||||
if device_url is None:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
|
||||
device_hostname = hostname_from_url(device_url)
|
||||
for entry in self._async_current_entries(include_ignore=False):
|
||||
if device_hostname == hostname_from_url(entry.data[CONF_WEBFSAPI_URL]):
|
||||
return self.async_abort(reason="already_configured")
|
||||
|
||||
speaker_name = discovery_info.ssdp_headers.get(SSDP_ATTR_SPEAKER_NAME)
|
||||
self.context["title_placeholders"] = {"name": speaker_name}
|
||||
|
||||
try:
|
||||
self._webfsapi_url = await AFSAPI.get_webfsapi_endpoint(device_url)
|
||||
except FSConnectionError:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
except Exception as exception: # pylint: disable=broad-except
|
||||
_LOGGER.debug(exception)
|
||||
return self.async_abort(reason="unknown")
|
||||
|
||||
try:
|
||||
# try to login with default pin
|
||||
afsapi = AFSAPI(self._webfsapi_url, DEFAULT_PIN)
|
||||
|
||||
unique_id = await afsapi.get_radio_id()
|
||||
except InvalidPinException:
|
||||
return self.async_abort(reason="invalid_auth")
|
||||
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={CONF_WEBFSAPI_URL: self._webfsapi_url}, reload_on_update=True
|
||||
)
|
||||
|
||||
self._name = await afsapi.get_friendly_name()
|
||||
|
||||
return await self.async_step_confirm()
|
||||
|
||||
async def _async_step_device_config_if_needed(self) -> FlowResult:
|
||||
"""Most users will not have changed the default PIN on their radio.
|
||||
|
||||
|
@ -111,21 +166,29 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
# try to login with default pin
|
||||
afsapi = AFSAPI(self._webfsapi_url, DEFAULT_PIN)
|
||||
|
||||
name = await afsapi.get_friendly_name()
|
||||
self._name = await afsapi.get_friendly_name()
|
||||
except InvalidPinException:
|
||||
# Ask for a PIN
|
||||
return await self.async_step_device_config()
|
||||
|
||||
self.context["title_placeholders"] = {"name": name}
|
||||
self.context["title_placeholders"] = {"name": self._name}
|
||||
|
||||
unique_id = await afsapi.get_radio_id()
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return self.async_create_entry(
|
||||
title=name,
|
||||
data={CONF_WEBFSAPI_URL: self._webfsapi_url, CONF_PIN: DEFAULT_PIN},
|
||||
)
|
||||
return await self._async_create_entry()
|
||||
|
||||
async def async_step_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Allow the user to confirm adding the device. Used when the default PIN could successfully be used."""
|
||||
|
||||
if user_input is not None:
|
||||
return await self._async_create_entry()
|
||||
|
||||
self._set_confirm_only()
|
||||
return self.async_show_form(step_id="confirm")
|
||||
|
||||
async def async_step_device_config(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
|
@ -145,7 +208,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
try:
|
||||
afsapi = AFSAPI(self._webfsapi_url, user_input[CONF_PIN])
|
||||
|
||||
name = await afsapi.get_friendly_name()
|
||||
self._name = await afsapi.get_friendly_name()
|
||||
|
||||
except FSConnectionError:
|
||||
errors["base"] = "cannot_connect"
|
||||
|
@ -156,15 +219,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
errors["base"] = "unknown"
|
||||
else:
|
||||
unique_id = await afsapi.get_radio_id()
|
||||
await self.async_set_unique_id(unique_id)
|
||||
await self.async_set_unique_id(unique_id, raise_on_progress=False)
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(
|
||||
title=name,
|
||||
data={
|
||||
CONF_WEBFSAPI_URL: self._webfsapi_url,
|
||||
CONF_PIN: user_input[CONF_PIN],
|
||||
},
|
||||
)
|
||||
return await self._async_create_entry(user_input[CONF_PIN])
|
||||
|
||||
data_schema = self.add_suggested_values_to_schema(
|
||||
STEP_DEVICE_CONFIG_DATA_SCHEMA, user_input
|
||||
|
@ -174,3 +231,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
data_schema=data_schema,
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def _async_create_entry(self, pin: str | None = None):
|
||||
"""Create the entry."""
|
||||
|
||||
return self.async_create_entry(
|
||||
title=self._name,
|
||||
data={CONF_WEBFSAPI_URL: self._webfsapi_url, CONF_PIN: pin or DEFAULT_PIN},
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue