514 lines
19 KiB
Python
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
|