From 7f5460b26d71bea3949ab66ea96bde4546be55a4 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 24 Jun 2024 23:27:39 +0200 Subject: [PATCH] Add MatterSoftwareVersion model for check_node_update Use a new model MatterSoftwareVersion to store the software version information typically fetched from DCL for the Matter nodes. --- matter_server/client/client.py | 12 ++++--- matter_server/common/models.py | 18 ++++++++++ matter_server/server/device_controller.py | 42 ++++++++++++++++++----- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/matter_server/client/client.py b/matter_server/client/client.py index e431b02a..6aae7e41 100644 --- a/matter_server/client/client.py +++ b/matter_server/client/client.py @@ -29,6 +29,7 @@ EventType, MatterNodeData, MatterNodeEvent, + MatterSoftwareVersion, MessageType, NodePingResult, ResultMessageBase, @@ -509,7 +510,7 @@ async def interview_node(self, node_id: int) -> None: """Interview a node.""" await self.send_command(APICommand.INTERVIEW_NODE, node_id=node_id) - async def check_node_update(self, node_id: int) -> dict[str, Any]: + async def check_node_update(self, node_id: int) -> MatterSoftwareVersion | None: """Check Node for updates. Return a dict with the available update information. Most notable @@ -518,10 +519,11 @@ async def check_node_update(self, node_id: int) -> dict[str, Any]: The "softwareVersionString" is a human friendly version string. """ - node_update = await self.send_command( - APICommand.CHECK_NODE_UPDATE, node_id=node_id - ) - return cast(dict[str, Any], node_update) + data = await self.send_command(APICommand.CHECK_NODE_UPDATE, node_id=node_id) + if data is None: + return None + + return dataclass_from_dict(MatterSoftwareVersion, data) async def update_node( self, diff --git a/matter_server/common/models.py b/matter_server/common/models.py index 17189ea8..6e9e1c18 100644 --- a/matter_server/common/models.py +++ b/matter_server/common/models.py @@ -210,3 +210,21 @@ class CommissioningParameters: setup_pin_code: int setup_manual_code: str setup_qr_code: str + + +@dataclass +class MatterSoftwareVersion: + """Representation of a Matter software version. Return by the check_node_update command. + + This holds Matter software version information similar to what is available from the CSA DCL. + https://on.dcl.csa-iot.org/#/Query/ModelVersion. + """ + + vid: int + pid: int + software_version: int + software_version_string: str + firmware_information: str | None + min_applicable_software_version: int + max_applicable_software_version: int + release_notes_url: str | None diff --git a/matter_server/server/device_controller.py b/matter_server/server/device_controller.py index 6594df80..605567e5 100644 --- a/matter_server/server/device_controller.py +++ b/matter_server/server/device_controller.py @@ -28,7 +28,11 @@ from matter_server.common.const import VERBOSE_LOG_LEVEL from matter_server.common.custom_clusters import check_polled_attributes -from matter_server.common.models import CommissionableNodeData, CommissioningParameters +from matter_server.common.models import ( + CommissionableNodeData, + CommissioningParameters, + MatterSoftwareVersion, +) from matter_server.server.helpers.attributes import parse_attributes_from_read_result from matter_server.server.helpers.utils import ping_ip from matter_server.server.ota import check_for_update @@ -887,7 +891,7 @@ async def import_test_node(self, dump: str) -> None: self.server.signal_event(EventType.NODE_ADDED, node) @api_command(APICommand.CHECK_NODE_UPDATE) - async def check_node_update(self, node_id: int) -> dict | None: + async def check_node_update(self, node_id: int) -> MatterSoftwareVersion | None: """ Check if there is an update for a particular node. @@ -896,12 +900,36 @@ async def check_node_update(self, node_id: int) -> dict | None: information of the latest update available. """ - return await self._check_node_update(node_id) + update = await self._check_node_update(node_id) + if update is None: + return None + + if not all( + key in update + for key in [ + "vid", + "pid", + "softwareVersion", + "softwareVersionString", + "minApplicableSoftwareVersion", + "maxApplicableSoftwareVersion", + ] + ): + raise UpdateCheckError("Invalid update data") + + return MatterSoftwareVersion( + vid=update["vid"], + pid=update["pid"], + software_version=update["softwareVersion"], + software_version_string=update["softwareVersionString"], + firmware_information=update.get("firmwareInformation", None), + min_applicable_software_version=update["minApplicableSoftwareVersion"], + max_applicable_software_version=update["maxApplicableSoftwareVersion"], + release_notes_url=update.get("releaseNotesUrl", None), + ) @api_command(APICommand.UPDATE_NODE) - async def update_node( - self, node_id: int, software_version: int | str - ) -> dict | None: + async def update_node(self, node_id: int, software_version: int | str) -> None: """ Update a node to a new software version. @@ -954,8 +982,6 @@ async def update_node( ) self._nodes_in_ota.remove(node_id) - return update - async def _check_node_update( self, node_id: int,