Show progress for zwave_js.update entity (#77905)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Raman Gupta 2022-09-08 16:40:55 -04:00 committed by GitHub
parent 823e7e8830
commit 52d2ebd2c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import Callable from collections.abc import Callable
from datetime import datetime, timedelta from datetime import datetime, timedelta
from math import floor
from typing import Any from typing import Any
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
@ -11,7 +12,7 @@ from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import NodeStatus from zwave_js_server.const import NodeStatus
from zwave_js_server.exceptions import BaseZwaveJSServerError, FailedZWaveCommand from zwave_js_server.exceptions import BaseZwaveJSServerError, FailedZWaveCommand
from zwave_js_server.model.driver import Driver from zwave_js_server.model.driver import Driver
from zwave_js_server.model.firmware import FirmwareUpdateInfo from zwave_js_server.model.firmware import FirmwareUpdateInfo, FirmwareUpdateProgress
from zwave_js_server.model.node import Node as ZwaveNode from zwave_js_server.model.node import Node as ZwaveNode
from homeassistant.components.update import UpdateDeviceClass, UpdateEntity from homeassistant.components.update import UpdateDeviceClass, UpdateEntity
@ -63,7 +64,9 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity):
_attr_entity_category = EntityCategory.CONFIG _attr_entity_category = EntityCategory.CONFIG
_attr_device_class = UpdateDeviceClass.FIRMWARE _attr_device_class = UpdateDeviceClass.FIRMWARE
_attr_supported_features = ( _attr_supported_features = (
UpdateEntityFeature.INSTALL | UpdateEntityFeature.RELEASE_NOTES UpdateEntityFeature.INSTALL
| UpdateEntityFeature.RELEASE_NOTES
| UpdateEntityFeature.PROGRESS
) )
_attr_has_entity_name = True _attr_has_entity_name = True
_attr_should_poll = False _attr_should_poll = False
@ -78,6 +81,8 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity):
self._latest_version_firmware: FirmwareUpdateInfo | None = None self._latest_version_firmware: FirmwareUpdateInfo | None = None
self._status_unsub: Callable[[], None] | None = None self._status_unsub: Callable[[], None] | None = None
self._poll_unsub: Callable[[], None] | None = None self._poll_unsub: Callable[[], None] | None = None
self._progress_unsub: Callable[[], None] | None = None
self._num_files_installed: int = 0
# Entity class attributes # Entity class attributes
self._attr_name = "Firmware" self._attr_name = "Firmware"
@ -93,6 +98,36 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity):
self._status_unsub = None self._status_unsub = None
self.hass.async_create_task(self._async_update()) self.hass.async_create_task(self._async_update())
@callback
def _update_progress(self, event: dict[str, Any]) -> None:
"""Update install progress on event."""
progress: FirmwareUpdateProgress = event["firmware_update_progress"]
if not self._latest_version_firmware:
return
# We will assume that each file in the firmware update represents an equal
# percentage of the overall progress. This is likely not true because each file
# may be a different size, but it's the best we can do since we don't know the
# total number of fragments across all files.
self._attr_in_progress = floor(
100
* (
self._num_files_installed
+ (progress.sent_fragments / progress.total_fragments)
)
/ len(self._latest_version_firmware.files)
)
self.async_write_ha_state()
@callback
def _reset_progress(self) -> None:
"""Reset update install progress."""
if self._progress_unsub:
self._progress_unsub()
self._progress_unsub = None
self._num_files_installed = 0
self._attr_in_progress = False
self.async_write_ha_state()
async def _async_update(self, _: HomeAssistant | datetime | None = None) -> None: async def _async_update(self, _: HomeAssistant | datetime | None = None) -> None:
"""Update the entity.""" """Update the entity."""
self._poll_unsub = None self._poll_unsub = None
@ -152,17 +187,28 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity):
"""Install an update.""" """Install an update."""
firmware = self._latest_version_firmware firmware = self._latest_version_firmware
assert firmware assert firmware
try: self._attr_in_progress = 0
self.async_write_ha_state()
self._progress_unsub = self.node.on(
"firmware update progress", self._update_progress
)
for file in firmware.files: for file in firmware.files:
try:
await self.driver.controller.async_begin_ota_firmware_update( await self.driver.controller.async_begin_ota_firmware_update(
self.node, file self.node, file
) )
except BaseZwaveJSServerError as err: except BaseZwaveJSServerError as err:
self._reset_progress()
raise HomeAssistantError(err) from err raise HomeAssistantError(err) from err
else: self._num_files_installed += 1
self._attr_in_progress = floor(
100 * self._num_files_installed / len(firmware.files)
)
self.async_write_ha_state()
self._attr_installed_version = self._attr_latest_version = firmware.version self._attr_installed_version = self._attr_latest_version = firmware.version
self._latest_version_firmware = None self._latest_version_firmware = None
self.async_write_ha_state() self._reset_progress()
async def async_poll_value(self, _: bool) -> None: async def async_poll_value(self, _: bool) -> None:
"""Poll a value.""" """Poll a value."""
@ -208,3 +254,7 @@ class ZWaveNodeFirmwareUpdate(UpdateEntity):
if self._poll_unsub: if self._poll_unsub:
self._poll_unsub() self._poll_unsub()
self._poll_unsub = None self._poll_unsub = None
if self._progress_unsub:
self._progress_unsub()
self._progress_unsub = None