core/homeassistant/components/system_bridge/sensor.py

514 lines
19 KiB
Python

"""Support for System Bridge sensors."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Final, cast
from systembridge import Bridge
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
DATA_GIGABYTES,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
DEVICE_CLASS_VOLTAGE,
ELECTRIC_POTENTIAL_VOLT,
FREQUENCY_GIGAHERTZ,
FREQUENCY_HERTZ,
FREQUENCY_MEGAHERTZ,
PERCENTAGE,
POWER_WATT,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import StateType
from . import SystemBridgeDeviceEntity
from .const import DOMAIN
from .coordinator import SystemBridgeDataUpdateCoordinator
ATTR_AVAILABLE: Final = "available"
ATTR_FILESYSTEM: Final = "filesystem"
ATTR_MOUNT: Final = "mount"
ATTR_SIZE: Final = "size"
ATTR_TYPE: Final = "type"
ATTR_USED: Final = "used"
PIXELS: Final = "px"
@dataclass
class SystemBridgeSensorEntityDescription(SensorEntityDescription):
"""Class describing System Bridge sensor entities."""
value: Callable = round
BASE_SENSOR_TYPES: tuple[SystemBridgeSensorEntityDescription, ...] = (
SystemBridgeSensorEntityDescription(
key="bios_version",
name="BIOS Version",
entity_registry_enabled_default=False,
icon="mdi:chip",
value=lambda bridge: bridge.system.bios.version,
),
SystemBridgeSensorEntityDescription(
key="cpu_speed",
name="CPU Speed",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=FREQUENCY_GIGAHERTZ,
icon="mdi:speedometer",
value=lambda bridge: bridge.cpu.currentSpeed.avg,
),
SystemBridgeSensorEntityDescription(
key="cpu_temperature",
name="CPU Temperature",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=TEMP_CELSIUS,
value=lambda bridge: bridge.cpu.temperature.main,
),
SystemBridgeSensorEntityDescription(
key="cpu_voltage",
name="CPU Voltage",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
value=lambda bridge: bridge.cpu.cpu.voltage,
),
SystemBridgeSensorEntityDescription(
key="displays_connected",
name="Displays Connected",
state_class=STATE_CLASS_MEASUREMENT,
icon="mdi:monitor",
value=lambda bridge: len(bridge.display.displays),
),
SystemBridgeSensorEntityDescription(
key="kernel",
name="Kernel",
state_class=STATE_CLASS_MEASUREMENT,
icon="mdi:devices",
value=lambda bridge: bridge.os.kernel,
),
SystemBridgeSensorEntityDescription(
key="memory_free",
name="Memory Free",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=DATA_GIGABYTES,
icon="mdi:memory",
value=lambda bridge: round(bridge.memory.free / 1000 ** 3, 2),
),
SystemBridgeSensorEntityDescription(
key="memory_used_percentage",
name="Memory Used %",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:memory",
value=lambda bridge: round((bridge.memory.used / bridge.memory.total) * 100, 2),
),
SystemBridgeSensorEntityDescription(
key="memory_used",
name="Memory Used",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=DATA_GIGABYTES,
icon="mdi:memory",
value=lambda bridge: round(bridge.memory.used / 1000 ** 3, 2),
),
SystemBridgeSensorEntityDescription(
key="os",
name="Operating System",
state_class=STATE_CLASS_MEASUREMENT,
icon="mdi:devices",
value=lambda bridge: f"{bridge.os.distro} {bridge.os.release}",
),
SystemBridgeSensorEntityDescription(
key="processes_load",
name="Load",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge: round(bridge.processes.load.currentLoad, 2),
),
SystemBridgeSensorEntityDescription(
key="processes_load_idle",
name="Idle Load",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge: round(bridge.processes.load.currentLoadIdle, 2),
),
SystemBridgeSensorEntityDescription(
key="processes_load_system",
name="System Load",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge: round(bridge.processes.load.currentLoadSystem, 2),
),
SystemBridgeSensorEntityDescription(
key="processes_load_user",
name="User Load",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge: round(bridge.processes.load.currentLoadUser, 2),
),
SystemBridgeSensorEntityDescription(
key="version",
name="Version",
icon="mdi:counter",
value=lambda bridge: bridge.information.version,
),
SystemBridgeSensorEntityDescription(
key="version_latest",
name="Latest Version",
icon="mdi:counter",
value=lambda bridge: bridge.information.updates.version.new,
),
)
BATTERY_SENSOR_TYPES: tuple[SystemBridgeSensorEntityDescription, ...] = (
SystemBridgeSensorEntityDescription(
key="battery",
name="Battery",
device_class=DEVICE_CLASS_BATTERY,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
value=lambda bridge: bridge.battery.percent,
),
SystemBridgeSensorEntityDescription(
key="battery_time_remaining",
name="Battery Time Remaining",
device_class=DEVICE_CLASS_TIMESTAMP,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda bridge: str(
datetime.now() + timedelta(minutes=bridge.battery.timeRemaining)
),
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
) -> None:
"""Set up System Bridge sensor based on a config entry."""
coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
entities = []
for description in BASE_SENSOR_TYPES:
entities.append(SystemBridgeSensor(coordinator, description))
for key, _ in coordinator.data.filesystem.fsSize.items():
uid = key.replace(":", "")
entities.append(
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"filesystem_{uid}",
name=f"{key} Space Used",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:harddisk",
value=lambda bridge, i=key: round(
bridge.filesystem.fsSize[i]["use"], 2
),
),
)
)
if coordinator.data.battery.hasBattery:
for description in BATTERY_SENSOR_TYPES:
entities.append(SystemBridgeSensor(coordinator, description))
for index, _ in enumerate(coordinator.data.display.displays):
name = index + 1
entities = [
*entities,
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"display_{name}_resolution_x",
name=f"Display {name} Resolution X",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PIXELS,
icon="mdi:monitor",
value=lambda bridge, i=index: bridge.display.displays[
i
].resolutionX,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"display_{name}_resolution_y",
name=f"Display {name} Resolution Y",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PIXELS,
icon="mdi:monitor",
value=lambda bridge, i=index: bridge.display.displays[
i
].resolutionY,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"display_{name}_refresh_rate",
name=f"Display {name} Refresh Rate",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=FREQUENCY_HERTZ,
icon="mdi:monitor",
value=lambda bridge, i=index: bridge.display.displays[
i
].currentRefreshRate,
),
),
]
for index, _ in enumerate(coordinator.data.graphics.controllers):
if coordinator.data.graphics.controllers[index].name is not None:
# Remove vendor from name
name = (
coordinator.data.graphics.controllers[index]
.name.replace(coordinator.data.graphics.controllers[index].vendor, "")
.strip()
)
entities = [
*entities,
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_core_clock_speed",
name=f"{name} Clock Speed",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=FREQUENCY_MEGAHERTZ,
icon="mdi:speedometer",
value=lambda bridge, i=index: bridge.graphics.controllers[
i
].clockCore,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_memory_clock_speed",
name=f"{name} Memory Clock Speed",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=FREQUENCY_MEGAHERTZ,
icon="mdi:speedometer",
value=lambda bridge, i=index: bridge.graphics.controllers[
i
].clockMemory,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_memory_free",
name=f"{name} Memory Free",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=DATA_GIGABYTES,
icon="mdi:memory",
value=lambda bridge, i=index: round(
bridge.graphics.controllers[i].memoryFree / 10 ** 3, 2
),
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_memory_used_percentage",
name=f"{name} Memory Used %",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:memory",
value=lambda bridge, i=index: round(
(
bridge.graphics.controllers[i].memoryUsed
/ bridge.graphics.controllers[i].memoryTotal
)
* 100,
2,
),
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_memory_used",
name=f"{name} Memory Used",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=DATA_GIGABYTES,
icon="mdi:memory",
value=lambda bridge, i=index: round(
bridge.graphics.controllers[i].memoryUsed / 10 ** 3, 2
),
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_fan_speed",
name=f"{name} Fan Speed",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:fan",
value=lambda bridge, i=index: bridge.graphics.controllers[
i
].fanSpeed,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_power_usage",
name=f"{name} Power Usage",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=POWER_WATT,
value=lambda bridge, i=index: bridge.graphics.controllers[
i
].powerDraw,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_temperature",
name=f"{name} Temperature",
entity_registry_enabled_default=False,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=TEMP_CELSIUS,
value=lambda bridge, i=index: bridge.graphics.controllers[
i
].temperatureGpu,
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"gpu_{index}_usage_percentage",
name=f"{name} Usage %",
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge, i=index: bridge.graphics.controllers[
i
].utilizationGpu,
),
),
]
for index, _ in enumerate(coordinator.data.processes.load.cpus):
entities = [
*entities,
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"processes_load_cpu_{index}",
name=f"Load CPU {index}",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge, index=index: round(
bridge.processes.load.cpus[index].load, 2
),
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"processes_load_cpu_{index}_idle",
name=f"Idle Load CPU {index}",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge, index=index: round(
bridge.processes.load.cpus[index].loadIdle, 2
),
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"processes_load_cpu_{index}_system",
name=f"System Load CPU {index}",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge, index=index: round(
bridge.processes.load.cpus[index].loadSystem, 2
),
),
),
SystemBridgeSensor(
coordinator,
SystemBridgeSensorEntityDescription(
key=f"processes_load_cpu_{index}_user",
name=f"User Load CPU {index}",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
icon="mdi:percent",
value=lambda bridge, index=index: round(
bridge.processes.load.cpus[index].loadUser, 2
),
),
),
]
async_add_entities(entities)
class SystemBridgeSensor(SystemBridgeDeviceEntity, SensorEntity):
"""Define a System Bridge sensor."""
coordinator: SystemBridgeDataUpdateCoordinator
entity_description: SystemBridgeSensorEntityDescription
def __init__(
self,
coordinator: SystemBridgeDataUpdateCoordinator,
description: SystemBridgeSensorEntityDescription,
) -> None:
"""Initialize."""
super().__init__(
coordinator,
description.key,
description.name,
)
self.entity_description = description
@property
def native_value(self) -> StateType:
"""Return the state."""
bridge: Bridge = self.coordinator.data
try:
return cast(StateType, self.entity_description.value(bridge))
except TypeError:
return None