Add sensor for CPU and memory utilization for unifi device (#114986)

Add system stats to unifi device sensors
This commit is contained in:
Kim de Vos 2024-04-08 19:29:54 +02:00 committed by GitHub
parent f9a7e6bb9f
commit f23e48f373
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 86 additions and 3 deletions

View file

@ -10,6 +10,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from datetime import date, datetime, timedelta
from decimal import Decimal
from functools import partial
from aiounifi.interfaces.api_handlers import ItemEvent
from aiounifi.interfaces.clients import Clients
@ -32,7 +33,7 @@ from homeassistant.components.sensor import (
UnitOfTemperature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory, UnitOfDataRate, UnitOfPower
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfDataRate, UnitOfPower
from homeassistant.core import Event as core_Event, HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -140,6 +141,16 @@ def async_device_outlet_supported_fn(hub: UnifiHub, obj_id: str) -> bool:
return hub.api.devices[obj_id].outlet_ac_power_budget is not None
def device_system_stats_supported_fn(
stat_index: int, hub: UnifiHub, obj_id: str
) -> bool:
"""Determine if a device supports reading item at index in system stats."""
return (
"system-stats" in hub.api.devices[obj_id].raw
and hub.api.devices[obj_id].system_stats[stat_index] != ""
)
@callback
def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
"""Check if client was last seen recently."""
@ -352,6 +363,34 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = (
unique_id_fn=lambda hub, obj_id: f"password-{obj_id}",
value_fn=lambda hub, obj: obj.x_passphrase,
),
UnifiSensorEntityDescription[Devices, Device](
key="Device CPU utilization",
entity_category=EntityCategory.DIAGNOSTIC,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
name_fn=lambda device: "CPU utilization",
object_fn=lambda api, obj_id: api.devices[obj_id],
supported_fn=partial(device_system_stats_supported_fn, 0),
unique_id_fn=lambda hub, obj_id: f"cpu_utilization-{obj_id}",
value_fn=lambda hub, device: device.system_stats[0],
),
UnifiSensorEntityDescription[Devices, Device](
key="Device memory utilization",
entity_category=EntityCategory.DIAGNOSTIC,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
api_handler_fn=lambda api: api.devices,
available_fn=async_device_available_fn,
device_info_fn=async_device_device_info_fn,
name_fn=lambda device: "Memory utilization",
object_fn=lambda api, obj_id: api.devices[obj_id],
supported_fn=partial(device_system_stats_supported_fn, 1),
unique_id_fn=lambda hub, obj_id: f"memory_utilization-{obj_id}",
value_fn=lambda hub, device: device.system_stats[1],
),
)

View file

@ -835,8 +835,8 @@ async def test_outlet_power_readings(
"""Test the outlet power reporting on PDU devices."""
await setup_unifi_integration(hass, aioclient_mock, devices_response=[PDU_DEVICE_1])
assert len(hass.states.async_all()) == 11
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 5
assert len(hass.states.async_all()) == 13
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 7
ent_reg_entry = entity_registry.async_get(f"sensor.{entity_id}")
assert ent_reg_entry.unique_id == expected_unique_id
@ -1069,3 +1069,47 @@ async def test_wlan_password(
mock_unifi_websocket(message=MessageKey.WLAN_CONF_UPDATED, data=wlan_1)
await hass.async_block_till_done()
assert hass.states.get(sensor_password).state == password
async def test_device_system_stats(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
aioclient_mock: AiohttpClientMocker,
mock_unifi_websocket,
) -> None:
"""Verify that device stats sensors are working as expected."""
device = {
"device_id": "mock-id",
"mac": "00:00:00:00:01:01",
"model": "US16P150",
"name": "Device",
"state": 1,
"version": "4.0.42.10433",
"system-stats": {"cpu": 5.8, "mem": 31.1, "uptime": 7316},
}
await setup_unifi_integration(hass, aioclient_mock, devices_response=[device])
assert len(hass.states.async_all()) == 8
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 4
assert hass.states.get("sensor.device_cpu_utilization").state == "5.8"
assert hass.states.get("sensor.device_memory_utilization").state == "31.1"
assert (
entity_registry.async_get("sensor.device_cpu_utilization").entity_category
is EntityCategory.DIAGNOSTIC
)
assert (
entity_registry.async_get("sensor.device_memory_utilization").entity_category
is EntityCategory.DIAGNOSTIC
)
# Verify new event change system-stats
device["system-stats"] = {"cpu": 7.7, "mem": 33.3, "uptime": 7316}
mock_unifi_websocket(message=MessageKey.DEVICE, data=device)
assert hass.states.get("sensor.device_cpu_utilization").state == "7.7"
assert hass.states.get("sensor.device_memory_utilization").state == "33.3"