mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 17:27:52 +00:00
Add QNAP QSW Update platform (#71019)
* qnap_qsw: add Update platform Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> * qnap_qsw: update: allow init if firmware coordinator fails QSW API can return an error if update servers aren't reachable and this prevents the integration from loading. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> * tests: qnap_qsw: achieve 100% coverage Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
This commit is contained in:
parent
0caeeb56c5
commit
768b98ae77
@ -8,10 +8,15 @@ from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import QswUpdateCoordinator
|
||||
from .const import DOMAIN, QSW_COORD_DATA, QSW_COORD_FW
|
||||
from .coordinator import QswDataCoordinator, QswFirmwareCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR]
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.SENSOR,
|
||||
Platform.UPDATE,
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
@ -24,10 +29,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
qsw = QnapQswApi(aiohttp_client.async_get_clientsession(hass), options)
|
||||
|
||||
coordinator = QswUpdateCoordinator(hass, qsw)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
coord_data = QswDataCoordinator(hass, qsw)
|
||||
await coord_data.async_config_entry_first_refresh()
|
||||
|
||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
|
||||
coord_fw = QswFirmwareCoordinator(hass, qsw)
|
||||
await coord_fw.async_config_entry_first_refresh()
|
||||
|
||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
|
||||
QSW_COORD_DATA: coord_data,
|
||||
QSW_COORD_FW: coord_fw,
|
||||
}
|
||||
|
||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||
|
||||
|
@ -16,8 +16,8 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import ATTR_MESSAGE, DOMAIN
|
||||
from .coordinator import QswUpdateCoordinator
|
||||
from .const import ATTR_MESSAGE, DOMAIN, QSW_COORD_DATA
|
||||
from .coordinator import QswDataCoordinator
|
||||
from .entity import QswEntityDescription, QswSensorEntity
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Add QNAP QSW binary sensors from a config_entry."""
|
||||
coordinator: QswUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
|
||||
async_add_entities(
|
||||
QswBinarySensor(coordinator, description, entry)
|
||||
for description in BINARY_SENSOR_TYPES
|
||||
@ -66,7 +66,7 @@ class QswBinarySensor(QswSensorEntity, BinarySensorEntity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: QswUpdateCoordinator,
|
||||
coordinator: QswDataCoordinator,
|
||||
description: QswBinarySensorEntityDescription,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
|
@ -17,9 +17,9 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN, QSW_REBOOT
|
||||
from .coordinator import QswUpdateCoordinator
|
||||
from .entity import QswEntity
|
||||
from .const import DOMAIN, QSW_COORD_DATA, QSW_REBOOT
|
||||
from .coordinator import QswDataCoordinator
|
||||
from .entity import QswDataEntity
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -49,20 +49,20 @@ async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Add QNAP QSW buttons from a config_entry."""
|
||||
coordinator: QswUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
|
||||
async_add_entities(
|
||||
QswButton(coordinator, description, entry) for description in BUTTON_TYPES
|
||||
)
|
||||
|
||||
|
||||
class QswButton(QswEntity, ButtonEntity):
|
||||
class QswButton(QswDataEntity, ButtonEntity):
|
||||
"""Define a QNAP QSW button."""
|
||||
|
||||
entity_description: QswButtonDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: QswUpdateCoordinator,
|
||||
coordinator: QswDataCoordinator,
|
||||
description: QswButtonDescription,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
|
@ -10,5 +10,8 @@ MANUFACTURER: Final = "QNAP"
|
||||
|
||||
RPM: Final = "rpm"
|
||||
|
||||
QSW_COORD_DATA: Final = "coordinator-data"
|
||||
QSW_COORD_FW: Final = "coordinator-firmware"
|
||||
QSW_REBOOT = "reboot"
|
||||
QSW_TIMEOUT_SEC: Final = 25
|
||||
QSW_UPDATE: Final = "update"
|
||||
|
@ -5,7 +5,7 @@ from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from aioqsw.exceptions import QswError
|
||||
from aioqsw.exceptions import APIError, QswError
|
||||
from aioqsw.localapi import QnapQswApi
|
||||
import async_timeout
|
||||
|
||||
@ -14,12 +14,13 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
||||
|
||||
from .const import DOMAIN, QSW_TIMEOUT_SEC
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=60)
|
||||
DATA_SCAN_INTERVAL = timedelta(seconds=60)
|
||||
FW_SCAN_INTERVAL = timedelta(hours=12)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class QswUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
class QswDataCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Class to manage fetching data from the QNAP QSW device."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, qsw: QnapQswApi) -> None:
|
||||
@ -30,7 +31,7 @@ class QswUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=DOMAIN,
|
||||
update_interval=SCAN_INTERVAL,
|
||||
update_interval=DATA_SCAN_INTERVAL,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
@ -41,3 +42,29 @@ class QswUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
except QswError as error:
|
||||
raise UpdateFailed(error) from error
|
||||
return self.qsw.data()
|
||||
|
||||
|
||||
class QswFirmwareCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Class to manage fetching firmware data from the QNAP QSW device."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, qsw: QnapQswApi) -> None:
|
||||
"""Initialize."""
|
||||
self.qsw = qsw
|
||||
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=DOMAIN,
|
||||
update_interval=FW_SCAN_INTERVAL,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update firmware data via library."""
|
||||
async with async_timeout.timeout(QSW_TIMEOUT_SEC):
|
||||
try:
|
||||
await self.qsw.check_firmware()
|
||||
except APIError as error:
|
||||
_LOGGER.warning(error)
|
||||
except QswError as error:
|
||||
raise UpdateFailed(error) from error
|
||||
return self.qsw.data()
|
||||
|
@ -10,8 +10,8 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import QswUpdateCoordinator
|
||||
from .const import DOMAIN, QSW_COORD_DATA, QSW_COORD_FW
|
||||
from .coordinator import QswDataCoordinator, QswFirmwareCoordinator
|
||||
|
||||
TO_REDACT_CONFIG = [
|
||||
CONF_USERNAME,
|
||||
@ -29,9 +29,12 @@ async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
coordinator: QswUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
entry_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coord_data: QswDataCoordinator = entry_data[QSW_COORD_DATA]
|
||||
coord_fw: QswFirmwareCoordinator = entry_data[QSW_COORD_FW]
|
||||
|
||||
return {
|
||||
"config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT_CONFIG),
|
||||
"coord_data": async_redact_data(coordinator.data, TO_REDACT_DATA),
|
||||
"coord_data": async_redact_data(coord_data.data, TO_REDACT_DATA),
|
||||
"coord_fw": async_redact_data(coord_fw.data, TO_REDACT_DATA),
|
||||
}
|
||||
|
@ -20,15 +20,15 @@ from homeassistant.helpers.entity import DeviceInfo, EntityDescription
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import MANUFACTURER
|
||||
from .coordinator import QswUpdateCoordinator
|
||||
from .coordinator import QswDataCoordinator, QswFirmwareCoordinator
|
||||
|
||||
|
||||
class QswEntity(CoordinatorEntity[QswUpdateCoordinator]):
|
||||
class QswDataEntity(CoordinatorEntity[QswDataCoordinator]):
|
||||
"""Define an QNAP QSW entity."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: QswUpdateCoordinator,
|
||||
coordinator: QswDataCoordinator,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
@ -72,7 +72,7 @@ class QswEntityDescription(EntityDescription, QswEntityDescriptionMixin):
|
||||
attributes: dict[str, list[str]] | None = None
|
||||
|
||||
|
||||
class QswSensorEntity(QswEntity):
|
||||
class QswSensorEntity(QswDataEntity):
|
||||
"""Base class for QSW sensor entities."""
|
||||
|
||||
entity_description: QswEntityDescription
|
||||
@ -91,3 +91,38 @@ class QswSensorEntity(QswEntity):
|
||||
key: self.get_device_value(val[0], val[1])
|
||||
for key, val in self.entity_description.attributes.items()
|
||||
}
|
||||
|
||||
|
||||
class QswFirmwareEntity(CoordinatorEntity[QswFirmwareCoordinator]):
|
||||
"""Define a QNAP QSW firmware entity."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: QswFirmwareCoordinator,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
configuration_url=entry.data[CONF_URL],
|
||||
connections={
|
||||
(
|
||||
CONNECTION_NETWORK_MAC,
|
||||
self.get_device_value(QSD_SYSTEM_BOARD, QSD_MAC),
|
||||
)
|
||||
},
|
||||
manufacturer=MANUFACTURER,
|
||||
model=self.get_device_value(QSD_SYSTEM_BOARD, QSD_PRODUCT),
|
||||
name=self.get_device_value(QSD_SYSTEM_BOARD, QSD_PRODUCT),
|
||||
sw_version=self.get_device_value(QSD_FIRMWARE_INFO, QSD_FIRMWARE),
|
||||
)
|
||||
|
||||
def get_device_value(self, key: str, subkey: str) -> Any:
|
||||
"""Return device value by key."""
|
||||
value = None
|
||||
if key in self.coordinator.data:
|
||||
data = self.coordinator.data[key]
|
||||
if subkey in data:
|
||||
value = data[subkey]
|
||||
return value
|
||||
|
@ -26,8 +26,8 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import ATTR_MAX, DOMAIN, RPM
|
||||
from .coordinator import QswUpdateCoordinator
|
||||
from .const import ATTR_MAX, DOMAIN, QSW_COORD_DATA, RPM
|
||||
from .coordinator import QswDataCoordinator
|
||||
from .entity import QswEntityDescription, QswSensorEntity
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Add QNAP QSW sensors from a config_entry."""
|
||||
coordinator: QswUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
|
||||
async_add_entities(
|
||||
QswSensor(coordinator, description, entry)
|
||||
for description in SENSOR_TYPES
|
||||
@ -100,7 +100,7 @@ class QswSensor(QswSensorEntity, SensorEntity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: QswUpdateCoordinator,
|
||||
coordinator: QswDataCoordinator,
|
||||
description: QswSensorEntityDescription,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
|
89
homeassistant/components/qnap_qsw/update.py
Normal file
89
homeassistant/components/qnap_qsw/update.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""Support for the QNAP QSW update."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
from aioqsw.const import (
|
||||
QSD_DESCRIPTION,
|
||||
QSD_FIRMWARE_CHECK,
|
||||
QSD_FIRMWARE_INFO,
|
||||
QSD_PRODUCT,
|
||||
QSD_SYSTEM_BOARD,
|
||||
QSD_VERSION,
|
||||
)
|
||||
|
||||
from homeassistant.components.update import (
|
||||
UpdateDeviceClass,
|
||||
UpdateEntity,
|
||||
UpdateEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN, QSW_COORD_FW, QSW_UPDATE
|
||||
from .coordinator import QswFirmwareCoordinator
|
||||
from .entity import QswFirmwareEntity
|
||||
|
||||
UPDATE_TYPES: Final[tuple[UpdateEntityDescription, ...]] = (
|
||||
UpdateEntityDescription(
|
||||
device_class=UpdateDeviceClass.FIRMWARE,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
key=QSW_UPDATE,
|
||||
name="Firmware Update",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Add QNAP QSW updates from a config_entry."""
|
||||
coordinator: QswFirmwareCoordinator = hass.data[DOMAIN][entry.entry_id][
|
||||
QSW_COORD_FW
|
||||
]
|
||||
async_add_entities(
|
||||
QswUpdate(coordinator, description, entry) for description in UPDATE_TYPES
|
||||
)
|
||||
|
||||
|
||||
class QswUpdate(QswFirmwareEntity, UpdateEntity):
|
||||
"""Define a QNAP QSW update."""
|
||||
|
||||
entity_description: UpdateEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: QswFirmwareCoordinator,
|
||||
description: UpdateEntityDescription,
|
||||
entry: ConfigEntry,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator, entry)
|
||||
self._attr_name = (
|
||||
f"{self.get_device_value(QSD_SYSTEM_BOARD, QSD_PRODUCT)} {description.name}"
|
||||
)
|
||||
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
|
||||
self.entity_description = description
|
||||
|
||||
self._attr_installed_version = self.get_device_value(
|
||||
QSD_FIRMWARE_INFO, QSD_VERSION
|
||||
)
|
||||
self._async_update_attrs()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Update attributes when the coordinator updates."""
|
||||
self._async_update_attrs()
|
||||
super()._handle_coordinator_update()
|
||||
|
||||
@callback
|
||||
def _async_update_attrs(self) -> None:
|
||||
"""Update attributes."""
|
||||
self._attr_latest_version = self.get_device_value(
|
||||
QSD_FIRMWARE_CHECK, QSD_VERSION
|
||||
)
|
||||
self._attr_release_summary = self.get_device_value(
|
||||
QSD_FIRMWARE_CHECK, QSD_DESCRIPTION
|
||||
)
|
@ -2,10 +2,13 @@
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from aioqsw.exceptions import QswError
|
||||
from aioqsw.exceptions import APIError, QswError
|
||||
|
||||
from homeassistant.components.qnap_qsw.const import DOMAIN
|
||||
from homeassistant.components.qnap_qsw.coordinator import SCAN_INTERVAL
|
||||
from homeassistant.components.qnap_qsw.coordinator import (
|
||||
DATA_SCAN_INTERVAL,
|
||||
FW_SCAN_INTERVAL,
|
||||
)
|
||||
from homeassistant.const import STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util.dt import utcnow
|
||||
@ -14,6 +17,7 @@ from .util import (
|
||||
CONFIG,
|
||||
FIRMWARE_CONDITION_MOCK,
|
||||
FIRMWARE_INFO_MOCK,
|
||||
FIRMWARE_UPDATE_CHECK_MOCK,
|
||||
SYSTEM_BOARD_MOCK,
|
||||
SYSTEM_SENSOR_MOCK,
|
||||
SYSTEM_TIME_MOCK,
|
||||
@ -37,6 +41,9 @@ async def test_coordinator_client_connector_error(hass: HomeAssistant) -> None:
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_firmware_info",
|
||||
return_value=FIRMWARE_INFO_MOCK,
|
||||
) as mock_firmware_info, patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_firmware_update_check",
|
||||
return_value=FIRMWARE_UPDATE_CHECK_MOCK,
|
||||
) as mock_firmware_update_check, patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_system_board",
|
||||
return_value=SYSTEM_BOARD_MOCK,
|
||||
) as mock_system_board, patch(
|
||||
@ -57,14 +64,16 @@ async def test_coordinator_client_connector_error(hass: HomeAssistant) -> None:
|
||||
|
||||
mock_firmware_condition.assert_called_once()
|
||||
mock_firmware_info.assert_called_once()
|
||||
mock_firmware_update_check.assert_called_once()
|
||||
mock_system_board.assert_called_once()
|
||||
mock_system_sensor.assert_called_once()
|
||||
mock_system_time.assert_called_once()
|
||||
mock_users_verification.assert_not_called()
|
||||
mock_users_verification.assert_called_once()
|
||||
mock_users_login.assert_called_once()
|
||||
|
||||
mock_firmware_condition.reset_mock()
|
||||
mock_firmware_info.reset_mock()
|
||||
mock_firmware_update_check.reset_mock()
|
||||
mock_system_board.reset_mock()
|
||||
mock_system_sensor.reset_mock()
|
||||
mock_system_time.reset_mock()
|
||||
@ -72,12 +81,28 @@ async def test_coordinator_client_connector_error(hass: HomeAssistant) -> None:
|
||||
mock_users_login.reset_mock()
|
||||
|
||||
mock_system_sensor.side_effect = QswError
|
||||
async_fire_time_changed(hass, utcnow() + SCAN_INTERVAL)
|
||||
async_fire_time_changed(hass, utcnow() + DATA_SCAN_INTERVAL)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_system_sensor.assert_called_once()
|
||||
mock_users_verification.assert_called_once()
|
||||
mock_users_verification.assert_called()
|
||||
mock_users_login.assert_not_called()
|
||||
|
||||
state = hass.states.get("sensor.qsw_m408_4c_temperature")
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
mock_firmware_update_check.side_effect = APIError
|
||||
async_fire_time_changed(hass, utcnow() + FW_SCAN_INTERVAL)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_firmware_update_check.assert_called_once()
|
||||
mock_firmware_update_check.reset_mock()
|
||||
|
||||
mock_firmware_update_check.side_effect = QswError
|
||||
async_fire_time_changed(hass, utcnow() + FW_SCAN_INTERVAL)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_firmware_update_check.assert_called_once()
|
||||
|
||||
update = hass.states.get("update.qsw_m408_4c_firmware_update")
|
||||
assert update.state == STATE_UNAVAILABLE
|
||||
|
@ -20,6 +20,9 @@ async def test_unload_entry(hass: HomeAssistant) -> None:
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.check_firmware",
|
||||
return_value=None,
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.validate",
|
||||
return_value=None,
|
||||
), patch(
|
||||
|
26
tests/components/qnap_qsw/test_update.py
Normal file
26
tests/components/qnap_qsw/test_update.py
Normal file
@ -0,0 +1,26 @@
|
||||
"""The sensor tests for the QNAP QSW platform."""
|
||||
|
||||
from aioqsw.const import API_RESULT, API_VERSION
|
||||
|
||||
from homeassistant.const import STATE_OFF
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .util import FIRMWARE_INFO_MOCK, FIRMWARE_UPDATE_CHECK_MOCK, async_init_integration
|
||||
|
||||
|
||||
async def test_qnap_qsw_update(hass: HomeAssistant) -> None:
|
||||
"""Test creation of update entities."""
|
||||
|
||||
await async_init_integration(hass)
|
||||
|
||||
update = hass.states.get("update.qsw_m408_4c_firmware_update")
|
||||
assert update is not None
|
||||
assert update.state == STATE_OFF
|
||||
assert (
|
||||
update.attributes.get("installed_version")
|
||||
== FIRMWARE_INFO_MOCK[API_RESULT][API_VERSION]
|
||||
)
|
||||
assert (
|
||||
update.attributes.get("latest_version")
|
||||
== FIRMWARE_UPDATE_CHECK_MOCK[API_RESULT][API_VERSION]
|
||||
)
|
@ -12,6 +12,8 @@ from aioqsw.const import (
|
||||
API_COMMIT_CPSS,
|
||||
API_COMMIT_ISS,
|
||||
API_DATE,
|
||||
API_DESCRIPTION,
|
||||
API_DOWNLOAD_URL,
|
||||
API_ERROR_CODE,
|
||||
API_ERROR_MESSAGE,
|
||||
API_FAN1_SPEED,
|
||||
@ -20,6 +22,7 @@ from aioqsw.const import (
|
||||
API_MAX_SWITCH_TEMP,
|
||||
API_MESSAGE,
|
||||
API_MODEL,
|
||||
API_NEWER,
|
||||
API_NUMBER,
|
||||
API_PORT_NUM,
|
||||
API_PRODUCT,
|
||||
@ -90,6 +93,24 @@ FIRMWARE_INFO_MOCK = {
|
||||
},
|
||||
}
|
||||
|
||||
FIRMWARE_UPDATE_CHECK_MOCK = {
|
||||
API_ERROR_CODE: 200,
|
||||
API_ERROR_MESSAGE: "OK",
|
||||
API_RESULT: {
|
||||
API_VERSION: "1.2.0",
|
||||
API_NUMBER: "29649",
|
||||
API_BUILD_NUMBER: "20220128",
|
||||
API_DATE: "Fri, 28 Jan 2022 01:17:39 +0800",
|
||||
API_DESCRIPTION: "",
|
||||
API_DOWNLOAD_URL: [
|
||||
"https://download.qnap.com/Storage/Networking/QSW408FW/QSW-M408AC3-FW.v1.2.0_S20220128_29649.img",
|
||||
"https://eu1.qnap.com/Storage/Networking/QSW408FW/QSW-M408AC3-FW.v1.2.0_S20220128_29649.img",
|
||||
"https://us1.qnap.com/Storage/Networking/QSW408FW/QSW-M408AC3-FW.v1.2.0_S20220128_29649.img",
|
||||
],
|
||||
API_NEWER: False,
|
||||
},
|
||||
}
|
||||
|
||||
SYSTEM_COMMAND_MOCK = {
|
||||
API_ERROR_CODE: 200,
|
||||
API_ERROR_MESSAGE: "OK",
|
||||
@ -146,6 +167,9 @@ async def async_init_integration(
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_firmware_info",
|
||||
return_value=FIRMWARE_INFO_MOCK,
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_firmware_update_check",
|
||||
return_value=FIRMWARE_UPDATE_CHECK_MOCK,
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_system_board",
|
||||
return_value=SYSTEM_BOARD_MOCK,
|
||||
@ -155,6 +179,9 @@ async def async_init_integration(
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_system_time",
|
||||
return_value=SYSTEM_TIME_MOCK,
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.get_users_verification",
|
||||
return_value=USERS_VERIFICATION_MOCK,
|
||||
), patch(
|
||||
"homeassistant.components.qnap_qsw.QnapQswApi.post_users_login",
|
||||
return_value=USERS_LOGIN_MOCK,
|
||||
|
Loading…
x
Reference in New Issue
Block a user