1 """Config flow for DoorBird integration."""
3 from __future__
import annotations
5 from collections.abc
import Mapping
6 from http
import HTTPStatus
10 from aiohttp
import ClientResponseError
11 from doorbirdpy
import DoorBird
12 import voluptuous
as vol
29 DEFAULT_DOORBELL_EVENT,
34 from .util
import get_mac_address_from_door_station_info
36 _LOGGER = logging.getLogger(__name__)
38 DEFAULT_OPTIONS = {CONF_EVENTS: [DEFAULT_DOORBELL_EVENT, DEFAULT_MOTION_EVENT]}
41 AUTH_VOL_DICT: VolDictType = {
42 vol.Required(CONF_USERNAME): str,
43 vol.Required(CONF_PASSWORD): str,
45 AUTH_SCHEMA = vol.Schema(AUTH_VOL_DICT)
49 host: str |
None =
None, name: str |
None =
None
53 vol.Required(CONF_HOST, default=host): str,
55 vol.Optional(CONF_NAME, default=name): str,
60 async
def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, str]:
61 """Validate the user input allows us to connect."""
64 data[CONF_HOST], data[CONF_USERNAME], data[CONF_PASSWORD], http_session=session
67 info = await device.info()
68 except ClientResponseError
as err:
69 if err.status == HTTPStatus.UNAUTHORIZED:
70 raise InvalidAuth
from err
71 raise CannotConnect
from err
72 except OSError
as err:
73 raise CannotConnect
from err
78 return {
"title": data[CONF_HOST],
"mac_addr": mac_addr}
82 """Verify the doorbell state endpoint returns a 401."""
84 device = DoorBird(host,
"",
"", http_session=session)
86 await device.doorbell_state()
87 except ClientResponseError
as err:
88 if err.status == HTTPStatus.UNAUTHORIZED:
96 """Handle a config flow for DoorBird."""
100 reauth_entry: ConfigEntry
103 """Initialize the DoorBird config flow."""
107 self, entry_data: Mapping[str, Any]
108 ) -> ConfigFlowResult:
114 self, user_input: dict[str, Any] |
None =
None
115 ) -> ConfigFlowResult:
116 """Handle reauth input."""
117 errors: dict[str, str] = {}
119 placeholders: dict[str, str] = {
120 CONF_NAME: existing_data[CONF_NAME],
121 CONF_HOST: existing_data[CONF_HOST],
123 self.context[
"title_placeholders"] = placeholders
124 if user_input
is not None:
127 CONF_USERNAME: user_input[CONF_USERNAME],
128 CONF_PASSWORD: user_input[CONF_PASSWORD],
137 description_placeholders=placeholders,
138 step_id=
"reauth_confirm",
139 data_schema=AUTH_SCHEMA,
144 self, user_input: dict[str, Any] |
None =
None
145 ) -> ConfigFlowResult:
146 """Handle the initial step."""
147 errors: dict[str, str] = {}
148 if user_input
is not None:
154 title=info[
"title"], data=user_input, options=DEFAULT_OPTIONS
161 self, discovery_info: zeroconf.ZeroconfServiceInfo
162 ) -> ConfigFlowResult:
163 """Prepare configuration for a discovered doorbird device."""
164 macaddress = discovery_info.properties[
"macaddress"]
166 if macaddress[:6] != DOORBIRD_OUI:
168 if discovery_info.ip_address.is_link_local:
170 if discovery_info.ip_address.version != 4:
174 host = discovery_info.host
182 chop_ending =
"._axis-video._tcp.local."
183 friendly_hostname = discovery_info.name.removesuffix(chop_ending)
185 self.context[
"title_placeholders"] = {
186 CONF_NAME: friendly_hostname,
194 self, user_input: dict[str, Any]
195 ) -> tuple[dict[str, Any], dict[str, Any]]:
196 """Validate doorbird or error."""
201 except CannotConnect:
202 errors[
"base"] =
"cannot_connect"
204 errors[
"base"] =
"invalid_auth"
206 _LOGGER.exception(
"Unexpected exception")
207 errors[
"base"] =
"unknown"
213 config_entry: ConfigEntry,
214 ) -> OptionsFlowHandler:
215 """Get the options flow for this handler."""
220 """Handle a option flow for doorbird."""
223 self, user_input: dict[str, Any] |
None =
None
224 ) -> ConfigFlowResult:
225 """Handle options flow."""
226 if user_input
is not None:
227 events = [event.strip()
for event
in user_input[CONF_EVENTS].split(
",")]
228 return self.
async_create_entryasync_create_entry(title=
"", data={CONF_EVENTS: events})
234 options_schema = vol.Schema(
235 {vol.Optional(CONF_EVENTS, default=
", ".join(current_events)): str}
237 return self.
async_show_formasync_show_form(step_id=
"init", data_schema=options_schema)
241 """Error to indicate we cannot connect."""
244 class InvalidAuth(HomeAssistantError):
245 """Error to indicate there is invalid auth."""
OptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult async_step_reauth_confirm(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_zeroconf(self, zeroconf.ZeroconfServiceInfo discovery_info)
tuple[dict[str, Any], dict[str, Any]] _async_validate_or_error(self, dict[str, Any] user_input)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry _get_reauth_entry(self)
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)
ConfigFlowResult async_update_reload_and_abort(self, ConfigEntry entry, *str|None|UndefinedType unique_id=UNDEFINED, str|UndefinedType title=UNDEFINED, Mapping[str, Any]|UndefinedType data=UNDEFINED, Mapping[str, Any]|UndefinedType data_updates=UNDEFINED, Mapping[str, Any]|UndefinedType options=UNDEFINED, str|UndefinedType reason=UNDEFINED, bool reload_even_if_entry_is_unchanged=True)
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)
None _async_abort_entries_match(self, dict[str, Any]|None match_dict=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)
ConfigEntry config_entry(self)
None config_entry(self, ConfigEntry value)
_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_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)
bool async_verify_supported_device(HomeAssistant hass, str host)
vol.Schema _schema_with_defaults(str|None host=None, str|None name=None)
dict[str, str] validate_input(HomeAssistant hass, dict[str, Any] data)
str get_mac_address_from_door_station_info(dict[str, Any] door_station_info)
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)