diff --git a/homeassistant/components/devolo_home_network/__init__.py b/homeassistant/components/devolo_home_network/__init__.py index 94e848fe8af..0fee65d57b6 100644 --- a/homeassistant/components/devolo_home_network/__init__.py +++ b/homeassistant/components/devolo_home_network/__init__.py @@ -28,6 +28,7 @@ from homeassistant.const import ( ) from homeassistant.core import Event, HomeAssistant, callback from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady +from homeassistant.helpers import device_registry as dr from homeassistant.helpers.httpx_client import get_async_client from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -54,6 +55,7 @@ async def async_setup_entry( # noqa: C901 hass.data.setdefault(DOMAIN, {}) zeroconf_instance = await zeroconf.async_get_async_instance(hass) async_client = get_async_client(hass) + device_registry = dr.async_get(hass) try: device = Device( @@ -73,6 +75,7 @@ async def async_setup_entry( # noqa: C901 async def async_update_firmware_available() -> UpdateFirmwareCheck: """Fetch data from API endpoint.""" assert device.device + update_sw_version(device_registry, device) try: return await device.device.async_check_firmware_available() except DeviceUnavailable as err: @@ -81,6 +84,7 @@ async def async_setup_entry( # noqa: C901 async def async_update_connected_plc_devices() -> LogicalNetwork: """Fetch data from API endpoint.""" assert device.plcnet + update_sw_version(device_registry, device) try: return await device.plcnet.async_get_network_overview() except DeviceUnavailable as err: @@ -89,6 +93,7 @@ async def async_setup_entry( # noqa: C901 async def async_update_guest_wifi_status() -> WifiGuestAccessGet: """Fetch data from API endpoint.""" assert device.device + update_sw_version(device_registry, device) try: return await device.device.async_get_wifi_guest_access() except DeviceUnavailable as err: @@ -99,6 +104,7 @@ async def async_setup_entry( # noqa: C901 async def async_update_led_status() -> bool: """Fetch data from API endpoint.""" assert device.device + update_sw_version(device_registry, device) try: return await device.device.async_get_led_setting() except DeviceUnavailable as err: @@ -107,6 +113,7 @@ async def async_setup_entry( # noqa: C901 async def async_update_wifi_connected_station() -> list[ConnectedStationInfo]: """Fetch data from API endpoint.""" assert device.device + update_sw_version(device_registry, device) try: return await device.device.async_get_wifi_connected_station() except DeviceUnavailable as err: @@ -115,6 +122,7 @@ async def async_setup_entry( # noqa: C901 async def async_update_wifi_neighbor_access_points() -> list[NeighborAPInfo]: """Fetch data from API endpoint.""" assert device.device + update_sw_version(device_registry, device) try: return await device.device.async_get_wifi_neighbor_access_points() except DeviceUnavailable as err: @@ -211,3 +219,16 @@ def platforms(device: Device) -> set[Platform]: if device.device and "update" in device.device.features: supported_platforms.add(Platform.UPDATE) return supported_platforms + + +@callback +def update_sw_version(device_registry: dr.DeviceRegistry, device: Device) -> None: + """Update device registry with new firmware version.""" + if ( + device_entry := device_registry.async_get_device( + identifiers={(DOMAIN, str(device.serial_number))} + ) + ) and device_entry.sw_version != device.firmware_version: + device_registry.async_update_device( + device_id=device_entry.id, sw_version=device.firmware_version + ) diff --git a/tests/components/devolo_home_network/mock.py b/tests/components/devolo_home_network/mock.py index 80d1348cf0f..612df4da2e0 100644 --- a/tests/components/devolo_home_network/mock.py +++ b/tests/components/devolo_home_network/mock.py @@ -31,12 +31,18 @@ class MockDevice(Device): ) -> None: """Bring mock in a well defined state.""" super().__init__(ip, zeroconf_instance) + self._firmware_version = DISCOVERY_INFO.properties["FirmwareVersion"] self.reset() @property def firmware_version(self) -> str: """Mock firmware version currently installed.""" - return DISCOVERY_INFO.properties["FirmwareVersion"] + return self._firmware_version + + @firmware_version.setter + def firmware_version(self, version: str) -> None: + """Mock firmware version currently installed.""" + self._firmware_version = version async def async_connect( self, session_instance: httpx.AsyncClient | None = None @@ -49,6 +55,7 @@ class MockDevice(Device): def reset(self): """Reset mock to starting point.""" + self._firmware_version = DISCOVERY_INFO.properties["FirmwareVersion"] self.async_disconnect = AsyncMock() self.device = DeviceApi(IP, None, DISCOVERY_INFO) self.device.async_check_firmware_available = AsyncMock( diff --git a/tests/components/devolo_home_network/test_update.py b/tests/components/devolo_home_network/test_update.py index 2f8e3fcbc2e..d80e9133a0a 100644 --- a/tests/components/devolo_home_network/test_update.py +++ b/tests/components/devolo_home_network/test_update.py @@ -14,9 +14,10 @@ from homeassistant.config_entries import SOURCE_REAUTH from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers import entity_registry as er +from homeassistant.helpers import device_registry as dr, entity_registry as er from . import configure_integration +from .const import FIRMWARE_UPDATE_AVAILABLE from .mock import MockDevice from tests.common import async_fire_time_changed @@ -38,6 +39,7 @@ async def test_update_setup(hass: HomeAssistant) -> None: async def test_update_firmware( hass: HomeAssistant, mock_device: MockDevice, + device_registry: dr.DeviceRegistry, entity_registry: er.EntityRegistry, freezer: FrozenDateTimeFactory, snapshot: SnapshotAssertion, @@ -62,6 +64,9 @@ async def test_update_firmware( assert mock_device.device.async_start_firmware_update.call_count == 1 # Emulate state change + mock_device.firmware_version = FIRMWARE_UPDATE_AVAILABLE.new_firmware_version.split( + "_" + )[0] mock_device.device.async_check_firmware_available.return_value = ( UpdateFirmwareCheck(result=UPDATE_NOT_AVAILABLE) ) @@ -73,6 +78,12 @@ async def test_update_firmware( assert state is not None assert state.state == STATE_OFF + device_info = device_registry.async_get_device( + {(DOMAIN, mock_device.serial_number)} + ) + assert device_info is not None + assert device_info.sw_version == mock_device.firmware_version + await hass.config_entries.async_unload(entry.entry_id)