From 3549aaf69c319484df8be6a4054f9780ad1cb7e2 Mon Sep 17 00:00:00 2001 From: wittypluck Date: Fri, 28 Jun 2024 22:47:20 +0200 Subject: [PATCH] Reject small uptime updates for Unifi clients (#120398) Extend logic to reject small uptime updates to Unifi clients + add unit tests --- homeassistant/components/unifi/sensor.py | 5 ++-- tests/components/unifi/test_sensor.py | 36 ++++++++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/unifi/sensor.py b/homeassistant/components/unifi/sensor.py index 028d70d8880..071230a9652 100644 --- a/homeassistant/components/unifi/sensor.py +++ b/homeassistant/components/unifi/sensor.py @@ -139,7 +139,7 @@ def async_device_uptime_value_fn(hub: UnifiHub, device: Device) -> datetime | No @callback -def async_device_uptime_value_changed_fn( +def async_uptime_value_changed_fn( old: StateType | date | datetime | Decimal, new: datetime | float | str | None ) -> bool: """Reject the new uptime value if it's too similar to the old one. Avoids unwanted fluctuation.""" @@ -310,6 +310,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( supported_fn=lambda hub, _: hub.config.option_allow_uptime_sensors, unique_id_fn=lambda hub, obj_id: f"uptime-{obj_id}", value_fn=async_client_uptime_value_fn, + value_changed_fn=async_uptime_value_changed_fn, ), UnifiSensorEntityDescription[Wlans, Wlan]( key="WLAN clients", @@ -396,7 +397,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( object_fn=lambda api, obj_id: api.devices[obj_id], unique_id_fn=lambda hub, obj_id: f"device_uptime-{obj_id}", value_fn=async_device_uptime_value_fn, - value_changed_fn=async_device_uptime_value_changed_fn, + value_changed_fn=async_uptime_value_changed_fn, ), UnifiSensorEntityDescription[Devices, Device]( key="Device temperature", diff --git a/tests/components/unifi/test_sensor.py b/tests/components/unifi/test_sensor.py index 960a5d3e529..48e524aef76 100644 --- a/tests/components/unifi/test_sensor.py +++ b/tests/components/unifi/test_sensor.py @@ -484,12 +484,12 @@ async def test_bandwidth_sensors( ], ) @pytest.mark.parametrize( - ("initial_uptime", "event_uptime", "new_uptime"), + ("initial_uptime", "event_uptime", "small_variation_uptime", "new_uptime"), [ # Uptime listed in epoch time should never change - (1609462800, 1609462800, 1612141200), + (1609462800, 1609462800, 1609462800, 1612141200), # Uptime counted in seconds increases with every event - (60, 64, 60), + (60, 240, 480, 60), ], ) @pytest.mark.usefixtures("entity_registry_enabled_by_default") @@ -503,6 +503,7 @@ async def test_uptime_sensors( client_payload: list[dict[str, Any]], initial_uptime, event_uptime, + small_variation_uptime, new_uptime, ) -> None: """Verify that uptime sensors are working as expected.""" @@ -519,15 +520,24 @@ async def test_uptime_sensors( ) # Verify normal new event doesn't change uptime - # 4 seconds has passed + # 4 minutes have passed uptime_client["uptime"] = event_uptime - now = datetime(2021, 1, 1, 1, 1, 4, tzinfo=dt_util.UTC) + now = datetime(2021, 1, 1, 1, 4, 0, tzinfo=dt_util.UTC) with patch("homeassistant.util.dt.now", return_value=now): mock_websocket_message(message=MessageKey.CLIENT, data=uptime_client) await hass.async_block_till_done() assert hass.states.get("sensor.client1_uptime").state == "2021-01-01T01:00:00+00:00" + # Verify small variation of uptime (<120 seconds) is ignored + # 15 seconds variation after 8 minutes + uptime_client["uptime"] = small_variation_uptime + now = datetime(2021, 1, 1, 1, 8, 15, tzinfo=dt_util.UTC) + with patch("homeassistant.util.dt.now", return_value=now): + mock_websocket_message(message=MessageKey.CLIENT, data=uptime_client) + + assert hass.states.get("sensor.client1_uptime").state == "2021-01-01T01:00:00+00:00" + # Verify new event change uptime # 1 month has passed uptime_client["uptime"] = new_uptime @@ -911,10 +921,20 @@ async def test_device_uptime( ) # Verify normal new event doesn't change uptime - # 4 seconds has passed + # 4 minutes have passed device = device_payload[0] - device["uptime"] = 64 - now = datetime(2021, 1, 1, 1, 1, 4, tzinfo=dt_util.UTC) + device["uptime"] = 240 + now = datetime(2021, 1, 1, 1, 4, 0, tzinfo=dt_util.UTC) + with patch("homeassistant.util.dt.now", return_value=now): + mock_websocket_message(message=MessageKey.DEVICE, data=device) + + assert hass.states.get("sensor.device_uptime").state == "2021-01-01T01:00:00+00:00" + + # Verify small variation of uptime (<120 seconds) is ignored + # 15 seconds variation after 8 minutes + device = device_payload[0] + device["uptime"] = 480 + now = datetime(2021, 1, 1, 1, 8, 15, tzinfo=dt_util.UTC) with patch("homeassistant.util.dt.now", return_value=now): mock_websocket_message(message=MessageKey.DEVICE, data=device)