Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 68 additions & 2 deletions tests/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION,
ATTR_RELEASE_NOTES,
ATTR_RELEASE_SUMMARY,
ATTR_RELEASE_URL,
ATTR_UPDATE_PERCENTAGE,
)
from zha.exceptions import ZHAException
Expand Down Expand Up @@ -69,14 +72,21 @@ def zigpy_device_mock(zha_gateway: Gateway):
)


def create_fw_image(version: int) -> OtaImageWithMetadata:
def create_fw_image(
version: int,
changelog: str | None = None,
release_notes: str | None = None,
release_url: str | None = None,
) -> OtaImageWithMetadata:
"""Create an OTA image with a specific file version."""
return OtaImageWithMetadata(
metadata=BaseOtaImageMetadata(
file_version=version,
manufacturer_id=0x1234,
image_type=0x90,
changelog="This is a test firmware image!",
changelog=changelog,
release_notes=release_notes,
release_url=release_url,
),
firmware=firmware.OTAImage(
header=firmware.OTAImageHeader(
Expand Down Expand Up @@ -605,3 +615,59 @@ async def test_firmware_update_latest_version_even_if_downgrade(
entity.state[ATTR_LATEST_VERSION]
== f"0x{fw_image_downgrade.firmware.header.file_version:08x}"
)


async def test_firmware_update_metadata(zha_gateway: Gateway) -> None:
"""Test ZHA update platform - firmware metadata (changelog, release_notes, release_url)."""
zigpy_device = zigpy_device_mock(zha_gateway)
zha_device, ota_cluster, fw_image, installed_fw_version = await setup_test_data(
zha_gateway, zigpy_device
)

# firmware image with optional metadata
fw_image = create_fw_image(
installed_fw_version + 10,
changelog="This is a test changelog!",
release_notes="These are the full release notes.",
release_url="https://example.com/releases/v1.0",
)

zigpy_device.application.ota.get_ota_images = AsyncMock(
return_value=OtaImagesResult(
upgrades=(fw_image,),
downgrades=(),
)
)

entity = get_entity(zha_device, platform=Platform.UPDATE)

# metadata should be None before notification
assert entity.state[ATTR_RELEASE_SUMMARY] is None
assert entity.state[ATTR_RELEASE_NOTES] is None
assert entity.state[ATTR_RELEASE_URL] is None

# simulate an image available notification
await ota_cluster._handle_query_next_image(
foundation.ZCLHeader.cluster(
tsn=0x12, command_id=general.Ota.ServerCommandDefs.query_next_image.id
),
general.QueryNextImageCommand(
field_control=fw_image.firmware.header.field_control,
manufacturer_code=zha_device.manufacturer_code,
image_type=fw_image.firmware.header.image_type,
current_file_version=installed_fw_version,
hardware_version=1,
),
)

await zha_gateway.async_block_till_done()

# verify metadata is exposed in entity state now
assert entity.state[ATTR_INSTALLED_VERSION] == f"0x{installed_fw_version:08x}"
assert (
entity.state[ATTR_LATEST_VERSION]
== f"0x{fw_image.firmware.header.file_version:08x}"
)
assert entity.state[ATTR_RELEASE_SUMMARY] == "This is a test changelog!"
assert entity.state[ATTR_RELEASE_NOTES] == "These are the full release notes."
assert entity.state[ATTR_RELEASE_URL] == "https://example.com/releases/v1.0"
2 changes: 2 additions & 0 deletions zha/application/platforms/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ def device_ota_image_query_result(
self._attr_latest_version = None
self._attr_release_summary = None
self._attr_release_notes = None
self._attr_release_url = None

latest_firmware: OtaImageWithMetadata | None = None

Expand All @@ -199,6 +200,7 @@ def device_ota_image_query_result(
self._attr_latest_version = f"0x{latest_firmware.version:08x}"
self._attr_release_summary = latest_firmware.metadata.changelog or None
self._attr_release_notes = latest_firmware.metadata.release_notes or None
self._attr_release_url = latest_firmware.metadata.release_url or None
elif images_result.downgrades:
# If not, note the version of the most recent firmware
latest_firmware = None
Expand Down
Loading