mirror of
https://github.com/home-assistant/core.git
synced 2026-10-06 14:29:21 -04:00
Load the Silicon Labs flasher only when needed (#183283)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, Protocol, override
|
||||
|
||||
from universal_silabs_flasher.flasher import Zbt2Flasher
|
||||
|
||||
from homeassistant.components import usb
|
||||
from homeassistant.components.homeassistant_hardware import firmware_config_flow
|
||||
from homeassistant.components.homeassistant_hardware.helpers import (
|
||||
@@ -13,6 +11,7 @@ from homeassistant.components.homeassistant_hardware.helpers import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
)
|
||||
from homeassistant.components.usb import usb_service_info_from_device
|
||||
from homeassistant.config_entries import (
|
||||
@@ -72,7 +71,7 @@ class ZBT2FirmwareMixin(ConfigEntryBaseFlow, FirmwareInstallFlowProtocol):
|
||||
context: ConfigFlowContext
|
||||
|
||||
ZIGBEE_BAUDRATE = 460800
|
||||
_flasher_cls = Zbt2Flasher
|
||||
_flasher_type = FlasherType.ZBT2
|
||||
|
||||
async def async_step_install_zigbee_firmware(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
from universal_silabs_flasher.flasher import Zbt2Flasher
|
||||
|
||||
from homeassistant.components.homeassistant_hardware.coordinator import (
|
||||
FirmwareUpdateCoordinator,
|
||||
)
|
||||
@@ -15,6 +13,7 @@ from homeassistant.components.homeassistant_hardware.update import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
)
|
||||
from homeassistant.components.update import UpdateDeviceClass
|
||||
from homeassistant.const import EntityCategory
|
||||
@@ -134,7 +133,7 @@ async def async_setup_entry(
|
||||
class FirmwareUpdateEntity(BaseFirmwareUpdateEntity):
|
||||
"""Connect ZBT-2 firmware update entity."""
|
||||
|
||||
_flasher_cls = Zbt2Flasher
|
||||
_flasher_type = FlasherType.ZBT2
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -8,9 +8,6 @@ from typing import Any, override
|
||||
|
||||
from aiohttp import ClientError
|
||||
from ha_silabs_firmware_client import FirmwareUpdateClient, ManifestMissing
|
||||
from universal_silabs_flasher.common import Version
|
||||
from universal_silabs_flasher.firmware import NabuCasaMetadata
|
||||
from universal_silabs_flasher.flasher import DeviceSpecificFlasher
|
||||
|
||||
from homeassistant.components.hassio import (
|
||||
AddonError,
|
||||
@@ -31,15 +28,20 @@ from homeassistant.data_entry_flow import AbortFlow
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.hassio import is_hassio
|
||||
from homeassistant.helpers.importlib import async_import_module
|
||||
|
||||
from .const import DOMAIN, OTBR_DOMAIN, Z2M_EMBER_DOCS_URL, ZHA_DOMAIN
|
||||
from .util import (
|
||||
COMMON_MODULE,
|
||||
FIRMWARE_MODULE,
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
OwningAddon,
|
||||
OwningIntegration,
|
||||
async_firmware_flashing_context,
|
||||
async_flash_silabs_firmware,
|
||||
async_get_flasher_cls,
|
||||
get_otbr_addon_manager,
|
||||
guess_firmware_info,
|
||||
guess_hardware_owners,
|
||||
@@ -79,7 +81,7 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
|
||||
"""Base flow to install firmware."""
|
||||
|
||||
ZIGBEE_BAUDRATE = 115200 # Default, subclasses may override
|
||||
_flasher_cls: type[DeviceSpecificFlasher]
|
||||
_flasher_type: FlasherType
|
||||
|
||||
_picked_firmware_type: PickedFirmwareType
|
||||
_zigbee_flow_strategy: ZigbeeFlowStrategy = ZigbeeFlowStrategy.RECOMMENDED
|
||||
@@ -234,9 +236,10 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
|
||||
# Installing new firmware is only truly required if the wrong type is
|
||||
# installed: upgrading to the latest release of the current firmware type
|
||||
# isn't strictly necessary for functionality.
|
||||
flasher_cls = await async_get_flasher_cls(self.hass, self._flasher_type)
|
||||
self._probed_firmware_info = await probe_silabs_firmware_info(
|
||||
self._device,
|
||||
flasher_cls=self._flasher_cls,
|
||||
flasher_cls=flasher_cls,
|
||||
)
|
||||
|
||||
firmware_install_required = self._probed_firmware_info is None or (
|
||||
@@ -273,9 +276,15 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
|
||||
assert self._probed_firmware_info is not None
|
||||
|
||||
# Make sure we do not downgrade the firmware
|
||||
fw_metadata = NabuCasaMetadata.from_json(fw_manifest.metadata)
|
||||
firmware_module = await async_import_module(self.hass, FIRMWARE_MODULE)
|
||||
common_module = await async_import_module(self.hass, COMMON_MODULE)
|
||||
fw_metadata = firmware_module.NabuCasaMetadata.from_json(
|
||||
fw_manifest.metadata
|
||||
)
|
||||
fw_version = fw_metadata.get_public_version()
|
||||
probed_fw_version = Version(self._probed_firmware_info.firmware_version)
|
||||
probed_fw_version = common_module.Version(
|
||||
self._probed_firmware_info.firmware_version
|
||||
)
|
||||
|
||||
if probed_fw_version >= fw_version:
|
||||
_LOGGER.debug(
|
||||
@@ -308,7 +317,7 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
|
||||
hass=self.hass,
|
||||
device=self._device,
|
||||
fw_data=fw_data,
|
||||
flasher_cls=self._flasher_cls,
|
||||
flasher_cls=flasher_cls,
|
||||
expected_installed_firmware_type=expected_installed_firmware_type,
|
||||
progress_callback=lambda offset, total: self.async_update_progress(
|
||||
offset / total
|
||||
|
||||
@@ -43,9 +43,11 @@ from homeassistant.helpers.storage import Store
|
||||
from .const import DOMAIN, LOGGER, SILABS_MULTIPROTOCOL_ADDON_SLUG
|
||||
from .util import (
|
||||
ApplicationType,
|
||||
FlasherType,
|
||||
WaitingAddonManager,
|
||||
async_firmware_flashing_context,
|
||||
async_flash_silabs_firmware,
|
||||
async_get_flasher_cls,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -296,8 +298,8 @@ class OptionsFlowHandler(OptionsFlow, ABC):
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def _flasher_cls(self) -> type:
|
||||
"""Return the hardware-specific flasher class."""
|
||||
def _flasher_type(self) -> FlasherType:
|
||||
"""Return the hardware-specific flasher type."""
|
||||
|
||||
@property
|
||||
def flow_manager(self) -> OptionsFlowManager:
|
||||
@@ -757,7 +759,9 @@ class OptionsFlowHandler(OptionsFlow, ABC):
|
||||
hass=self.hass,
|
||||
device=device,
|
||||
fw_data=fw_data,
|
||||
flasher_cls=self._flasher_cls,
|
||||
flasher_cls=await async_get_flasher_cls(
|
||||
self.hass, self._flasher_type
|
||||
),
|
||||
expected_installed_firmware_type=ApplicationType.EZSP,
|
||||
progress_callback=lambda offset, total: (
|
||||
self.async_update_progress(offset / total)
|
||||
|
||||
@@ -8,7 +8,6 @@ from typing import Any, cast, override
|
||||
from aiohasupervisor import SupervisorError
|
||||
from aiohasupervisor.models import RaspberryPiFirmwareInfo
|
||||
from ha_silabs_firmware_client import FirmwareManifest, FirmwareMetadata
|
||||
from universal_silabs_flasher.flasher import DeviceSpecificFlasher
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant.components.update import (
|
||||
@@ -28,8 +27,10 @@ from .helpers import async_register_firmware_info_callback
|
||||
from .util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
async_firmware_flashing_context,
|
||||
async_flash_silabs_firmware,
|
||||
async_get_flasher_cls,
|
||||
async_get_raspberry_pi_firmware_info,
|
||||
async_update_raspberry_pi_firmware,
|
||||
humanize_rpi_firmware_version,
|
||||
@@ -99,7 +100,7 @@ class BaseFirmwareUpdateEntity(
|
||||
UpdateEntityFeature.INSTALL | UpdateEntityFeature.PROGRESS
|
||||
)
|
||||
_attr_has_entity_name = True
|
||||
_flasher_cls: type[DeviceSpecificFlasher]
|
||||
_flasher_type: FlasherType
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -292,7 +293,9 @@ class BaseFirmwareUpdateEntity(
|
||||
hass=self.hass,
|
||||
device=self._current_device,
|
||||
fw_data=fw_data,
|
||||
flasher_cls=self._flasher_cls,
|
||||
flasher_cls=await async_get_flasher_cls(
|
||||
self.hass, self._flasher_type
|
||||
),
|
||||
expected_installed_firmware_type=self.entity_description.expected_firmware_type,
|
||||
progress_callback=self._update_progress,
|
||||
)
|
||||
|
||||
@@ -7,12 +7,10 @@ from contextlib import AsyncExitStack, asynccontextmanager
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
from aiohasupervisor import SupervisorError, SupervisorNotFoundError
|
||||
from aiohasupervisor.models import RaspberryPiFirmwareInfo
|
||||
from universal_silabs_flasher.const import ApplicationType as FlasherApplicationType
|
||||
from universal_silabs_flasher.firmware import parse_firmware_image
|
||||
from universal_silabs_flasher.flasher import BaseFlasher, DeviceSpecificFlasher, Flasher
|
||||
|
||||
from homeassistant.components.hassio import (
|
||||
AddonError,
|
||||
@@ -26,6 +24,7 @@ from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.hassio import is_hassio
|
||||
from homeassistant.helpers.importlib import async_import_module
|
||||
from homeassistant.helpers.singleton import singleton
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
@@ -39,8 +38,17 @@ from .const import (
|
||||
)
|
||||
from .helpers import async_firmware_update_context
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from universal_silabs_flasher.const import ApplicationType as FlasherApplicationType
|
||||
from universal_silabs_flasher.flasher import BaseFlasher, DeviceSpecificFlasher
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# The flasher library pulls in the full Zigbee stack, only load it when used
|
||||
FLASHER_MODULE = "universal_silabs_flasher.flasher"
|
||||
COMMON_MODULE = "universal_silabs_flasher.common"
|
||||
FIRMWARE_MODULE = "universal_silabs_flasher.firmware"
|
||||
|
||||
ADDON_STATE_POLL_INTERVAL = 3
|
||||
ADDON_INFO_POLL_TIMEOUT = 15 * 60
|
||||
|
||||
@@ -109,10 +117,33 @@ class ApplicationType(StrEnum):
|
||||
return cls(app_type.value)
|
||||
|
||||
def as_flasher_application_type(self) -> FlasherApplicationType:
|
||||
"""Convert the application type enum into one compatible with USF."""
|
||||
"""Convert the application type enum into one compatible with USF.
|
||||
|
||||
Only call this once the flasher library has been imported.
|
||||
"""
|
||||
from universal_silabs_flasher.const import ( # noqa: PLC0415
|
||||
ApplicationType as FlasherApplicationType,
|
||||
)
|
||||
|
||||
return FlasherApplicationType(self.value)
|
||||
|
||||
|
||||
class FlasherType(StrEnum):
|
||||
"""Device specific flasher class of the flasher library."""
|
||||
|
||||
YELLOW = "YellowFlasher"
|
||||
ZBT1 = "Zbt1Flasher"
|
||||
ZBT2 = "Zbt2Flasher"
|
||||
|
||||
|
||||
async def async_get_flasher_cls(
|
||||
hass: HomeAssistant, flasher_type: FlasherType
|
||||
) -> type[DeviceSpecificFlasher]:
|
||||
"""Return a device specific flasher class, importing the flasher on first use."""
|
||||
flasher_module = await async_import_module(hass, FLASHER_MODULE)
|
||||
return cast("type[DeviceSpecificFlasher]", getattr(flasher_module, flasher_type))
|
||||
|
||||
|
||||
@singleton(OTBR_ADDON_MANAGER_DATA)
|
||||
@callback
|
||||
def get_otbr_addon_manager(hass: HomeAssistant) -> WaitingAddonManager:
|
||||
@@ -424,12 +455,14 @@ async def probe_silabs_firmware_info(
|
||||
|
||||
|
||||
async def probe_silabs_firmware_type(
|
||||
hass: HomeAssistant,
|
||||
device: str,
|
||||
*,
|
||||
application_probe_methods: Sequence[tuple[ApplicationType, int]],
|
||||
) -> ApplicationType | None:
|
||||
"""Probe the running firmware type on a SiLabs device."""
|
||||
flasher = Flasher(
|
||||
flasher_module = await async_import_module(hass, FLASHER_MODULE)
|
||||
flasher = flasher_module.Flasher(
|
||||
device=device,
|
||||
probe_methods=[
|
||||
(m.as_flasher_application_type(), b) for m, b in application_probe_methods
|
||||
@@ -476,7 +509,10 @@ async def async_flash_silabs_firmware(
|
||||
This function is meant to be used within a firmware update context.
|
||||
"""
|
||||
|
||||
fw_image = await hass.async_add_executor_job(parse_firmware_image, fw_data)
|
||||
firmware_module = await async_import_module(hass, FIRMWARE_MODULE)
|
||||
fw_image = await hass.async_add_executor_job(
|
||||
firmware_module.parse_firmware_image, fw_data
|
||||
)
|
||||
|
||||
flasher = flasher_cls(device=device)
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, Protocol, override
|
||||
|
||||
from universal_silabs_flasher.flasher import Zbt1Flasher
|
||||
|
||||
from homeassistant.components import usb
|
||||
from homeassistant.components.homeassistant_hardware import (
|
||||
firmware_config_flow,
|
||||
@@ -16,6 +14,7 @@ from homeassistant.components.homeassistant_hardware.helpers import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
)
|
||||
from homeassistant.components.usb import usb_service_info_from_device
|
||||
from homeassistant.config_entries import (
|
||||
@@ -77,7 +76,7 @@ class SkyConnectFirmwareMixin(ConfigEntryBaseFlow, FirmwareInstallFlowProtocol):
|
||||
context: ConfigFlowContext
|
||||
|
||||
ZIGBEE_BAUDRATE = 115200
|
||||
_flasher_cls = Zbt1Flasher
|
||||
_flasher_type = FlasherType.ZBT1
|
||||
|
||||
@override
|
||||
def _get_translation_placeholders(self) -> dict[str, str]:
|
||||
@@ -268,9 +267,9 @@ class HomeAssistantSkyConnectMultiPanOptionsFlowHandler(
|
||||
|
||||
@property
|
||||
@override
|
||||
def _flasher_cls(self) -> type:
|
||||
"""Return the hardware-specific flasher class."""
|
||||
return Zbt1Flasher # type: ignore[no-any-return]
|
||||
def _flasher_type(self) -> FlasherType:
|
||||
"""Return the hardware-specific flasher type."""
|
||||
return FlasherType.ZBT1
|
||||
|
||||
@override
|
||||
async def async_step_flashing_complete(
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
from universal_silabs_flasher.flasher import Zbt1Flasher
|
||||
|
||||
from homeassistant.components.homeassistant_hardware.coordinator import (
|
||||
FirmwareUpdateCoordinator,
|
||||
)
|
||||
@@ -15,6 +13,7 @@ from homeassistant.components.homeassistant_hardware.update import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
)
|
||||
from homeassistant.components.update import UpdateDeviceClass
|
||||
from homeassistant.const import EntityCategory
|
||||
@@ -152,7 +151,7 @@ async def async_setup_entry(
|
||||
class FirmwareUpdateEntity(BaseFirmwareUpdateEntity):
|
||||
"""SkyConnect firmware update entity."""
|
||||
|
||||
_flasher_cls = Zbt1Flasher
|
||||
_flasher_type = FlasherType.ZBT1
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -6,7 +6,6 @@ import logging
|
||||
from typing import TYPE_CHECKING, Any, Protocol, final, override
|
||||
|
||||
import probatio
|
||||
from universal_silabs_flasher.flasher import YellowFlasher
|
||||
|
||||
from homeassistant.components.hassio import (
|
||||
SupervisorError,
|
||||
@@ -24,6 +23,8 @@ from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
async_get_flasher_cls,
|
||||
probe_silabs_firmware_info,
|
||||
)
|
||||
from homeassistant.config_entries import (
|
||||
@@ -81,7 +82,7 @@ class YellowFirmwareMixin(ConfigEntryBaseFlow, FirmwareInstallFlowProtocol):
|
||||
"""Mixin for Home Assistant Yellow firmware methods."""
|
||||
|
||||
ZIGBEE_BAUDRATE = 115200
|
||||
_flasher_cls = YellowFlasher
|
||||
_flasher_type = FlasherType.YELLOW
|
||||
|
||||
async def async_step_install_zigbee_firmware(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
@@ -148,7 +149,7 @@ class HomeAssistantYellowConfigFlow(
|
||||
# We do not actually use any portion of `BaseFirmwareConfigFlow` beyond this
|
||||
self._probed_firmware_info = await probe_silabs_firmware_info(
|
||||
self._device,
|
||||
flasher_cls=self._flasher_cls,
|
||||
flasher_cls=await async_get_flasher_cls(self.hass, self._flasher_type),
|
||||
)
|
||||
|
||||
# Kick off ZHA hardware discovery automatically if Zigbee firmware is running
|
||||
@@ -338,9 +339,9 @@ class HomeAssistantYellowMultiPanOptionsFlowHandler(
|
||||
|
||||
@property
|
||||
@override
|
||||
def _flasher_cls(self) -> type:
|
||||
"""Return the hardware-specific flasher class."""
|
||||
return YellowFlasher # type: ignore[no-any-return]
|
||||
def _flasher_type(self) -> FlasherType:
|
||||
"""Return the hardware-specific flasher type."""
|
||||
return FlasherType.YELLOW
|
||||
|
||||
@override
|
||||
async def async_step_flashing_complete(
|
||||
|
||||
@@ -4,7 +4,6 @@ import logging
|
||||
from typing import override
|
||||
|
||||
from aiohasupervisor import SupervisorError
|
||||
from universal_silabs_flasher.flasher import YellowFlasher
|
||||
|
||||
from homeassistant.components.homeassistant_hardware.coordinator import (
|
||||
FirmwareUpdateCoordinator,
|
||||
@@ -17,6 +16,7 @@ from homeassistant.components.homeassistant_hardware.update import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
async_get_raspberry_pi_firmware_info,
|
||||
)
|
||||
from homeassistant.components.update import UpdateDeviceClass, UpdateEntity
|
||||
@@ -178,7 +178,7 @@ async def async_setup_entry(
|
||||
class FirmwareUpdateEntity(BaseFirmwareUpdateEntity):
|
||||
"""Yellow firmware update entity."""
|
||||
|
||||
_flasher_cls = YellowFlasher
|
||||
_flasher_type = FlasherType.YELLOW
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -70,6 +70,7 @@ async def warn_on_wrong_silabs_firmware(hass: HomeAssistant, device: str) -> boo
|
||||
return False
|
||||
|
||||
app_type = await probe_silabs_firmware_type(
|
||||
hass,
|
||||
device,
|
||||
application_probe_methods=[
|
||||
(ApplicationType.GECKO_BOOTLOADER, 115200),
|
||||
|
||||
@@ -324,9 +324,7 @@ async def test_options_flow(
|
||||
),
|
||||
],
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.parse_firmware_image"
|
||||
),
|
||||
patch("universal_silabs_flasher.firmware.parse_firmware_image"),
|
||||
):
|
||||
pick_result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
|
||||
@@ -14,7 +14,7 @@ from ha_silabs_firmware_client import (
|
||||
FirmwareUpdateClient,
|
||||
)
|
||||
import pytest
|
||||
from universal_silabs_flasher.flasher import DeviceSpecificFlasher, Zbt1Flasher
|
||||
from universal_silabs_flasher.flasher import DeviceSpecificFlasher
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant.components.homeassistant_hardware.const import (
|
||||
@@ -30,6 +30,7 @@ from homeassistant.components.homeassistant_hardware.firmware_config_flow import
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
)
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_IGNORE,
|
||||
@@ -65,7 +66,7 @@ class FakeFirmwareConfigFlow(BaseFirmwareConfigFlow, domain=TEST_DOMAIN):
|
||||
VERSION = 1
|
||||
MINOR_VERSION = 2
|
||||
|
||||
_flasher_cls = Zbt1Flasher
|
||||
_flasher_type = FlasherType.ZBT1
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
@@ -129,7 +130,7 @@ class FakeFirmwareConfigFlow(BaseFirmwareConfigFlow, domain=TEST_DOMAIN):
|
||||
class FakeFirmwareOptionsFlowHandler(BaseFirmwareOptionsFlow):
|
||||
"""Options flow for `test_firmware_domain`."""
|
||||
|
||||
_flasher_cls = Zbt1Flasher
|
||||
_flasher_type = FlasherType.ZBT1
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
"""Instantiate options flow."""
|
||||
@@ -336,9 +337,7 @@ def mock_firmware_info(
|
||||
"homeassistant.components.homeassistant_hardware.firmware_config_flow.FirmwareUpdateClient",
|
||||
return_value=mock_update_client,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.parse_firmware_image"
|
||||
),
|
||||
patch("universal_silabs_flasher.firmware.parse_firmware_image"),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.firmware_config_flow.async_flash_silabs_firmware",
|
||||
side_effect=mock_flash_firmware,
|
||||
|
||||
@@ -11,6 +11,7 @@ import pytest
|
||||
|
||||
from homeassistant.components.hassio import AddonError, AddonInfo, AddonState, HassIO
|
||||
from homeassistant.components.homeassistant_hardware import silabs_multiprotocol_addon
|
||||
from homeassistant.components.homeassistant_hardware.util import FlasherType
|
||||
from homeassistant.components.zha import DOMAIN as ZHA_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
||||
from homeassistant.const import EVENT_COMPONENT_LOADED
|
||||
@@ -106,9 +107,9 @@ class FakeOptionsFlow(silabs_multiprotocol_addon.OptionsFlowHandler):
|
||||
return "test_zigbee_ncp"
|
||||
|
||||
@property
|
||||
def _flasher_cls(self) -> type:
|
||||
"""Return the hardware-specific flasher class."""
|
||||
return Mock
|
||||
def _flasher_type(self) -> FlasherType:
|
||||
"""Return the hardware-specific flasher type."""
|
||||
return FlasherType.ZBT1
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
||||
@@ -8,7 +8,7 @@ from unittest.mock import Mock, patch
|
||||
|
||||
import aiohttp
|
||||
import pytest
|
||||
from universal_silabs_flasher.flasher import DeviceSpecificFlasher, Zbt1Flasher
|
||||
from universal_silabs_flasher.flasher import DeviceSpecificFlasher
|
||||
|
||||
from homeassistant.components.homeassistant import (
|
||||
DOMAIN as HOMEASSISTANT_DOMAIN,
|
||||
@@ -30,6 +30,7 @@ from homeassistant.components.homeassistant_hardware.update import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
OwningIntegration,
|
||||
)
|
||||
from homeassistant.components.update import UpdateDeviceClass
|
||||
@@ -176,7 +177,7 @@ async def mock_async_setup_update_entities(
|
||||
class MockFirmwareUpdateEntity(BaseFirmwareUpdateEntity):
|
||||
"""Mock SkyConnect firmware update entity."""
|
||||
|
||||
_flasher_cls = Zbt1Flasher
|
||||
_flasher_type = FlasherType.ZBT1
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -8,6 +8,7 @@ import pytest
|
||||
from universal_silabs_flasher.common import Version as FlasherVersion
|
||||
from universal_silabs_flasher.const import ApplicationType as FlasherApplicationType
|
||||
from universal_silabs_flasher.firmware import GBLImage
|
||||
from universal_silabs_flasher.flasher import YellowFlasher, Zbt1Flasher, Zbt2Flasher
|
||||
|
||||
from homeassistant.components.hassio import (
|
||||
AddonError,
|
||||
@@ -22,10 +23,12 @@ from homeassistant.components.homeassistant_hardware.helpers import (
|
||||
from homeassistant.components.homeassistant_hardware.util import (
|
||||
ApplicationType,
|
||||
FirmwareInfo,
|
||||
FlasherType,
|
||||
OwningAddon,
|
||||
OwningIntegration,
|
||||
async_firmware_flashing_context,
|
||||
async_flash_silabs_firmware,
|
||||
async_get_flasher_cls,
|
||||
get_otbr_addon_firmware_info,
|
||||
get_z2m_addon_firmware_info,
|
||||
get_z2m_addon_manager,
|
||||
@@ -789,6 +792,21 @@ async def test_probe_silabs_firmware_info(
|
||||
assert result == expected_fw_info
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("flasher_type", "expected_cls"),
|
||||
[
|
||||
(FlasherType.YELLOW, YellowFlasher),
|
||||
(FlasherType.ZBT1, Zbt1Flasher),
|
||||
(FlasherType.ZBT2, Zbt2Flasher),
|
||||
],
|
||||
)
|
||||
async def test_async_get_flasher_cls(
|
||||
hass: HomeAssistant, flasher_type: FlasherType, expected_cls: type
|
||||
) -> None:
|
||||
"""Test resolving the flasher class of a flasher type."""
|
||||
assert await async_get_flasher_cls(hass, flasher_type) is expected_cls
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("probe_result", "expected"),
|
||||
[
|
||||
@@ -798,7 +816,9 @@ async def test_probe_silabs_firmware_info(
|
||||
],
|
||||
)
|
||||
async def test_probe_silabs_firmware_type(
|
||||
probe_result: FirmwareInfo | None, expected: ApplicationType | None
|
||||
hass: HomeAssistant,
|
||||
probe_result: FirmwareInfo | None,
|
||||
expected: ApplicationType | None,
|
||||
) -> None:
|
||||
"""Test getting the firmware type from the probe result."""
|
||||
|
||||
@@ -813,11 +833,12 @@ async def test_probe_silabs_firmware_type(
|
||||
mock_flasher.app_type = None
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.Flasher",
|
||||
"universal_silabs_flasher.flasher.Flasher",
|
||||
autospec=True,
|
||||
return_value=mock_flasher,
|
||||
):
|
||||
result = await probe_silabs_firmware_type(
|
||||
hass,
|
||||
"/dev/ttyUSB0",
|
||||
application_probe_methods=[
|
||||
(ApplicationType.EZSP, 460800),
|
||||
@@ -872,9 +893,7 @@ async def test_async_flash_silabs_firmware(hass: HomeAssistant) -> None:
|
||||
owners=[owner1, owner2],
|
||||
),
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.parse_firmware_image"
|
||||
),
|
||||
patch("universal_silabs_flasher.firmware.parse_firmware_image"),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.probe_silabs_firmware_info",
|
||||
return_value=expected_firmware_info,
|
||||
@@ -952,9 +971,7 @@ async def test_async_flash_silabs_firmware_flash_failure(
|
||||
owners=[owner1, owner2],
|
||||
),
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.parse_firmware_image"
|
||||
),
|
||||
patch("universal_silabs_flasher.firmware.parse_firmware_image"),
|
||||
pytest.raises(HomeAssistantError, match=expected_error_msg) as exc,
|
||||
):
|
||||
async with async_firmware_flashing_context(
|
||||
@@ -1006,9 +1023,7 @@ async def test_async_flash_silabs_firmware_probe_failure(hass: HomeAssistant) ->
|
||||
owners=[owner1, owner2],
|
||||
),
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.parse_firmware_image"
|
||||
),
|
||||
patch("universal_silabs_flasher.firmware.parse_firmware_image"),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.probe_silabs_firmware_info",
|
||||
return_value=None,
|
||||
|
||||
@@ -395,9 +395,7 @@ async def test_firmware_options_flow_zigbee(hass: HomeAssistant) -> None:
|
||||
),
|
||||
],
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.homeassistant_hardware.util.parse_firmware_image"
|
||||
),
|
||||
patch("universal_silabs_flasher.firmware.parse_firmware_image"),
|
||||
):
|
||||
pick_result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
|
||||
Reference in New Issue
Block a user