Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for foscam integration."""
2 
3 from typing import Any
4 
5 from libpyfoscam import FoscamCamera
6 from libpyfoscam.foscam import (
7  ERROR_FOSCAM_AUTH,
8  ERROR_FOSCAM_UNAVAILABLE,
9  FOSCAM_SUCCESS,
10 )
11 import voluptuous as vol
12 
13 from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
14 from homeassistant.const import (
15  CONF_HOST,
16  CONF_NAME,
17  CONF_PASSWORD,
18  CONF_PORT,
19  CONF_USERNAME,
20 )
21 from homeassistant.data_entry_flow import AbortFlow
22 from homeassistant.exceptions import HomeAssistantError
23 
24 from .const import CONF_RTSP_PORT, CONF_STREAM, DOMAIN, LOGGER
25 
26 STREAMS = ["Main", "Sub"]
27 
28 DEFAULT_PORT = 88
29 DEFAULT_RTSP_PORT = 554
30 
31 
32 DATA_SCHEMA = vol.Schema(
33  {
34  vol.Required(CONF_HOST): str,
35  vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
36  vol.Required(CONF_USERNAME): str,
37  vol.Required(CONF_PASSWORD): str,
38  vol.Required(CONF_STREAM, default=STREAMS[0]): vol.In(STREAMS),
39  vol.Required(CONF_RTSP_PORT, default=DEFAULT_RTSP_PORT): int,
40  }
41 )
42 
43 
44 class FoscamConfigFlow(ConfigFlow, domain=DOMAIN):
45  """Handle a config flow for foscam."""
46 
47  VERSION = 2
48 
49  async def _validate_and_create(self, data):
50  """Validate the user input allows us to connect.
51 
52  Data has the keys from DATA_SCHEMA with values provided by the user.
53  """
54  self._async_abort_entries_match_async_abort_entries_match(
55  {CONF_HOST: data[CONF_HOST], CONF_PORT: data[CONF_PORT]}
56  )
57 
58  camera = FoscamCamera(
59  data[CONF_HOST],
60  data[CONF_PORT],
61  data[CONF_USERNAME],
62  data[CONF_PASSWORD],
63  verbose=False,
64  )
65 
66  # Validate data by sending a request to the camera
67  ret, _ = await self.hass.async_add_executor_job(camera.get_product_all_info)
68 
69  if ret == ERROR_FOSCAM_UNAVAILABLE:
70  raise CannotConnect
71 
72  if ret == ERROR_FOSCAM_AUTH:
73  raise InvalidAuth
74 
75  if ret != FOSCAM_SUCCESS:
76  LOGGER.error(
77  "Unexpected error code from camera %s:%s: %s",
78  data[CONF_HOST],
79  data[CONF_PORT],
80  ret,
81  )
82  raise InvalidResponse
83 
84  # Try to get camera name (only possible with admin account)
85  ret, response = await self.hass.async_add_executor_job(camera.get_dev_info)
86 
87  dev_name = response.get(
88  "devName", f"Foscam {data[CONF_HOST]}:{data[CONF_PORT]}"
89  )
90 
91  name = data.pop(CONF_NAME, dev_name)
92 
93  return self.async_create_entryasync_create_entryasync_create_entry(title=name, data=data)
94 
95  async def async_step_user(
96  self, user_input: dict[str, Any] | None = None
97  ) -> ConfigFlowResult:
98  """Handle the initial step."""
99  errors = {}
100 
101  if user_input is not None:
102  try:
103  return await self._validate_and_create_validate_and_create(user_input)
104 
105  except CannotConnect:
106  errors["base"] = "cannot_connect"
107 
108  except InvalidAuth:
109  errors["base"] = "invalid_auth"
110 
111  except InvalidResponse:
112  errors["base"] = "invalid_response"
113 
114  except AbortFlow:
115  raise
116 
117  except Exception: # noqa: BLE001
118  LOGGER.exception("Unexpected exception")
119  errors["base"] = "unknown"
120 
121  return self.async_show_formasync_show_formasync_show_form(
122  step_id="user", data_schema=DATA_SCHEMA, errors=errors
123  )
124 
125 
127  """Error to indicate we cannot connect."""
128 
129 
130 class InvalidAuth(HomeAssistantError):
131  """Error to indicate there is invalid auth."""
132 
133 
135  """Error to indicate there is invalid response."""
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:97
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)
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)
_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)