Add sensor for CPU and memory utilization for unifi device (#114986)
Add system stats to unifi device sensors
This commit is contained in:
parent
f9a7e6bb9f
commit
f23e48f373
2 changed files with 86 additions and 3 deletions
|
@ -10,6 +10,7 @@ from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from aiounifi.interfaces.api_handlers import ItemEvent
|
from aiounifi.interfaces.api_handlers import ItemEvent
|
||||||
from aiounifi.interfaces.clients import Clients
|
from aiounifi.interfaces.clients import Clients
|
||||||
|
@ -32,7 +33,7 @@ from homeassistant.components.sensor import (
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
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.core import Event as core_Event, HomeAssistant, callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
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
|
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
|
@callback
|
||||||
def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
|
def async_client_is_connected_fn(hub: UnifiHub, obj_id: str) -> bool:
|
||||||
"""Check if client was last seen recently."""
|
"""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}",
|
unique_id_fn=lambda hub, obj_id: f"password-{obj_id}",
|
||||||
value_fn=lambda hub, obj: obj.x_passphrase,
|
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],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -835,8 +835,8 @@ async def test_outlet_power_readings(
|
||||||
"""Test the outlet power reporting on PDU devices."""
|
"""Test the outlet power reporting on PDU devices."""
|
||||||
await setup_unifi_integration(hass, aioclient_mock, devices_response=[PDU_DEVICE_1])
|
await setup_unifi_integration(hass, aioclient_mock, devices_response=[PDU_DEVICE_1])
|
||||||
|
|
||||||
assert len(hass.states.async_all()) == 11
|
assert len(hass.states.async_all()) == 13
|
||||||
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 5
|
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 7
|
||||||
|
|
||||||
ent_reg_entry = entity_registry.async_get(f"sensor.{entity_id}")
|
ent_reg_entry = entity_registry.async_get(f"sensor.{entity_id}")
|
||||||
assert ent_reg_entry.unique_id == expected_unique_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)
|
mock_unifi_websocket(message=MessageKey.WLAN_CONF_UPDATED, data=wlan_1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(sensor_password).state == password
|
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"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue