1
mirror of https://github.com/home-assistant/core synced 2024-08-28 03:36:46 +02:00
ha-core/homeassistant/components/foscam/config_flow.py
2021-12-14 13:11:07 +01:00

130 lines
3.5 KiB
Python

"""Config flow for foscam integration."""
from libpyfoscam import FoscamCamera
from libpyfoscam.foscam import (
ERROR_FOSCAM_AUTH,
ERROR_FOSCAM_UNAVAILABLE,
FOSCAM_SUCCESS,
)
import voluptuous as vol
from homeassistant import config_entries, exceptions
from homeassistant.const import (
CONF_HOST,
CONF_NAME,
CONF_PASSWORD,
CONF_PORT,
CONF_USERNAME,
)
from homeassistant.data_entry_flow import AbortFlow
from .const import CONF_RTSP_PORT, CONF_STREAM, DOMAIN, LOGGER
STREAMS = ["Main", "Sub"]
DEFAULT_PORT = 88
DEFAULT_RTSP_PORT = 554
DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
vol.Required(CONF_STREAM, default=STREAMS[0]): vol.In(STREAMS),
vol.Required(CONF_RTSP_PORT, default=DEFAULT_RTSP_PORT): int,
}
)
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for foscam."""
VERSION = 2
async def _validate_and_create(self, data):
"""Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA with values provided by the user.
"""
self._async_abort_entries_match(
{CONF_HOST: data[CONF_HOST], CONF_PORT: data[CONF_PORT]}
)
camera = FoscamCamera(
data[CONF_HOST],
data[CONF_PORT],
data[CONF_USERNAME],
data[CONF_PASSWORD],
verbose=False,
)
# Validate data by sending a request to the camera
ret, _ = await self.hass.async_add_executor_job(camera.get_product_all_info)
if ret == ERROR_FOSCAM_UNAVAILABLE:
raise CannotConnect
if ret == ERROR_FOSCAM_AUTH:
raise InvalidAuth
if ret != FOSCAM_SUCCESS:
LOGGER.error(
"Unexpected error code from camera %s:%s: %s",
data[CONF_HOST],
data[CONF_PORT],
ret,
)
raise InvalidResponse
# Try to get camera name (only possible with admin account)
ret, response = await self.hass.async_add_executor_job(camera.get_dev_info)
dev_name = response.get(
"devName", f"Foscam {data[CONF_HOST]}:{data[CONF_PORT]}"
)
name = data.pop(CONF_NAME, dev_name)
return self.async_create_entry(title=name, data=data)
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
errors = {}
if user_input is not None:
try:
return await self._validate_and_create(user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
except InvalidResponse:
errors["base"] = "invalid_response"
except AbortFlow:
raise
except Exception: # pylint: disable=broad-except
LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
return self.async_show_form(
step_id="user", data_schema=DATA_SCHEMA, errors=errors
)
class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""
class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""
class InvalidResponse(exceptions.HomeAssistantError):
"""Error to indicate there is invalid response."""