mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 13:57:10 +00:00
Handle all firmware types for ZBT-1 and Yellow update entities (#141674)
Handle other firmware types
This commit is contained in:
parent
17c56208ee
commit
5283e1a39f
@ -199,7 +199,7 @@ class BaseFirmwareUpdateEntity(
|
|||||||
# This entity is not currently associated with a device so we must manually
|
# This entity is not currently associated with a device so we must manually
|
||||||
# give it a name
|
# give it a name
|
||||||
self._attr_name = f"{self._config_entry.title} Update"
|
self._attr_name = f"{self._config_entry.title} Update"
|
||||||
self._attr_title = self.entity_description.firmware_name or "unknown"
|
self._attr_title = self.entity_description.firmware_name or "Unknown"
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self._current_firmware_info is None
|
self._current_firmware_info is None
|
||||||
|
@ -64,6 +64,28 @@ FIRMWARE_ENTITY_DESCRIPTIONS: dict[
|
|||||||
expected_firmware_type=ApplicationType.SPINEL,
|
expected_firmware_type=ApplicationType.SPINEL,
|
||||||
firmware_name="OpenThread RCP",
|
firmware_name="OpenThread RCP",
|
||||||
),
|
),
|
||||||
|
ApplicationType.CPC: FirmwareUpdateEntityDescription(
|
||||||
|
key="firmware",
|
||||||
|
display_precision=0,
|
||||||
|
device_class=UpdateDeviceClass.FIRMWARE,
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
version_parser=lambda fw: fw,
|
||||||
|
fw_type="skyconnect_multipan",
|
||||||
|
version_key="cpc_version",
|
||||||
|
expected_firmware_type=ApplicationType.CPC,
|
||||||
|
firmware_name="Multiprotocol",
|
||||||
|
),
|
||||||
|
ApplicationType.GECKO_BOOTLOADER: FirmwareUpdateEntityDescription(
|
||||||
|
key="firmware",
|
||||||
|
display_precision=0,
|
||||||
|
device_class=UpdateDeviceClass.FIRMWARE,
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
version_parser=lambda fw: fw,
|
||||||
|
fw_type=None, # We don't want to update the bootloader
|
||||||
|
version_key="gecko_bootloader_version",
|
||||||
|
expected_firmware_type=ApplicationType.GECKO_BOOTLOADER,
|
||||||
|
firmware_name="Gecko Bootloader",
|
||||||
|
),
|
||||||
None: FirmwareUpdateEntityDescription(
|
None: FirmwareUpdateEntityDescription(
|
||||||
key="firmware",
|
key="firmware",
|
||||||
display_precision=0,
|
display_precision=0,
|
||||||
@ -86,9 +108,16 @@ def _async_create_update_entity(
|
|||||||
) -> FirmwareUpdateEntity:
|
) -> FirmwareUpdateEntity:
|
||||||
"""Create an update entity that handles firmware type changes."""
|
"""Create an update entity that handles firmware type changes."""
|
||||||
firmware_type = config_entry.data[FIRMWARE]
|
firmware_type = config_entry.data[FIRMWARE]
|
||||||
|
|
||||||
|
try:
|
||||||
entity_description = FIRMWARE_ENTITY_DESCRIPTIONS[
|
entity_description = FIRMWARE_ENTITY_DESCRIPTIONS[
|
||||||
ApplicationType(firmware_type) if firmware_type is not None else None
|
ApplicationType(firmware_type)
|
||||||
]
|
]
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Unknown firmware type %r, using default entity description", firmware_type
|
||||||
|
)
|
||||||
|
entity_description = FIRMWARE_ENTITY_DESCRIPTIONS[None]
|
||||||
|
|
||||||
entity = FirmwareUpdateEntity(
|
entity = FirmwareUpdateEntity(
|
||||||
device=config_entry.data["device"],
|
device=config_entry.data["device"],
|
||||||
|
@ -64,6 +64,28 @@ FIRMWARE_ENTITY_DESCRIPTIONS: dict[
|
|||||||
expected_firmware_type=ApplicationType.SPINEL,
|
expected_firmware_type=ApplicationType.SPINEL,
|
||||||
firmware_name="OpenThread RCP",
|
firmware_name="OpenThread RCP",
|
||||||
),
|
),
|
||||||
|
ApplicationType.CPC: FirmwareUpdateEntityDescription(
|
||||||
|
key="firmware",
|
||||||
|
display_precision=0,
|
||||||
|
device_class=UpdateDeviceClass.FIRMWARE,
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
version_parser=lambda fw: fw,
|
||||||
|
fw_type="yellow_multipan",
|
||||||
|
version_key="cpc_version",
|
||||||
|
expected_firmware_type=ApplicationType.CPC,
|
||||||
|
firmware_name="Multiprotocol",
|
||||||
|
),
|
||||||
|
ApplicationType.GECKO_BOOTLOADER: FirmwareUpdateEntityDescription(
|
||||||
|
key="firmware",
|
||||||
|
display_precision=0,
|
||||||
|
device_class=UpdateDeviceClass.FIRMWARE,
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
version_parser=lambda fw: fw,
|
||||||
|
fw_type=None, # We don't want to update the bootloader
|
||||||
|
version_key="gecko_bootloader_version",
|
||||||
|
expected_firmware_type=ApplicationType.GECKO_BOOTLOADER,
|
||||||
|
firmware_name="Gecko Bootloader",
|
||||||
|
),
|
||||||
None: FirmwareUpdateEntityDescription(
|
None: FirmwareUpdateEntityDescription(
|
||||||
key="radio_firmware",
|
key="radio_firmware",
|
||||||
display_precision=0,
|
display_precision=0,
|
||||||
@ -86,9 +108,16 @@ def _async_create_update_entity(
|
|||||||
) -> FirmwareUpdateEntity:
|
) -> FirmwareUpdateEntity:
|
||||||
"""Create an update entity that handles firmware type changes."""
|
"""Create an update entity that handles firmware type changes."""
|
||||||
firmware_type = config_entry.data[FIRMWARE]
|
firmware_type = config_entry.data[FIRMWARE]
|
||||||
|
|
||||||
|
try:
|
||||||
entity_description = FIRMWARE_ENTITY_DESCRIPTIONS[
|
entity_description = FIRMWARE_ENTITY_DESCRIPTIONS[
|
||||||
ApplicationType(firmware_type) if firmware_type is not None else None
|
ApplicationType(firmware_type)
|
||||||
]
|
]
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Unknown firmware type %r, using default entity description", firmware_type
|
||||||
|
)
|
||||||
|
entity_description = FIRMWARE_ENTITY_DESCRIPTIONS[None]
|
||||||
|
|
||||||
entity = FirmwareUpdateEntity(
|
entity = FirmwareUpdateEntity(
|
||||||
device=RADIO_DEVICE,
|
device=RADIO_DEVICE,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""Test SkyConnect firmware update entity."""
|
"""Test SkyConnect firmware update entity."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.homeassistant_hardware.helpers import (
|
from homeassistant.components.homeassistant_hardware.helpers import (
|
||||||
async_notify_firmware_info,
|
async_notify_firmware_info,
|
||||||
)
|
)
|
||||||
@ -84,3 +86,47 @@ async def test_zbt1_update_entity(hass: HomeAssistant) -> None:
|
|||||||
assert state_spinel.attributes["title"] == "OpenThread RCP"
|
assert state_spinel.attributes["title"] == "OpenThread RCP"
|
||||||
assert state_spinel.attributes["installed_version"] == "2.4.4.0"
|
assert state_spinel.attributes["installed_version"] == "2.4.4.0"
|
||||||
assert state_spinel.attributes["latest_version"] is None
|
assert state_spinel.attributes["latest_version"] is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("firmware", "version", "expected"),
|
||||||
|
[
|
||||||
|
("ezsp", "7.3.1.0 build 0", "EmberZNet Zigbee 7.3.1.0"),
|
||||||
|
("spinel", "SL-OPENTHREAD/2.4.4.0_GitHub-7074a43e4", "OpenThread RCP 2.4.4.0"),
|
||||||
|
("bootloader", "2.4.2", "Gecko Bootloader 2.4.2"),
|
||||||
|
("cpc", "4.3.2", "Multiprotocol 4.3.2"),
|
||||||
|
("router", "1.2.3.4", "Unknown 1.2.3.4"), # Not supported but still shown
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_zbt1_update_entity_state(
|
||||||
|
hass: HomeAssistant, firmware: str, version: str, expected: str
|
||||||
|
) -> None:
|
||||||
|
"""Test the ZBT-1 firmware update entity with different firmware types."""
|
||||||
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
|
zbt1_config_entry = MockConfigEntry(
|
||||||
|
domain="homeassistant_sky_connect",
|
||||||
|
data={
|
||||||
|
"firmware": firmware,
|
||||||
|
"firmware_version": version,
|
||||||
|
"device": USB_DATA_ZBT1.device,
|
||||||
|
"manufacturer": USB_DATA_ZBT1.manufacturer,
|
||||||
|
"pid": USB_DATA_ZBT1.pid,
|
||||||
|
"product": USB_DATA_ZBT1.description,
|
||||||
|
"serial_number": USB_DATA_ZBT1.serial_number,
|
||||||
|
"vid": USB_DATA_ZBT1.vid,
|
||||||
|
},
|
||||||
|
version=1,
|
||||||
|
minor_version=3,
|
||||||
|
)
|
||||||
|
zbt1_config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert await hass.config_entries.async_setup(zbt1_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(UPDATE_ENTITY_ID)
|
||||||
|
assert state is not None
|
||||||
|
assert (
|
||||||
|
f"{state.attributes['title']} {state.attributes['installed_version']}"
|
||||||
|
== expected
|
||||||
|
)
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.homeassistant_hardware.helpers import (
|
from homeassistant.components.homeassistant_hardware.helpers import (
|
||||||
async_notify_firmware_info,
|
async_notify_firmware_info,
|
||||||
)
|
)
|
||||||
@ -90,3 +92,53 @@ async def test_yellow_update_entity(hass: HomeAssistant) -> None:
|
|||||||
assert state_spinel.attributes["title"] == "OpenThread RCP"
|
assert state_spinel.attributes["title"] == "OpenThread RCP"
|
||||||
assert state_spinel.attributes["installed_version"] == "2.4.4.0"
|
assert state_spinel.attributes["installed_version"] == "2.4.4.0"
|
||||||
assert state_spinel.attributes["latest_version"] is None
|
assert state_spinel.attributes["latest_version"] is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("firmware", "version", "expected"),
|
||||||
|
[
|
||||||
|
("ezsp", "7.3.1.0 build 0", "EmberZNet Zigbee 7.3.1.0"),
|
||||||
|
("spinel", "SL-OPENTHREAD/2.4.4.0_GitHub-7074a43e4", "OpenThread RCP 2.4.4.0"),
|
||||||
|
("bootloader", "2.4.2", "Gecko Bootloader 2.4.2"),
|
||||||
|
("cpc", "4.3.2", "Multiprotocol 4.3.2"),
|
||||||
|
("router", "1.2.3.4", "Unknown 1.2.3.4"), # Not supported but still shown
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_yellow_update_entity_state(
|
||||||
|
hass: HomeAssistant, firmware: str, version: str, expected: str
|
||||||
|
) -> None:
|
||||||
|
"""Test the Yellow firmware update entity with different firmware types."""
|
||||||
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
|
# Set up the Yellow integration
|
||||||
|
yellow_config_entry = MockConfigEntry(
|
||||||
|
title="Home Assistant Yellow",
|
||||||
|
domain="homeassistant_yellow",
|
||||||
|
data={
|
||||||
|
"firmware": firmware,
|
||||||
|
"firmware_version": version,
|
||||||
|
"device": RADIO_DEVICE,
|
||||||
|
},
|
||||||
|
version=1,
|
||||||
|
minor_version=3,
|
||||||
|
)
|
||||||
|
yellow_config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.homeassistant_yellow.is_hassio", return_value=True
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.homeassistant_yellow.get_os_info",
|
||||||
|
return_value={"board": "yellow"},
|
||||||
|
),
|
||||||
|
):
|
||||||
|
assert await hass.config_entries.async_setup(yellow_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(UPDATE_ENTITY_ID)
|
||||||
|
assert state is not None
|
||||||
|
assert (
|
||||||
|
f"{state.attributes['title']} {state.attributes['installed_version']}"
|
||||||
|
== expected
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user