"""Config flow for Panasonic Viera TV integration.""" from functools import partial import logging from urllib.request import URLError from panasonic_viera import TV_TYPE_ENCRYPTED, RemoteControl, SOAPError import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PIN, CONF_PORT from .const import ( # pylint: disable=unused-import CONF_APP_ID, CONF_ENCRYPTION_KEY, CONF_ON_ACTION, DEFAULT_NAME, DEFAULT_PORT, DOMAIN, ERROR_INVALID_PIN_CODE, ERROR_NOT_CONNECTED, REASON_NOT_CONNECTED, REASON_UNKNOWN, ) _LOGGER = logging.getLogger(__name__) class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Config flow for Panasonic Viera.""" VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL def __init__(self): """Initialize the Panasonic Viera config flow.""" self._data = { CONF_HOST: None, CONF_NAME: None, CONF_PORT: None, CONF_ON_ACTION: None, } self._remote = None async def async_step_user(self, user_input=None): """Handle the initial step.""" errors = {} if user_input is not None: await self.async_load_data(user_input) try: self._remote = await self.hass.async_add_executor_job( partial(RemoteControl, self._data[CONF_HOST], self._data[CONF_PORT]) ) except (TimeoutError, URLError, SOAPError, OSError) as err: _LOGGER.error("Could not establish remote connection: %s", err) errors["base"] = ERROR_NOT_CONNECTED except Exception as err: # pylint: disable=broad-except _LOGGER.exception("An unknown error occurred: %s", err) return self.async_abort(reason=REASON_UNKNOWN) if "base" not in errors: if self._remote.type == TV_TYPE_ENCRYPTED: return await self.async_step_pairing() return self.async_create_entry( title=self._data[CONF_NAME], data=self._data, ) return self.async_show_form( step_id="user", data_schema=vol.Schema( { vol.Required( CONF_HOST, default=self._data[CONF_HOST] if self._data[CONF_HOST] is not None else "", ): str, vol.Optional( CONF_NAME, default=self._data[CONF_NAME] if self._data[CONF_NAME] is not None else DEFAULT_NAME, ): str, } ), errors=errors, ) async def async_step_pairing(self, user_input=None): """Handle the pairing step.""" errors = {} if user_input is not None: pin = user_input[CONF_PIN] try: self._remote.authorize_pin_code(pincode=pin) except SOAPError as err: _LOGGER.error("Invalid PIN code: %s", err) errors["base"] = ERROR_INVALID_PIN_CODE except (TimeoutError, URLError, OSError) as err: _LOGGER.error("The remote connection was lost: %s", err) return self.async_abort(reason=REASON_NOT_CONNECTED) except Exception as err: # pylint: disable=broad-except _LOGGER.exception("Unknown error: %s", err) return self.async_abort(reason=REASON_UNKNOWN) if "base" not in errors: encryption_data = { CONF_APP_ID: self._remote.app_id, CONF_ENCRYPTION_KEY: self._remote.enc_key, } self._data = {**self._data, **encryption_data} return self.async_create_entry( title=self._data[CONF_NAME], data=self._data, ) try: self._remote.request_pin_code(name="Home Assistant") except (TimeoutError, URLError, SOAPError, OSError) as err: _LOGGER.error("The remote connection was lost: %s", err) return self.async_abort(reason=REASON_NOT_CONNECTED) except Exception as err: # pylint: disable=broad-except _LOGGER.exception("Unknown error: %s", err) return self.async_abort(reason=REASON_UNKNOWN) return self.async_show_form( step_id="pairing", data_schema=vol.Schema({vol.Required(CONF_PIN): str}), errors=errors, ) async def async_step_import(self, import_config): """Import a config entry from configuration.yaml.""" return await self.async_step_user(user_input=import_config) async def async_load_data(self, config): """Load the data.""" self._data = config self._data[CONF_PORT] = ( self._data[CONF_PORT] if CONF_PORT in self._data else DEFAULT_PORT ) self._data[CONF_ON_ACTION] = ( self._data[CONF_ON_ACTION] if CONF_ON_ACTION in self._data else None ) await self.async_set_unique_id(self._data[CONF_HOST]) self._abort_if_unique_id_configured()