mirror of
https://github.com/home-assistant/core.git
synced 2026-06-11 11:41:42 +02:00
Fix Reolink camera updates persisting in UI (#161149)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -143,8 +143,13 @@ async def async_setup_entry(
|
||||
min_timeout = host.api.timeout * (RETRY_ATTEMPTS + 2)
|
||||
update_timeout = max(min_timeout, min_timeout * host.api.num_cameras / 10)
|
||||
|
||||
# Track firmware versions to detect external updates (e.g., via Reolink app)
|
||||
last_known_firmware: dict[int | None, str | None] = {}
|
||||
|
||||
async def async_device_config_update() -> None:
|
||||
"""Update the host state cache and renew the ONVIF-subscription."""
|
||||
nonlocal last_known_firmware
|
||||
|
||||
async with asyncio.timeout(update_timeout):
|
||||
try:
|
||||
await host.update_states()
|
||||
@@ -162,6 +167,23 @@ async def async_setup_entry(
|
||||
|
||||
host.credential_errors = 0
|
||||
|
||||
# Check for firmware version changes (external update detection)
|
||||
firmware_changed = False
|
||||
for ch in (*host.api.channels, None):
|
||||
new_version = host.api.camera_sw_version(ch)
|
||||
old_version = last_known_firmware.get(ch)
|
||||
if (
|
||||
old_version is not None
|
||||
and new_version is not None
|
||||
and new_version != old_version
|
||||
):
|
||||
firmware_changed = True
|
||||
last_known_firmware[ch] = new_version
|
||||
|
||||
# Notify firmware coordinator if firmware changed externally
|
||||
if firmware_changed and firmware_coordinator is not None:
|
||||
firmware_coordinator.async_set_updated_data(None)
|
||||
|
||||
async with asyncio.timeout(min_timeout):
|
||||
await host.renew()
|
||||
|
||||
|
||||
@@ -206,3 +206,39 @@ async def test_update_firm_keeps_available(
|
||||
|
||||
# still available
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
|
||||
|
||||
@pytest.mark.parametrize("entity_name", [TEST_NVR_NAME, TEST_CAM_NAME])
|
||||
async def test_external_firmware_update_detected(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
reolink_host: MagicMock,
|
||||
entity_name: str,
|
||||
) -> None:
|
||||
"""Test that external firmware updates (via Reolink app) are detected."""
|
||||
reolink_host.camera_sw_version.return_value = "v1.1.0.0.0.0000"
|
||||
new_firmware = NewSoftwareVersion(
|
||||
version_string="v3.3.0.226_23031644",
|
||||
download_url=TEST_DOWNLOAD_URL,
|
||||
release_notes=TEST_RELEASE_NOTES,
|
||||
)
|
||||
reolink_host.firmware_update_available.return_value = new_firmware
|
||||
|
||||
with patch("homeassistant.components.reolink.PLATFORMS", [Platform.UPDATE]):
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
entity_id = f"{Platform.UPDATE}.{entity_name}_firmware"
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
|
||||
# Simulate external firmware update via Reolink app
|
||||
reolink_host.camera_sw_version.return_value = "v3.3.0.226_23031644"
|
||||
reolink_host.firmware_update_available.return_value = False
|
||||
|
||||
# Trigger device coordinator update (simulates regular polling)
|
||||
await config_entry.runtime_data.device_coordinator.async_refresh()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# The firmware coordinator should have been refreshed, and update should be cleared
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
Reference in New Issue
Block a user