Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Support for EZVIZ camera."""
2 
3 import logging
4 
5 from pyezviz.client import EzvizClient
6 from pyezviz.exceptions import (
7  EzvizAuthTokenExpired,
8  EzvizAuthVerificationCode,
9  HTTPError,
10  InvalidURL,
11  PyEzvizError,
12 )
13 
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import CONF_TIMEOUT, CONF_TYPE, CONF_URL, Platform
16 from homeassistant.core import HomeAssistant
17 from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
18 
19 from .const import (
20  ATTR_TYPE_CAMERA,
21  ATTR_TYPE_CLOUD,
22  CONF_FFMPEG_ARGUMENTS,
23  CONF_RFSESSION_ID,
24  CONF_SESSION_ID,
25  DATA_COORDINATOR,
26  DEFAULT_FFMPEG_ARGUMENTS,
27  DEFAULT_TIMEOUT,
28  DOMAIN,
29 )
30 from .coordinator import EzvizDataUpdateCoordinator
31 
32 _LOGGER = logging.getLogger(__name__)
33 
34 PLATFORMS_BY_TYPE: dict[str, list] = {
35  ATTR_TYPE_CAMERA: [],
36  ATTR_TYPE_CLOUD: [
37  Platform.ALARM_CONTROL_PANEL,
38  Platform.BINARY_SENSOR,
39  Platform.BUTTON,
40  Platform.CAMERA,
41  Platform.IMAGE,
42  Platform.LIGHT,
43  Platform.NUMBER,
44  Platform.SELECT,
45  Platform.SENSOR,
46  Platform.SIREN,
47  Platform.SWITCH,
48  Platform.UPDATE,
49  ],
50 }
51 
52 
53 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
54  """Set up EZVIZ from a config entry."""
55  hass.data.setdefault(DOMAIN, {})
56  sensor_type: str = entry.data[CONF_TYPE]
57  ezviz_client = None
58 
59  if not entry.options:
60  options = {
61  CONF_FFMPEG_ARGUMENTS: DEFAULT_FFMPEG_ARGUMENTS,
62  CONF_TIMEOUT: DEFAULT_TIMEOUT,
63  }
64 
65  hass.config_entries.async_update_entry(entry, options=options)
66 
67  # Initialize EZVIZ cloud entities
68  if PLATFORMS_BY_TYPE[sensor_type]:
69  # Initiate reauth config flow if account token if not present.
70  if not entry.data.get(CONF_SESSION_ID):
71  raise ConfigEntryAuthFailed
72 
73  ezviz_client = EzvizClient(
74  token={
75  CONF_SESSION_ID: entry.data.get(CONF_SESSION_ID),
76  CONF_RFSESSION_ID: entry.data.get(CONF_RFSESSION_ID),
77  "api_url": entry.data.get(CONF_URL),
78  },
79  timeout=entry.options.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
80  )
81 
82  try:
83  await hass.async_add_executor_job(ezviz_client.login)
84 
85  except (EzvizAuthTokenExpired, EzvizAuthVerificationCode) as error:
86  raise ConfigEntryAuthFailed from error
87 
88  except (InvalidURL, HTTPError, PyEzvizError) as error:
89  _LOGGER.error("Unable to connect to Ezviz service: %s", str(error))
90  raise ConfigEntryNotReady from error
91 
92  coordinator = EzvizDataUpdateCoordinator(
93  hass, api=ezviz_client, api_timeout=entry.options[CONF_TIMEOUT]
94  )
95 
96  await coordinator.async_config_entry_first_refresh()
97 
98  hass.data[DOMAIN][entry.entry_id] = {DATA_COORDINATOR: coordinator}
99 
100  entry.async_on_unload(entry.add_update_listener(_async_update_listener))
101 
102  # Check EZVIZ cloud account entity is present, reload cloud account entities for camera entity change to take effect.
103  # Cameras are accessed via local RTSP stream with unique credentials per camera.
104  # Separate camera entities allow for credential changes per camera.
105  if sensor_type == ATTR_TYPE_CAMERA and hass.data[DOMAIN]:
106  for item in hass.config_entries.async_entries(domain=DOMAIN):
107  if item.data.get(CONF_TYPE) == ATTR_TYPE_CLOUD:
108  _LOGGER.debug("Reload Ezviz main account with camera entry")
109  await hass.config_entries.async_reload(item.entry_id)
110  return True
111 
112  await hass.config_entries.async_forward_entry_setups(
113  entry, PLATFORMS_BY_TYPE[sensor_type]
114  )
115 
116  return True
117 
118 
119 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
120  """Unload a config entry."""
121  sensor_type = entry.data[CONF_TYPE]
122 
123  unload_ok = await hass.config_entries.async_unload_platforms(
124  entry, PLATFORMS_BY_TYPE[sensor_type]
125  )
126  if sensor_type == ATTR_TYPE_CLOUD and unload_ok:
127  hass.data[DOMAIN].pop(entry.entry_id)
128 
129  return unload_ok
130 
131 
132 async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
133  """Handle options update."""
134  await hass.config_entries.async_reload(entry.entry_id)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:53
None _async_update_listener(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:132
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:119