1 """Config flow to configure SmartThings."""
3 from http
import HTTPStatus
7 from aiohttp
import ClientResponseError
8 from pysmartthings
import APIResponseError, AppOAuth, SmartThings
9 from pysmartthings.installedapp
import format_install_url
10 import voluptuous
as vol
17 APP_OAUTH_CLIENT_NAME,
20 CONF_INSTALLED_APP_ID,
26 from .smartapp
import (
32 setup_smartapp_endpoint,
34 validate_webhook_requirements,
37 _LOGGER = logging.getLogger(__name__)
41 """Handle configuration of SmartThings integrations."""
50 """Create a new instance of the flow handler."""
59 """Occurs when a previously entry setup fails and is re-initiated."""
63 self, user_input: dict[str, Any] |
None =
None
64 ) -> ConfigFlowResult:
65 """Validate and confirm webhook setup."""
76 reason=
"invalid_webhook_url",
77 description_placeholders={
78 "webhook_url": webhook_url,
80 "https://www.home-assistant.io/integrations/smartthings/"
86 if user_input
is None:
89 description_placeholders={
"webhook_url": webhook_url},
96 self, user_input: dict[str, str] |
None =
None
97 ) -> ConfigFlowResult:
98 """Get the Personal Access Token and validate it."""
99 errors: dict[str, str] = {}
100 if user_input
is None or CONF_ACCESS_TOKEN
not in user_input:
106 if not VAL_UID_MATCHER.match(self.
access_tokenaccess_token):
107 errors[CONF_ACCESS_TOKEN] =
"token_invalid_format"
122 if entry.data[CONF_APP_ID] == app.app_id
131 app_oauth = AppOAuth(app.app_id)
132 app_oauth.client_name = APP_OAUTH_CLIENT_NAME
133 app_oauth.scope.extend(APP_OAUTH_SCOPES)
134 client = await self.
apiapi.generate_app_oauth(app_oauth)
144 except APIResponseError
as ex:
145 if ex.is_target_error():
146 errors[
"base"] =
"webhook_error"
148 errors[
"base"] =
"app_setup_error"
150 "API error setting up the SmartApp: %s", ex.raw_error_response
153 except ClientResponseError
as ex:
154 if ex.status == HTTPStatus.UNAUTHORIZED:
155 errors[CONF_ACCESS_TOKEN] =
"token_unauthorized"
157 "Unauthorized error received setting up SmartApp", exc_info=
True
159 elif ex.status == HTTPStatus.FORBIDDEN:
160 errors[CONF_ACCESS_TOKEN] =
"token_forbidden"
162 "Forbidden error received setting up SmartApp", exc_info=
True
165 errors[
"base"] =
"app_setup_error"
166 _LOGGER.exception(
"Unexpected error setting up the SmartApp")
169 errors[
"base"] =
"app_setup_error"
170 _LOGGER.exception(
"Unexpected error setting up the SmartApp")
176 self, user_input: dict[str, str] |
None =
None
177 ) -> ConfigFlowResult:
178 """Ask user to select the location to setup."""
179 if user_input
is None or CONF_LOCATION_ID
not in user_input:
181 existing_locations = [
184 locations = await self.
apiapi.locations()
185 locations_options = {
186 location.location_id: location.name
187 for location
in locations
188 if location.location_id
not in existing_locations
190 if not locations_options:
194 step_id=
"select_location",
195 data_schema=vol.Schema(
196 {vol.Required(CONF_LOCATION_ID): vol.In(locations_options)}
205 self, user_input: dict[str, Any] |
None =
None
206 ) -> ConfigFlowResult:
207 """Wait for the user to authorize the app installation."""
208 user_input = {}
if user_input
is None else user_input
209 self.
installed_app_idinstalled_app_id = user_input.get(CONF_INSTALLED_APP_ID)
210 self.
refresh_tokenrefresh_token = user_input.get(CONF_REFRESH_TOKEN)
223 entry.data.get(CONF_ACCESS_TOKEN)
231 data_schema=vol.Schema(
232 {vol.Required(CONF_ACCESS_TOKEN, default=self.
access_tokenaccess_token): str}
235 description_placeholders={
236 "token_url":
"https://account.smartthings.com/tokens",
238 "https://www.home-assistant.io/integrations/smartthings/"
244 self, user_input: dict[str, Any] |
None =
None
245 ) -> ConfigFlowResult:
246 """Create a config entry at completion of a flow and authorization of the app."""
253 CONF_APP_ID: self.
app_idapp_id,
257 location = await self.
apiapi.location(data[CONF_LOCATION_ID])
ConfigFlowResult async_step_import(self, None import_data)
def _show_step_pat(self, errors)
ConfigFlowResult async_step_select_location(self, dict[str, str]|None user_input=None)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_install(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_pat(self, dict[str, str]|None user_input=None)
ConfigFlowResult async_step_authorize(self, dict[str, Any]|None user_input=None)
ConfigEntry|None async_set_unique_id(self, str|None unique_id=None, *bool raise_on_progress=True)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
list[ConfigEntry] _async_current_entries(self, bool|None include_ignore=None)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_external_step(self, *str|None step_id=None, str url, Mapping[str, str]|None description_placeholders=None)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_external_step_done(self, *str next_step_id)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
def setup_smartapp_endpoint(HomeAssistant hass, bool fresh_install)
bool validate_webhook_requirements(HomeAssistant hass)
AppEntity|None find_app(HomeAssistant hass, SmartThings api)
def setup_smartapp(hass, app)
str get_webhook_url(HomeAssistant hass)
def create_app(HomeAssistant hass, api)
def update_app(HomeAssistant hass, app)
str format_unique_id(str address)
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)