Home Assistant Unofficial Reference 2024.12.1
repairs.py
Go to the documentation of this file.
1 """unifiprotect.repairs."""
2 
3 from __future__ import annotations
4 
5 from typing import cast
6 
7 from uiprotect import ProtectApiClient
8 from uiprotect.data import Bootstrap, Camera, ModelType
9 from uiprotect.data.types import FirmwareReleaseChannel
10 import voluptuous as vol
11 
12 from homeassistant import data_entry_flow
13 from homeassistant.components.repairs import ConfirmRepairFlow, RepairsFlow
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.core import HomeAssistant, callback
16 from homeassistant.helpers import issue_registry as ir
17 
18 from .const import CONF_ALLOW_EA
19 from .data import UFPConfigEntry, async_get_data_for_entry_id
20 from .utils import async_create_api_client
21 
22 
24  """Handler for an issue fixing flow."""
25 
26  _api: ProtectApiClient
27  _entry: UFPConfigEntry
28 
29  def __init__(self, *, api: ProtectApiClient, entry: UFPConfigEntry) -> None:
30  """Create flow."""
31 
32  self._api_api = api
33  self._entry_entry = entry
34  super().__init__()
35 
36  @callback
37  def _async_get_placeholders(self) -> dict[str, str]:
38  issue_registry = ir.async_get(self.hass)
39  description_placeholders = {}
40  if issue := issue_registry.async_get_issue(self.handler, self.issue_id):
41  description_placeholders = issue.translation_placeholders or {}
42  if issue.learn_more_url:
43  description_placeholders["learn_more"] = issue.learn_more_url
44 
45  return description_placeholders
46 
47 
49  """Handler for an issue fixing flow."""
50 
51  async def async_step_init(
52  self, user_input: dict[str, str] | None = None
54  """Handle the first step of a fix flow."""
55 
56  return await self.async_step_startasync_step_start()
57 
58  async def async_step_start(
59  self, user_input: dict[str, str] | None = None
61  """Handle the confirm step of a fix flow."""
62  if user_input is None:
63  placeholders = self._async_get_placeholders_async_get_placeholders()
64  return self.async_show_formasync_show_form(
65  step_id="start",
66  data_schema=vol.Schema({}),
67  description_placeholders=placeholders,
68  )
69 
70  nvr = await self._api_api.get_nvr()
71  if nvr.release_channel != FirmwareReleaseChannel.RELEASE:
72  return await self.async_step_confirmasync_step_confirm()
73  await self.hass.config_entries.async_reload(self._entry_entry.entry_id)
74  return self.async_create_entryasync_create_entry(data={})
75 
76  async def async_step_confirm(
77  self, user_input: dict[str, str] | None = None
79  """Handle the confirm step of a fix flow."""
80  if user_input is not None:
81  options = dict(self._entry_entry.options)
82  options[CONF_ALLOW_EA] = True
83  self.hass.config_entries.async_update_entry(self._entry_entry, options=options)
84  return self.async_create_entryasync_create_entry(data={})
85 
86  placeholders = self._async_get_placeholders_async_get_placeholders()
87  return self.async_show_formasync_show_form(
88  step_id="confirm",
89  data_schema=vol.Schema({}),
90  description_placeholders=placeholders,
91  )
92 
93 
95  """Handler for an issue fixing flow."""
96 
97  async def async_step_init(
98  self, user_input: dict[str, str] | None = None
100  """Handle the first step of a fix flow."""
101 
102  return await self.async_step_confirmasync_step_confirm()
103 
105  self, user_input: dict[str, str] | None = None
107  """Handle the first step of a fix flow."""
108 
109  if user_input is None:
110  placeholders = self._async_get_placeholders_async_get_placeholders()
111  return self.async_show_formasync_show_form(
112  step_id="confirm",
113  data_schema=vol.Schema({}),
114  description_placeholders=placeholders,
115  )
116 
117  self._entry_entry.async_start_reauth(self.hass)
118  return self.async_create_entryasync_create_entry(data={})
119 
120 
122  """Handler for an issue fixing flow."""
123 
124  _camera_id: str
125  _camera: Camera | None
126  _bootstrap: Bootstrap | None
127 
128  def __init__(
129  self,
130  *,
131  api: ProtectApiClient,
132  entry: UFPConfigEntry,
133  camera_id: str,
134  ) -> None:
135  """Create flow."""
136 
137  super().__init__(api=api, entry=entry)
138  self._camera_id_camera_id = camera_id
139  self._bootstrap_bootstrap = None
140  self._camera_camera = None
141 
142  @callback
143  def _async_get_placeholders(self) -> dict[str, str]:
144  description_placeholders = super()._async_get_placeholders()
145  if self._camera_camera is not None:
146  description_placeholders["camera"] = self._camera_camera.display_name
147 
148  return description_placeholders
149 
150  async def _get_boostrap(self) -> Bootstrap:
151  if self._bootstrap_bootstrap is None:
152  self._bootstrap_bootstrap = await self._api_api.get_bootstrap()
153 
154  return self._bootstrap_bootstrap
155 
156  async def _get_camera(self) -> Camera:
157  if self._camera_camera is None:
158  bootstrap = await self._get_boostrap_get_boostrap()
159  self._camera_camera = bootstrap.cameras.get(self._camera_id_camera_id)
160  assert self._camera_camera is not None
161  return self._camera_camera
162 
163  async def _enable_rtsp(self) -> None:
164  camera = await self._get_camera_get_camera()
165  bootstrap = await self._get_boostrap_get_boostrap()
166  user = bootstrap.users.get(bootstrap.auth_user_id)
167  if not user or not camera.can_write(user):
168  return
169 
170  channel = camera.channels[0]
171  channel.is_rtsp_enabled = True
172  await self._api_api.update_device(
173  ModelType.CAMERA, camera.id, {"channels": camera.unifi_dict()["channels"]}
174  )
175 
176  async def async_step_init(
177  self, user_input: dict[str, str] | None = None
179  """Handle the first step of a fix flow."""
180 
181  return await self.async_step_startasync_step_start()
182 
183  async def async_step_start(
184  self, user_input: dict[str, str] | None = None
186  """Handle the first step of a fix flow."""
187 
188  if user_input is None:
189  # make sure camera object is loaded for placeholders
190  await self._get_camera_get_camera()
191  placeholders = self._async_get_placeholders_async_get_placeholders_async_get_placeholders()
192  return self.async_show_formasync_show_form(
193  step_id="start",
194  data_schema=vol.Schema({}),
195  description_placeholders=placeholders,
196  )
197 
198  updated_camera = await self._api_api.get_camera(self._camera_id_camera_id)
199  if not any(c.is_rtsp_enabled for c in updated_camera.channels):
200  await self._enable_rtsp_enable_rtsp()
201 
202  updated_camera = await self._api_api.get_camera(self._camera_id_camera_id)
203  if any(c.is_rtsp_enabled for c in updated_camera.channels):
204  await self.hass.config_entries.async_reload(self._entry_entry.entry_id)
205  return self.async_create_entryasync_create_entry(data={})
206  return await self.async_step_confirmasync_step_confirm()
207 
209  self, user_input: dict[str, str] | None = None
211  """Handle the confirm step of a fix flow."""
212  if user_input is not None:
213  return self.async_create_entryasync_create_entry(data={})
214 
215  placeholders = self._async_get_placeholders_async_get_placeholders_async_get_placeholders()
216  return self.async_show_formasync_show_form(
217  step_id="confirm",
218  data_schema=vol.Schema({}),
219  description_placeholders=placeholders,
220  )
221 
222 
223 @callback
225  hass: HomeAssistant, entry: ConfigEntry
226 ) -> ProtectApiClient:
227  """Get or create an API client."""
228  if data := async_get_data_for_entry_id(hass, entry.entry_id):
229  return data.api
230  return async_create_api_client(hass, entry)
231 
232 
234  hass: HomeAssistant,
235  issue_id: str,
236  data: dict[str, str | int | float | None] | None,
237 ) -> RepairsFlow:
238  """Create flow."""
239  if (
240  data is not None
241  and "entry_id" in data
242  and (entry := hass.config_entries.async_get_entry(cast(str, data["entry_id"])))
243  ):
244  api = _async_get_or_create_api_client(hass, entry)
245  if issue_id == "ea_channel_warning":
246  return EAConfirmRepair(api=api, entry=entry)
247  if issue_id == "cloud_user":
248  return CloudAccountRepair(api=api, entry=entry)
249  if issue_id.startswith("rtsp_disabled_"):
250  return RTSPRepair(
251  api=api, entry=entry, camera_id=cast(str, data["camera_id"])
252  )
253  return ConfirmRepairFlow()
data_entry_flow.FlowResult async_step_confirm(self, dict[str, str]|None user_input=None)
Definition: repairs.py:106
data_entry_flow.FlowResult async_step_init(self, dict[str, str]|None user_input=None)
Definition: repairs.py:99
data_entry_flow.FlowResult async_step_confirm(self, dict[str, str]|None user_input=None)
Definition: repairs.py:78
data_entry_flow.FlowResult async_step_start(self, dict[str, str]|None user_input=None)
Definition: repairs.py:60
data_entry_flow.FlowResult async_step_init(self, dict[str, str]|None user_input=None)
Definition: repairs.py:53
None __init__(self, *ProtectApiClient api, UFPConfigEntry entry)
Definition: repairs.py:29
data_entry_flow.FlowResult async_step_init(self, dict[str, str]|None user_input=None)
Definition: repairs.py:178
data_entry_flow.FlowResult async_step_confirm(self, dict[str, str]|None user_input=None)
Definition: repairs.py:210
None __init__(self, *ProtectApiClient api, UFPConfigEntry entry, str camera_id)
Definition: repairs.py:134
data_entry_flow.FlowResult async_step_start(self, dict[str, str]|None user_input=None)
Definition: repairs.py:185
_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)
str|None update_device(HomeAssistant hass, ConfigEntry config_entry, ConfigType config)
Definition: entity.py:1512
ProtectData|None async_get_data_for_entry_id(HomeAssistant hass, str entry_id)
Definition: data.py:390
ProtectApiClient _async_get_or_create_api_client(HomeAssistant hass, ConfigEntry entry)
Definition: repairs.py:226
RepairsFlow async_create_fix_flow(HomeAssistant hass, str issue_id, dict[str, str|int|float|None]|None data)
Definition: repairs.py:237
ProtectApiClient async_create_api_client(HomeAssistant hass, UFPConfigEntry entry)
Definition: utils.py:109