Add Webmin filesystem sensors (#112660)
* Add Webmin filesystem sensors * fix names * update snapshots --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
465e3d421e
commit
6ce1d97e7a
6 changed files with 3097 additions and 21 deletions
|
@ -51,4 +51,6 @@ class WebminUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _async_update_data(self) -> dict[str, Any]:
|
async def _async_update_data(self) -> dict[str, Any]:
|
||||||
return await self.instance.update()
|
data = await self.instance.update()
|
||||||
|
data["disk_fs"] = {item["dir"]: item for item in data["disk_fs"]}
|
||||||
|
return data
|
||||||
|
|
|
@ -21,6 +21,39 @@
|
||||||
},
|
},
|
||||||
"swap_free": {
|
"swap_free": {
|
||||||
"default": "mdi:memory"
|
"default": "mdi:memory"
|
||||||
|
},
|
||||||
|
"disk_total": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_used": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_free": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_total": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_used": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_free": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_itotal": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_iused": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_ifree": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_used_percent": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
|
},
|
||||||
|
"disk_fs_iused_percent": {
|
||||||
|
"default": "mdi:harddisk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
SensorEntityDescription,
|
SensorEntityDescription,
|
||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
from homeassistant.const import UnitOfInformation
|
from homeassistant.const import PERCENTAGE, UnitOfInformation
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
@ -16,6 +18,14 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
from . import WebminConfigEntry
|
from . import WebminConfigEntry
|
||||||
from .coordinator import WebminUpdateCoordinator
|
from .coordinator import WebminUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class WebminFSSensorDescription(SensorEntityDescription):
|
||||||
|
"""Represents a filesystem sensor description."""
|
||||||
|
|
||||||
|
mountpoint: str
|
||||||
|
|
||||||
|
|
||||||
SENSOR_TYPES: list[SensorEntityDescription] = [
|
SENSOR_TYPES: list[SensorEntityDescription] = [
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="load_1m",
|
key="load_1m",
|
||||||
|
@ -75,9 +85,118 @@ SENSOR_TYPES: list[SensorEntityDescription] = [
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="disk_total",
|
||||||
|
translation_key="disk_total",
|
||||||
|
native_unit_of_measurement=UnitOfInformation.BYTES,
|
||||||
|
suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
|
||||||
|
device_class=SensorDeviceClass.DATA_SIZE,
|
||||||
|
suggested_display_precision=1,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="disk_free",
|
||||||
|
translation_key="disk_free",
|
||||||
|
native_unit_of_measurement=UnitOfInformation.BYTES,
|
||||||
|
suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
|
||||||
|
device_class=SensorDeviceClass.DATA_SIZE,
|
||||||
|
suggested_display_precision=1,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="disk_used",
|
||||||
|
translation_key="disk_used",
|
||||||
|
native_unit_of_measurement=UnitOfInformation.BYTES,
|
||||||
|
suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
|
||||||
|
device_class=SensorDeviceClass.DATA_SIZE,
|
||||||
|
suggested_display_precision=1,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def generate_filesystem_sensor_description(
|
||||||
|
mountpoint: str,
|
||||||
|
) -> list[WebminFSSensorDescription]:
|
||||||
|
"""Return all sensor descriptions for a mount point."""
|
||||||
|
|
||||||
|
return [
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="total",
|
||||||
|
translation_key="disk_fs_total",
|
||||||
|
native_unit_of_measurement=UnitOfInformation.BYTES,
|
||||||
|
suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
|
||||||
|
device_class=SensorDeviceClass.DATA_SIZE,
|
||||||
|
suggested_display_precision=1,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="used",
|
||||||
|
translation_key="disk_fs_used",
|
||||||
|
native_unit_of_measurement=UnitOfInformation.BYTES,
|
||||||
|
suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
|
||||||
|
device_class=SensorDeviceClass.DATA_SIZE,
|
||||||
|
suggested_display_precision=1,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="free",
|
||||||
|
translation_key="disk_fs_free",
|
||||||
|
native_unit_of_measurement=UnitOfInformation.BYTES,
|
||||||
|
suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
|
||||||
|
device_class=SensorDeviceClass.DATA_SIZE,
|
||||||
|
suggested_display_precision=1,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="itotal",
|
||||||
|
translation_key="disk_fs_itotal",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="iused",
|
||||||
|
translation_key="disk_fs_iused",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="ifree",
|
||||||
|
translation_key="disk_fs_ifree",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="used_percent",
|
||||||
|
translation_key="disk_fs_used_percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
WebminFSSensorDescription(
|
||||||
|
mountpoint=mountpoint,
|
||||||
|
key="iused_percent",
|
||||||
|
translation_key="disk_fs_iused_percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry: WebminConfigEntry,
|
entry: WebminConfigEntry,
|
||||||
|
@ -85,11 +204,21 @@ async def async_setup_entry(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up Webmin sensors based on a config entry."""
|
"""Set up Webmin sensors based on a config entry."""
|
||||||
coordinator = entry.runtime_data
|
coordinator = entry.runtime_data
|
||||||
async_add_entities(
|
|
||||||
|
entities: list[WebminSensor | WebminFSSensor] = [
|
||||||
WebminSensor(coordinator, description)
|
WebminSensor(coordinator, description)
|
||||||
for description in SENSOR_TYPES
|
for description in SENSOR_TYPES
|
||||||
if description.key in coordinator.data
|
if description.key in coordinator.data
|
||||||
)
|
]
|
||||||
|
|
||||||
|
for fs, values in coordinator.data["disk_fs"].items():
|
||||||
|
entities += [
|
||||||
|
WebminFSSensor(coordinator, description)
|
||||||
|
for description in generate_filesystem_sensor_description(fs)
|
||||||
|
if description.key in values
|
||||||
|
]
|
||||||
|
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class WebminSensor(CoordinatorEntity[WebminUpdateCoordinator], SensorEntity):
|
class WebminSensor(CoordinatorEntity[WebminUpdateCoordinator], SensorEntity):
|
||||||
|
@ -112,3 +241,32 @@ class WebminSensor(CoordinatorEntity[WebminUpdateCoordinator], SensorEntity):
|
||||||
def native_value(self) -> int | float:
|
def native_value(self) -> int | float:
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
return self.coordinator.data[self.entity_description.key]
|
return self.coordinator.data[self.entity_description.key]
|
||||||
|
|
||||||
|
|
||||||
|
class WebminFSSensor(CoordinatorEntity[WebminUpdateCoordinator], SensorEntity):
|
||||||
|
"""Represents a Webmin filesystem sensor."""
|
||||||
|
|
||||||
|
entity_description: WebminFSSensorDescription
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: WebminUpdateCoordinator,
|
||||||
|
description: WebminFSSensorDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize a Webmin filesystem sensor."""
|
||||||
|
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = description
|
||||||
|
self._attr_device_info = coordinator.device_info
|
||||||
|
self._attr_translation_placeholders = {"mountpoint": description.mountpoint}
|
||||||
|
self._attr_unique_id = (
|
||||||
|
f"{coordinator.mac_address}_{description.mountpoint}_{description.key}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> int | float:
|
||||||
|
"""Return the state of the sensor."""
|
||||||
|
return self.coordinator.data["disk_fs"][self.entity_description.mountpoint][
|
||||||
|
self.entity_description.key
|
||||||
|
]
|
||||||
|
|
|
@ -48,6 +48,39 @@
|
||||||
},
|
},
|
||||||
"swap_free": {
|
"swap_free": {
|
||||||
"name": "Swap free"
|
"name": "Swap free"
|
||||||
|
},
|
||||||
|
"disk_total": {
|
||||||
|
"name": "Disks total space"
|
||||||
|
},
|
||||||
|
"disk_used": {
|
||||||
|
"name": "Disks used space"
|
||||||
|
},
|
||||||
|
"disk_free": {
|
||||||
|
"name": "Disks free space"
|
||||||
|
},
|
||||||
|
"disk_fs_total": {
|
||||||
|
"name": "Disk total space {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_used": {
|
||||||
|
"name": "Disk used space {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_free": {
|
||||||
|
"name": "Disk free space {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_itotal": {
|
||||||
|
"name": "Disk total inodes {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_iused": {
|
||||||
|
"name": "Disk used inodes {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_ifree": {
|
||||||
|
"name": "Disk free inodes {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_used_percent": {
|
||||||
|
"name": "Disk usage {mountpoint}"
|
||||||
|
},
|
||||||
|
"disk_fs_iused_percent": {
|
||||||
|
"name": "Disk inode usage {mountpoint}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,8 @@
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
'disk_free': 7749321486336,
|
'disk_free': 7749321486336,
|
||||||
'disk_fs': list([
|
'disk_fs': dict({
|
||||||
dict({
|
'/': dict({
|
||||||
'device': '**REDACTED**',
|
'device': '**REDACTED**',
|
||||||
'dir': '**REDACTED**',
|
'dir': '**REDACTED**',
|
||||||
'free': 49060442112,
|
'free': 49060442112,
|
||||||
|
@ -125,20 +125,7 @@
|
||||||
'used': 186676502528,
|
'used': 186676502528,
|
||||||
'used_percent': 80,
|
'used_percent': 80,
|
||||||
}),
|
}),
|
||||||
dict({
|
'/media/disk1': dict({
|
||||||
'device': '**REDACTED**',
|
|
||||||
'dir': '**REDACTED**',
|
|
||||||
'free': 7028764823552,
|
|
||||||
'ifree': 362656466,
|
|
||||||
'itotal': 366198784,
|
|
||||||
'iused': 3542318,
|
|
||||||
'iused_percent': 1,
|
|
||||||
'total': 11903838912512,
|
|
||||||
'type': 'ext4',
|
|
||||||
'used': 4275077644288,
|
|
||||||
'used_percent': 38,
|
|
||||||
}),
|
|
||||||
dict({
|
|
||||||
'device': '**REDACTED**',
|
'device': '**REDACTED**',
|
||||||
'dir': '**REDACTED**',
|
'dir': '**REDACTED**',
|
||||||
'free': 671496220672,
|
'free': 671496220672,
|
||||||
|
@ -151,7 +138,20 @@
|
||||||
'used': 4981066997760,
|
'used': 4981066997760,
|
||||||
'used_percent': 89,
|
'used_percent': 89,
|
||||||
}),
|
}),
|
||||||
]),
|
'/media/disk2': dict({
|
||||||
|
'device': '**REDACTED**',
|
||||||
|
'dir': '**REDACTED**',
|
||||||
|
'free': 7028764823552,
|
||||||
|
'ifree': 362656466,
|
||||||
|
'itotal': 366198784,
|
||||||
|
'iused': 3542318,
|
||||||
|
'iused_percent': 1,
|
||||||
|
'total': 11903838912512,
|
||||||
|
'type': 'ext4',
|
||||||
|
'used': 4275077644288,
|
||||||
|
'used_percent': 38,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
'disk_total': 18104905818112,
|
'disk_total': 18104905818112,
|
||||||
'disk_used': 9442821144576,
|
'disk_used': 9442821144576,
|
||||||
'drivetemps': list([
|
'drivetemps': list([
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue