Fix update platform for Shelly gen1 devices (#124798)
This commit is contained in:
parent
1fcfe9e135
commit
99a65d3098
3 changed files with 92 additions and 28 deletions
|
@ -9,6 +9,7 @@ from typing import Any, Final, cast
|
|||
|
||||
from aioshelly.const import RPC_GENERATIONS
|
||||
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError, RpcCallError
|
||||
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
|
||||
|
||||
from homeassistant.components.update import (
|
||||
ATTR_INSTALLED_VERSION,
|
||||
|
@ -203,6 +204,22 @@ class RestUpdateEntity(ShellyRestAttributeEntity, UpdateEntity):
|
|||
else:
|
||||
LOGGER.debug("Result of OTA update call: %s", result)
|
||||
|
||||
def version_is_newer(self, latest_version: str, installed_version: str) -> bool:
|
||||
"""Return True if available version is newer then installed version.
|
||||
|
||||
Default strategy generate an exception with Shelly firmware format
|
||||
thus making the entity state always true.
|
||||
"""
|
||||
return AwesomeVersion(
|
||||
latest_version,
|
||||
find_first_match=True,
|
||||
ensure_strategy=[AwesomeVersionStrategy.SEMVER],
|
||||
) > AwesomeVersion(
|
||||
installed_version,
|
||||
find_first_match=True,
|
||||
ensure_strategy=[AwesomeVersionStrategy.SEMVER],
|
||||
)
|
||||
|
||||
|
||||
class RpcUpdateEntity(ShellyRpcAttributeEntity, UpdateEntity):
|
||||
"""Represent a RPC update entity."""
|
||||
|
|
|
@ -226,9 +226,9 @@ MOCK_STATUS_COAP = {
|
|||
"update": {
|
||||
"status": "pending",
|
||||
"has_update": True,
|
||||
"beta_version": "some_beta_version",
|
||||
"new_version": "some_new_version",
|
||||
"old_version": "some_old_version",
|
||||
"beta_version": "20231107-162609/v1.14.1-rc1-g0617c15",
|
||||
"new_version": "20230913-111730/v1.14.0-gcb84623",
|
||||
"old_version": "20230913-111730/v1.14.0-gcb84623",
|
||||
},
|
||||
"uptime": 5 * REST_SENSORS_UPDATE_INTERVAL,
|
||||
"wifi_sta": {"rssi": -64},
|
||||
|
|
|
@ -54,15 +54,15 @@ async def test_block_update(
|
|||
) -> None:
|
||||
"""Test block device update entity."""
|
||||
entity_id = "update.test_name_firmware_update"
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1.0.0")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2.0.0")
|
||||
monkeypatch.setitem(mock_block_device.status, "cloud", {"connected": False})
|
||||
await init_integration(hass, 1)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is False
|
||||
supported_feat = state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
assert supported_feat == UpdateEntityFeature.INSTALL | UpdateEntityFeature.PROGRESS
|
||||
|
@ -77,18 +77,18 @@ async def test_block_update(
|
|||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is True
|
||||
assert state.attributes[ATTR_RELEASE_URL] == GEN1_RELEASE_URL
|
||||
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "2")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "2.0.0")
|
||||
await mock_rest_update(hass, freezer)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "2"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "2.0.0"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is False
|
||||
|
||||
entry = entity_registry.async_get(entity_id)
|
||||
|
@ -106,25 +106,27 @@ async def test_block_beta_update(
|
|||
) -> None:
|
||||
"""Test block device beta update entity."""
|
||||
entity_id = "update.test_name_beta_firmware_update"
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1.0.0")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2.0.0")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "beta_version", "")
|
||||
monkeypatch.setitem(mock_block_device.status, "cloud", {"connected": False})
|
||||
await init_integration(hass, 1)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "1"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "1.0.0"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is False
|
||||
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "beta_version", "2b")
|
||||
monkeypatch.setitem(
|
||||
mock_block_device.status["update"], "beta_version", "2.0.0-beta"
|
||||
)
|
||||
await mock_rest_update(hass, freezer)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2b"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0-beta"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is False
|
||||
assert state.attributes[ATTR_RELEASE_URL] is None
|
||||
|
||||
|
@ -138,17 +140,17 @@ async def test_block_beta_update(
|
|||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2b"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "1.0.0"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0-beta"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is True
|
||||
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "2b")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "2.0.0-beta")
|
||||
await mock_rest_update(hass, freezer)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "2b"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2b"
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == "2.0.0-beta"
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == "2.0.0-beta"
|
||||
assert state.attributes[ATTR_IN_PROGRESS] is False
|
||||
|
||||
entry = entity_registry.async_get(entity_id)
|
||||
|
@ -164,8 +166,8 @@ async def test_block_update_connection_error(
|
|||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test block device update connection error."""
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1.0.0")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2.0.0")
|
||||
monkeypatch.setattr(
|
||||
mock_block_device,
|
||||
"trigger_ota_update",
|
||||
|
@ -190,8 +192,8 @@ async def test_block_update_auth_error(
|
|||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Test block device update authentication error."""
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", "1.0.0")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "2.0.0")
|
||||
monkeypatch.setattr(
|
||||
mock_block_device,
|
||||
"trigger_ota_update",
|
||||
|
@ -222,6 +224,51 @@ async def test_block_update_auth_error(
|
|||
assert flow["context"].get("entry_id") == entry.entry_id
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_block_version_compare(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mock_block_device: Mock,
|
||||
entity_registry: EntityRegistry,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Test block device custom firmware version comparison."""
|
||||
|
||||
STABLE = "20230913-111730/v1.14.0-gcb84623"
|
||||
BETA = "20231107-162609/v1.14.1-rc1-g0617c15"
|
||||
|
||||
entity_id_beta = "update.test_name_beta_firmware_update"
|
||||
entity_id_latest = "update.test_name_firmware_update"
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", STABLE)
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", "")
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "beta_version", BETA)
|
||||
monkeypatch.setitem(mock_block_device.status, "cloud", {"connected": False})
|
||||
await init_integration(hass, 1)
|
||||
|
||||
state = hass.states.get(entity_id_latest)
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == STABLE
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == STABLE
|
||||
state = hass.states.get(entity_id_beta)
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == STABLE
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == BETA
|
||||
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "old_version", BETA)
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "new_version", STABLE)
|
||||
monkeypatch.setitem(mock_block_device.status["update"], "beta_version", BETA)
|
||||
await mock_rest_update(hass, freezer)
|
||||
|
||||
state = hass.states.get(entity_id_latest)
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == BETA
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == STABLE
|
||||
state = hass.states.get(entity_id_beta)
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes[ATTR_INSTALLED_VERSION] == BETA
|
||||
assert state.attributes[ATTR_LATEST_VERSION] == BETA
|
||||
|
||||
|
||||
async def test_rpc_update(
|
||||
hass: HomeAssistant,
|
||||
mock_rpc_device: Mock,
|
||||
|
|
Loading…
Add table
Reference in a new issue