core/homeassistant/components/system_bridge/sensor.py

341 lines
10 KiB
Python

"""Support for System Bridge sensors."""
from __future__ import annotations
from datetime import datetime, timedelta
from typing import Any
from systembridge import Bridge
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
DEVICE_CLASS_VOLTAGE,
FREQUENCY_GIGAHERTZ,
PERCENTAGE,
TEMP_CELSIUS,
VOLT,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import BridgeDeviceEntity
from .const import DOMAIN
ATTR_AVAILABLE = "available"
ATTR_FILESYSTEM = "filesystem"
ATTR_LOAD_AVERAGE = "load_average"
ATTR_LOAD_IDLE = "load_idle"
ATTR_LOAD_SYSTEM = "load_system"
ATTR_LOAD_USER = "load_user"
ATTR_MOUNT = "mount"
ATTR_SIZE = "size"
ATTR_TYPE = "type"
ATTR_USED = "used"
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
) -> None:
"""Set up System Bridge sensor based on a config entry."""
coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
bridge: Bridge = coordinator.data
entities = [
BridgeCpuSpeedSensor(coordinator, bridge),
BridgeCpuTemperatureSensor(coordinator, bridge),
BridgeCpuVoltageSensor(coordinator, bridge),
*[
BridgeFilesystemSensor(coordinator, bridge, key)
for key, _ in bridge.filesystem.fsSize.items()
],
BridgeKernelSensor(coordinator, bridge),
BridgeOsSensor(coordinator, bridge),
BridgeProcessesLoadSensor(coordinator, bridge),
]
if bridge.battery.hasBattery:
entities.append(BridgeBatterySensor(coordinator, bridge))
entities.append(BridgeBatteryTimeRemainingSensor(coordinator, bridge))
async_add_entities(entities)
class BridgeSensor(BridgeDeviceEntity, SensorEntity):
"""Defines a System Bridge sensor."""
def __init__(
self,
coordinator: DataUpdateCoordinator,
bridge: Bridge,
key: str,
name: str,
icon: str | None,
device_class: str | None,
unit_of_measurement: str | None,
enabled_by_default: bool,
) -> None:
"""Initialize System Bridge sensor."""
self._device_class = device_class
self._unit_of_measurement = unit_of_measurement
super().__init__(coordinator, bridge, key, name, icon, enabled_by_default)
@property
def device_class(self) -> str | None:
"""Return the class of this sensor."""
return self._device_class
@property
def unit_of_measurement(self) -> str | None:
"""Return the unit this state is expressed in."""
return self._unit_of_measurement
class BridgeBatterySensor(BridgeSensor):
"""Defines a Battery sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"battery",
"Battery",
None,
DEVICE_CLASS_BATTERY,
PERCENTAGE,
True,
)
@property
def state(self) -> float:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return bridge.battery.percent
class BridgeBatteryTimeRemainingSensor(BridgeSensor):
"""Defines the Battery Time Remaining sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"battery_time_remaining",
"Battery Time Remaining",
None,
DEVICE_CLASS_TIMESTAMP,
None,
True,
)
@property
def state(self) -> str | None:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
if bridge.battery.timeRemaining is None:
return None
return str(datetime.now() + timedelta(minutes=bridge.battery.timeRemaining))
class BridgeCpuSpeedSensor(BridgeSensor):
"""Defines a CPU speed sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"cpu_speed",
"CPU Speed",
None,
None,
FREQUENCY_GIGAHERTZ,
True,
)
@property
def state(self) -> float:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return bridge.cpu.currentSpeed.avg
class BridgeCpuTemperatureSensor(BridgeSensor):
"""Defines a CPU temperature sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"cpu_temperature",
"CPU Temperature",
None,
DEVICE_CLASS_TEMPERATURE,
TEMP_CELSIUS,
False,
)
@property
def state(self) -> float:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return bridge.cpu.temperature.main
class BridgeCpuVoltageSensor(BridgeSensor):
"""Defines a CPU voltage sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"cpu_voltage",
"CPU Voltage",
None,
DEVICE_CLASS_VOLTAGE,
VOLT,
False,
)
@property
def state(self) -> float:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return bridge.cpu.cpu.voltage
class BridgeFilesystemSensor(BridgeSensor):
"""Defines a filesystem sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge, key: str):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
f"filesystem_{key}",
f"{key} Space Used",
None,
None,
PERCENTAGE,
True,
)
self._key = key
@property
def state(self) -> float:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return (
round(bridge.filesystem.fsSize[self._key]["use"], 2)
if bridge.filesystem.fsSize[self._key]["use"] is not None
else None
)
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the entity."""
bridge: Bridge = self.coordinator.data
return {
ATTR_AVAILABLE: bridge.filesystem.fsSize[self._key]["available"],
ATTR_FILESYSTEM: bridge.filesystem.fsSize[self._key]["fs"],
ATTR_MOUNT: bridge.filesystem.fsSize[self._key]["mount"],
ATTR_SIZE: bridge.filesystem.fsSize[self._key]["size"],
ATTR_TYPE: bridge.filesystem.fsSize[self._key]["type"],
ATTR_USED: bridge.filesystem.fsSize[self._key]["used"],
}
class BridgeKernelSensor(BridgeSensor):
"""Defines a kernel sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"kernel",
"Kernel",
"mdi:devices",
None,
None,
True,
)
@property
def state(self) -> str:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return bridge.os.kernel
class BridgeOsSensor(BridgeSensor):
"""Defines an OS sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"os",
"Operating System",
"mdi:devices",
None,
None,
True,
)
@property
def state(self) -> str:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return f"{bridge.os.distro} {bridge.os.release}"
class BridgeProcessesLoadSensor(BridgeSensor):
"""Defines a Processes Load sensor."""
def __init__(self, coordinator: DataUpdateCoordinator, bridge: Bridge):
"""Initialize System Bridge sensor."""
super().__init__(
coordinator,
bridge,
"processes_load",
"Load",
"mdi:percent",
None,
PERCENTAGE,
True,
)
@property
def state(self) -> float:
"""Return the state of the sensor."""
bridge: Bridge = self.coordinator.data
return (
round(bridge.processes.load.currentLoad, 2)
if bridge.processes.load.currentLoad is not None
else None
)
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the entity."""
bridge: Bridge = self.coordinator.data
attrs = {}
if bridge.processes.load.avgLoad is not None:
attrs[ATTR_LOAD_AVERAGE] = round(bridge.processes.load.avgLoad, 2)
if bridge.processes.load.currentLoadUser is not None:
attrs[ATTR_LOAD_USER] = round(bridge.processes.load.currentLoadUser, 2)
if bridge.processes.load.currentLoadSystem is not None:
attrs[ATTR_LOAD_SYSTEM] = round(bridge.processes.load.currentLoadSystem, 2)
if bridge.processes.load.currentLoadIdle is not None:
attrs[ATTR_LOAD_IDLE] = round(bridge.processes.load.currentLoadIdle, 2)
return attrs