Reject small uptime updates for Unifi clients (#120398)

Extend logic to reject small uptime updates to Unifi clients + add unit tests
This commit is contained in:
wittypluck 2024-06-28 22:47:20 +02:00 committed by GitHub
parent a3394675f3
commit 3549aaf69c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 10 deletions

View File

@ -139,7 +139,7 @@ def async_device_uptime_value_fn(hub: UnifiHub, device: Device) -> datetime | No
@callback @callback
def async_device_uptime_value_changed_fn( def async_uptime_value_changed_fn(
old: StateType | date | datetime | Decimal, new: datetime | float | str | None old: StateType | date | datetime | Decimal, new: datetime | float | str | None
) -> bool: ) -> bool:
"""Reject the new uptime value if it's too similar to the old one. Avoids unwanted fluctuation.""" """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, supported_fn=lambda hub, _: hub.config.option_allow_uptime_sensors,
unique_id_fn=lambda hub, obj_id: f"uptime-{obj_id}", unique_id_fn=lambda hub, obj_id: f"uptime-{obj_id}",
value_fn=async_client_uptime_value_fn, value_fn=async_client_uptime_value_fn,
value_changed_fn=async_uptime_value_changed_fn,
), ),
UnifiSensorEntityDescription[Wlans, Wlan]( UnifiSensorEntityDescription[Wlans, Wlan](
key="WLAN clients", key="WLAN clients",
@ -396,7 +397,7 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
object_fn=lambda api, obj_id: api.devices[obj_id], object_fn=lambda api, obj_id: api.devices[obj_id],
unique_id_fn=lambda hub, obj_id: f"device_uptime-{obj_id}", unique_id_fn=lambda hub, obj_id: f"device_uptime-{obj_id}",
value_fn=async_device_uptime_value_fn, 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]( UnifiSensorEntityDescription[Devices, Device](
key="Device temperature", key="Device temperature",

View File

@ -484,12 +484,12 @@ async def test_bandwidth_sensors(
], ],
) )
@pytest.mark.parametrize( @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 # Uptime listed in epoch time should never change
(1609462800, 1609462800, 1612141200), (1609462800, 1609462800, 1609462800, 1612141200),
# Uptime counted in seconds increases with every event # Uptime counted in seconds increases with every event
(60, 64, 60), (60, 240, 480, 60),
], ],
) )
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.usefixtures("entity_registry_enabled_by_default")
@ -503,6 +503,7 @@ async def test_uptime_sensors(
client_payload: list[dict[str, Any]], client_payload: list[dict[str, Any]],
initial_uptime, initial_uptime,
event_uptime, event_uptime,
small_variation_uptime,
new_uptime, new_uptime,
) -> None: ) -> None:
"""Verify that uptime sensors are working as expected.""" """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 # Verify normal new event doesn't change uptime
# 4 seconds has passed # 4 minutes have passed
uptime_client["uptime"] = event_uptime 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): with patch("homeassistant.util.dt.now", return_value=now):
mock_websocket_message(message=MessageKey.CLIENT, data=uptime_client) mock_websocket_message(message=MessageKey.CLIENT, data=uptime_client)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get("sensor.client1_uptime").state == "2021-01-01T01:00:00+00:00" 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 # Verify new event change uptime
# 1 month has passed # 1 month has passed
uptime_client["uptime"] = new_uptime uptime_client["uptime"] = new_uptime
@ -911,10 +921,20 @@ async def test_device_uptime(
) )
# Verify normal new event doesn't change uptime # Verify normal new event doesn't change uptime
# 4 seconds has passed # 4 minutes have passed
device = device_payload[0] device = device_payload[0]
device["uptime"] = 64 device["uptime"] = 240
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.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): with patch("homeassistant.util.dt.now", return_value=now):
mock_websocket_message(message=MessageKey.DEVICE, data=device) mock_websocket_message(message=MessageKey.DEVICE, data=device)