Skip to content

Commit bf19060

Browse files
puddlyfrenck
authored andcommitted
Reduce Connect firmware install times by removing unnecessary firmware probing (home-assistant#153012)
1 parent e982ac1 commit bf19060

File tree

7 files changed

+90
-313
lines changed

7 files changed

+90
-313
lines changed

homeassistant/components/homeassistant_hardware/firmware_config_flow.py

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -155,34 +155,6 @@ async def async_step_pick_firmware(
155155
description_placeholders=self._get_translation_placeholders(),
156156
)
157157

158-
async def _probe_firmware_info(
159-
self,
160-
probe_methods: tuple[ApplicationType, ...] = (
161-
# We probe in order of frequency: Zigbee, Thread, then multi-PAN
162-
ApplicationType.GECKO_BOOTLOADER,
163-
ApplicationType.EZSP,
164-
ApplicationType.SPINEL,
165-
ApplicationType.CPC,
166-
),
167-
) -> bool:
168-
"""Probe the firmware currently on the device."""
169-
assert self._device is not None
170-
171-
self._probed_firmware_info = await probe_silabs_firmware_info(
172-
self._device,
173-
probe_methods=probe_methods,
174-
)
175-
176-
return (
177-
self._probed_firmware_info is not None
178-
and self._probed_firmware_info.firmware_type
179-
in (
180-
ApplicationType.EZSP,
181-
ApplicationType.SPINEL,
182-
ApplicationType.CPC,
183-
)
184-
)
185-
186158
async def _install_firmware_step(
187159
self,
188160
fw_update_url: str,
@@ -236,12 +208,6 @@ async def _install_firmware(
236208
expected_installed_firmware_type: ApplicationType,
237209
) -> None:
238210
"""Install firmware."""
239-
if not await self._probe_firmware_info():
240-
raise AbortFlow(
241-
reason="unsupported_firmware",
242-
description_placeholders=self._get_translation_placeholders(),
243-
)
244-
245211
assert self._device is not None
246212

247213
# Keep track of the firmware we're working with, for error messages
@@ -250,6 +216,8 @@ async def _install_firmware(
250216
# Installing new firmware is only truly required if the wrong type is
251217
# installed: upgrading to the latest release of the current firmware type
252218
# isn't strictly necessary for functionality.
219+
self._probed_firmware_info = await probe_silabs_firmware_info(self._device)
220+
253221
firmware_install_required = self._probed_firmware_info is None or (
254222
self._probed_firmware_info.firmware_type != expected_installed_firmware_type
255223
)
@@ -301,7 +269,7 @@ async def _install_firmware(
301269
# Otherwise, fail
302270
raise AbortFlow(reason="firmware_download_failed") from err
303271

304-
await async_flash_silabs_firmware(
272+
self._probed_firmware_info = await async_flash_silabs_firmware(
305273
hass=self.hass,
306274
device=self._device,
307275
fw_data=fw_data,
@@ -314,15 +282,6 @@ async def _install_firmware(
314282

315283
async def _configure_and_start_otbr_addon(self) -> None:
316284
"""Configure and start the OTBR addon."""
317-
318-
# Before we start the addon, confirm that the correct firmware is running
319-
# and populate `self._probed_firmware_info` with the correct information
320-
if not await self._probe_firmware_info(probe_methods=(ApplicationType.SPINEL,)):
321-
raise AbortFlow(
322-
"unsupported_firmware",
323-
description_placeholders=self._get_translation_placeholders(),
324-
)
325-
326285
otbr_manager = get_otbr_addon_manager(self.hass)
327286
addon_info = await self._async_get_addon_info(otbr_manager)
328287

@@ -444,12 +403,12 @@ async def _async_continue_picked_firmware(self) -> ConfigFlowResult:
444403
if self._picked_firmware_type == PickedFirmwareType.ZIGBEE:
445404
return await self.async_step_install_zigbee_firmware()
446405

447-
return await self.async_step_prepare_thread_installation()
406+
return await self.async_step_install_thread_firmware()
448407

449-
async def async_step_prepare_thread_installation(
408+
async def async_step_finish_thread_installation(
450409
self, user_input: dict[str, Any] | None = None
451410
) -> ConfigFlowResult:
452-
"""Prepare for Thread installation by stopping the OTBR addon if needed."""
411+
"""Finish Thread installation by starting the OTBR addon."""
453412
if not is_hassio(self.hass):
454413
return self.async_abort(
455414
reason="not_hassio_thread",
@@ -459,22 +418,12 @@ async def async_step_prepare_thread_installation(
459418
otbr_manager = get_otbr_addon_manager(self.hass)
460419
addon_info = await self._async_get_addon_info(otbr_manager)
461420

462-
if addon_info.state == AddonState.RUNNING:
463-
# Stop the addon before continuing to flash firmware
464-
await otbr_manager.async_stop_addon()
465-
466-
return await self.async_step_install_thread_firmware()
467-
468-
async def async_step_finish_thread_installation(
469-
self, user_input: dict[str, Any] | None = None
470-
) -> ConfigFlowResult:
471-
"""Finish Thread installation by starting the OTBR addon."""
472-
otbr_manager = get_otbr_addon_manager(self.hass)
473-
addon_info = await self._async_get_addon_info(otbr_manager)
474-
475421
if addon_info.state == AddonState.NOT_INSTALLED:
476422
return await self.async_step_install_otbr_addon()
477423

424+
if addon_info.state == AddonState.RUNNING:
425+
await otbr_manager.async_stop_addon()
426+
478427
return await self.async_step_start_otbr_addon()
479428

480429
async def async_step_pick_firmware_zigbee(
@@ -511,12 +460,6 @@ async def async_step_continue_zigbee(
511460
assert self._device is not None
512461
assert self._hardware_name is not None
513462

514-
if not await self._probe_firmware_info(probe_methods=(ApplicationType.EZSP,)):
515-
return self.async_abort(
516-
reason="unsupported_firmware",
517-
description_placeholders=self._get_translation_placeholders(),
518-
)
519-
520463
if self._zigbee_integration == ZigbeeIntegration.OTHER:
521464
return self._async_flow_finished()
522465

homeassistant/components/homeassistant_hardware/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ class ApplicationType(StrEnum):
4242
"""Application type running on a device."""
4343

4444
GECKO_BOOTLOADER = "bootloader"
45-
CPC = "cpc"
4645
EZSP = "ezsp"
4746
SPINEL = "spinel"
47+
CPC = "cpc"
4848
ROUTER = "router"
4949

5050
@classmethod

homeassistant/components/homeassistant_yellow/config_flow.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from homeassistant.components.homeassistant_hardware.util import (
2828
ApplicationType,
2929
FirmwareInfo,
30+
probe_silabs_firmware_info,
3031
)
3132
from homeassistant.config_entries import (
3233
SOURCE_HARDWARE,
@@ -141,8 +142,10 @@ async def async_step_system(
141142
self, data: dict[str, Any] | None = None
142143
) -> ConfigFlowResult:
143144
"""Handle the initial step."""
145+
assert self._device is not None
146+
144147
# We do not actually use any portion of `BaseFirmwareConfigFlow` beyond this
145-
await self._probe_firmware_info()
148+
self._probed_firmware_info = await probe_silabs_firmware_info(self._device)
146149

147150
# Kick off ZHA hardware discovery automatically if Zigbee firmware is running
148151
if (

tests/components/homeassistant_connect_zbt2/test_config_flow.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ async def mock_install_firmware_step(
7272
step_id: str,
7373
next_step_id: str,
7474
) -> ConfigFlowResult:
75+
self._probed_firmware_info = FirmwareInfo(
76+
device=usb_data.device,
77+
firmware_type=expected_installed_firmware_type,
78+
firmware_version=fw_version,
79+
owners=[],
80+
source="probe",
81+
)
7582
return await getattr(self, f"async_step_{next_step_id}")()
7683

7784
with (
@@ -80,16 +87,6 @@ async def mock_install_firmware_step(
8087
autospec=True,
8188
side_effect=mock_install_firmware_step,
8289
),
83-
patch(
84-
"homeassistant.components.homeassistant_hardware.firmware_config_flow.probe_silabs_firmware_info",
85-
return_value=FirmwareInfo(
86-
device=usb_data.device,
87-
firmware_type=fw_type,
88-
firmware_version=fw_version,
89-
owners=[],
90-
source="probe",
91-
),
92-
),
9390
):
9491
pick_result = await hass.config_entries.flow.async_configure(
9592
result["flow_id"],
@@ -157,6 +154,13 @@ async def mock_install_firmware_step(
157154
step_id: str,
158155
next_step_id: str,
159156
) -> ConfigFlowResult:
157+
self._probed_firmware_info = FirmwareInfo(
158+
device=usb_data.device,
159+
firmware_type=expected_installed_firmware_type,
160+
firmware_version=fw_version,
161+
owners=[],
162+
source="probe",
163+
)
160164
return await getattr(self, f"async_step_{next_step_id}")()
161165

162166
with (
@@ -165,16 +169,6 @@ async def mock_install_firmware_step(
165169
autospec=True,
166170
side_effect=mock_install_firmware_step,
167171
),
168-
patch(
169-
"homeassistant.components.homeassistant_hardware.firmware_config_flow.probe_silabs_firmware_info",
170-
return_value=FirmwareInfo(
171-
device=usb_data.device,
172-
firmware_type=fw_type,
173-
firmware_version=fw_version,
174-
owners=[],
175-
source="probe",
176-
),
177-
),
178172
):
179173
result = await hass.config_entries.flow.async_configure(
180174
result["flow_id"],
@@ -258,6 +252,13 @@ async def mock_install_firmware_step(
258252
step_id: str,
259253
next_step_id: str,
260254
) -> ConfigFlowResult:
255+
self._probed_firmware_info = FirmwareInfo(
256+
device=usb_data.device,
257+
firmware_type=expected_installed_firmware_type,
258+
firmware_version="7.4.4.0 build 0",
259+
owners=[],
260+
source="probe",
261+
)
261262
return await getattr(self, f"async_step_{next_step_id}")()
262263

263264
with (
@@ -270,16 +271,6 @@ async def mock_install_firmware_step(
270271
autospec=True,
271272
side_effect=mock_install_firmware_step,
272273
),
273-
patch(
274-
"homeassistant.components.homeassistant_hardware.firmware_config_flow.probe_silabs_firmware_info",
275-
return_value=FirmwareInfo(
276-
device=usb_data.device,
277-
firmware_type=ApplicationType.EZSP,
278-
firmware_version="7.4.4.0 build 0",
279-
owners=[],
280-
source="probe",
281-
),
282-
),
283274
):
284275
pick_result = await hass.config_entries.options.async_configure(
285276
result["flow_id"],

0 commit comments

Comments
 (0)