2828 OptionsFlow ,
2929)
3030from homeassistant .core import callback
31- from homeassistant .data_entry_flow import AbortFlow , progress_step
31+ from homeassistant .data_entry_flow import AbortFlow
3232from homeassistant .exceptions import HomeAssistantError
3333from homeassistant .helpers .aiohttp_client import async_get_clientsession
3434from homeassistant .helpers .hassio import is_hassio
@@ -97,6 +97,12 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
9797 self .addon_uninstall_task : asyncio .Task | None = None
9898 self .firmware_install_task : asyncio .Task [None ] | None = None
9999 self .installing_firmware_name : str | None = None
100+ self ._install_otbr_addon_task : asyncio .Task [None ] | None = None
101+ self ._start_otbr_addon_task : asyncio .Task [None ] | None = None
102+
103+ # Progress flow steps cannot abort so we need to store the abort reason and then
104+ # re-raise it in a dedicated step
105+ self ._progress_error : AbortFlow | None = None
100106
101107 def _get_translation_placeholders (self ) -> dict [str , str ]:
102108 """Shared translation placeholders."""
@@ -106,6 +112,11 @@ def _get_translation_placeholders(self) -> dict[str, str]:
106112 if self ._probed_firmware_info is not None
107113 else "unknown"
108114 ),
115+ "firmware_name" : (
116+ self .installing_firmware_name
117+ if self .installing_firmware_name is not None
118+ else "unknown"
119+ ),
109120 "model" : self ._hardware_name ,
110121 }
111122
@@ -182,22 +193,22 @@ async def _install_firmware_step(
182193 return self .async_show_progress (
183194 step_id = step_id ,
184195 progress_action = "install_firmware" ,
185- description_placeholders = {
186- ** self ._get_translation_placeholders (),
187- "firmware_name" : firmware_name ,
188- },
196+ description_placeholders = self ._get_translation_placeholders (),
189197 progress_task = self .firmware_install_task ,
190198 )
191199
192200 try :
193201 await self .firmware_install_task
194202 except AbortFlow as err :
195- return self .async_show_progress_done (
196- next_step_id = err .reason ,
197- )
203+ self ._progress_error = err
204+ return self .async_show_progress_done (next_step_id = "progress_failed" )
198205 except HomeAssistantError :
199206 _LOGGER .exception ("Failed to flash firmware" )
200- return self .async_show_progress_done (next_step_id = "firmware_install_failed" )
207+ self ._progress_error = AbortFlow (
208+ reason = "fw_install_failed" ,
209+ description_placeholders = self ._get_translation_placeholders (),
210+ )
211+ return self .async_show_progress_done (next_step_id = "progress_failed" )
201212 finally :
202213 self .firmware_install_task = None
203214
@@ -241,7 +252,10 @@ async def _install_firmware(
241252 _LOGGER .debug ("Skipping firmware upgrade due to index download failure" )
242253 return
243254
244- raise AbortFlow (reason = "firmware_download_failed" ) from err
255+ raise AbortFlow (
256+ reason = "fw_download_failed" ,
257+ description_placeholders = self ._get_translation_placeholders (),
258+ ) from err
245259
246260 if not firmware_install_required :
247261 assert self ._probed_firmware_info is not None
@@ -270,7 +284,10 @@ async def _install_firmware(
270284 return
271285
272286 # Otherwise, fail
273- raise AbortFlow (reason = "firmware_download_failed" ) from err
287+ raise AbortFlow (
288+ reason = "fw_download_failed" ,
289+ description_placeholders = self ._get_translation_placeholders (),
290+ ) from err
274291
275292 self ._probed_firmware_info = await async_flash_silabs_firmware (
276293 hass = self .hass ,
@@ -313,41 +330,6 @@ async def _configure_and_start_otbr_addon(self) -> None:
313330
314331 await otbr_manager .async_start_addon_waiting ()
315332
316- async def async_step_firmware_download_failed (
317- self , user_input : dict [str , Any ] | None = None
318- ) -> ConfigFlowResult :
319- """Abort when firmware download failed."""
320- assert self .installing_firmware_name is not None
321- return self .async_abort (
322- reason = "fw_download_failed" ,
323- description_placeholders = {
324- ** self ._get_translation_placeholders (),
325- "firmware_name" : self .installing_firmware_name ,
326- },
327- )
328-
329- async def async_step_firmware_install_failed (
330- self , user_input : dict [str , Any ] | None = None
331- ) -> ConfigFlowResult :
332- """Abort when firmware install failed."""
333- assert self .installing_firmware_name is not None
334- return self .async_abort (
335- reason = "fw_install_failed" ,
336- description_placeholders = {
337- ** self ._get_translation_placeholders (),
338- "firmware_name" : self .installing_firmware_name ,
339- },
340- )
341-
342- async def async_step_unsupported_firmware (
343- self , user_input : dict [str , Any ] | None = None
344- ) -> ConfigFlowResult :
345- """Abort when unsupported firmware is detected."""
346- return self .async_abort (
347- reason = "unsupported_firmware" ,
348- description_placeholders = self ._get_translation_placeholders (),
349- )
350-
351333 async def async_step_zigbee_installation_type (
352334 self , user_input : dict [str , Any ] | None = None
353335 ) -> ConfigFlowResult :
@@ -511,16 +493,15 @@ async def async_step_install_thread_firmware(
511493 """Install Thread firmware."""
512494 raise NotImplementedError
513495
514- @progress_step (
515- description_placeholders = lambda self : {
516- ** self ._get_translation_placeholders (),
517- "addon_name" : get_otbr_addon_manager (self .hass ).addon_name ,
518- }
519- )
520- async def async_step_install_otbr_addon (
496+ async def async_step_progress_failed (
521497 self , user_input : dict [str , Any ] | None = None
522498 ) -> ConfigFlowResult :
523- """Show progress dialog for installing the OTBR addon."""
499+ """Abort when progress step failed."""
500+ assert self ._progress_error is not None
501+ raise self ._progress_error
502+
503+ async def _async_install_otbr_addon (self ) -> None :
504+ """Do the work of installing the OTBR addon."""
524505 addon_manager = get_otbr_addon_manager (self .hass )
525506 addon_info = await self ._async_get_addon_info (addon_manager )
526507
@@ -538,18 +519,39 @@ async def async_step_install_otbr_addon(
538519 },
539520 ) from err
540521
541- return await self .async_step_finish_thread_installation ()
542-
543- @progress_step (
544- description_placeholders = lambda self : {
545- ** self ._get_translation_placeholders (),
546- "addon_name" : get_otbr_addon_manager (self .hass ).addon_name ,
547- }
548- )
549- async def async_step_start_otbr_addon (
522+ async def async_step_install_otbr_addon (
550523 self , user_input : dict [str , Any ] | None = None
551524 ) -> ConfigFlowResult :
552- """Configure OTBR to point to the SkyConnect and run the addon."""
525+ """Show progress dialog for installing the OTBR addon."""
526+ if self ._install_otbr_addon_task is None :
527+ self ._install_otbr_addon_task = self .hass .async_create_task (
528+ self ._async_install_otbr_addon (),
529+ "Install OTBR addon" ,
530+ )
531+
532+ if not self ._install_otbr_addon_task .done ():
533+ return self .async_show_progress (
534+ step_id = "install_otbr_addon" ,
535+ progress_action = "install_otbr_addon" ,
536+ description_placeholders = {
537+ ** self ._get_translation_placeholders (),
538+ "addon_name" : get_otbr_addon_manager (self .hass ).addon_name ,
539+ },
540+ progress_task = self ._install_otbr_addon_task ,
541+ )
542+
543+ try :
544+ await self ._install_otbr_addon_task
545+ except AbortFlow as err :
546+ self ._progress_error = err
547+ return self .async_show_progress_done (next_step_id = "progress_failed" )
548+ finally :
549+ self ._install_otbr_addon_task = None
550+
551+ return self .async_show_progress_done (next_step_id = "finish_thread_installation" )
552+
553+ async def _async_start_otbr_addon (self ) -> None :
554+ """Do the work of starting the OTBR addon."""
553555 try :
554556 await self ._configure_and_start_otbr_addon ()
555557 except AddonError as err :
@@ -562,7 +564,36 @@ async def async_step_start_otbr_addon(
562564 },
563565 ) from err
564566
565- return await self .async_step_pre_confirm_otbr ()
567+ async def async_step_start_otbr_addon (
568+ self , user_input : dict [str , Any ] | None = None
569+ ) -> ConfigFlowResult :
570+ """Configure OTBR to point to the SkyConnect and run the addon."""
571+ if self ._start_otbr_addon_task is None :
572+ self ._start_otbr_addon_task = self .hass .async_create_task (
573+ self ._async_start_otbr_addon (),
574+ "Start OTBR addon" ,
575+ )
576+
577+ if not self ._start_otbr_addon_task .done ():
578+ return self .async_show_progress (
579+ step_id = "start_otbr_addon" ,
580+ progress_action = "start_otbr_addon" ,
581+ description_placeholders = {
582+ ** self ._get_translation_placeholders (),
583+ "addon_name" : get_otbr_addon_manager (self .hass ).addon_name ,
584+ },
585+ progress_task = self ._start_otbr_addon_task ,
586+ )
587+
588+ try :
589+ await self ._start_otbr_addon_task
590+ except AbortFlow as err :
591+ self ._progress_error = err
592+ return self .async_show_progress_done (next_step_id = "progress_failed" )
593+ finally :
594+ self ._start_otbr_addon_task = None
595+
596+ return self .async_show_progress_done (next_step_id = "pre_confirm_otbr" )
566597
567598 async def async_step_pre_confirm_otbr (
568599 self , user_input : dict [str , Any ] | None = None
0 commit comments