Use EntityDescription - synology_dsm (#55407)

This commit is contained in:
Marc Mueller 2021-09-03 23:35:28 +02:00 committed by GitHub
parent f5cd321185
commit 4eba2ccebc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 486 additions and 472 deletions

View File

@ -26,14 +26,9 @@ from synology_dsm.exceptions import (
SynologyDSMRequestException, SynologyDSMRequestException,
) )
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
CONF_HOST, CONF_HOST,
CONF_MAC, CONF_MAC,
CONF_PASSWORD, CONF_PASSWORD,
@ -68,7 +63,6 @@ from .const import (
DEFAULT_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL,
DEFAULT_VERIFY_SSL, DEFAULT_VERIFY_SSL,
DOMAIN, DOMAIN,
ENTITY_ENABLE,
EXCEPTION_DETAILS, EXCEPTION_DETAILS,
EXCEPTION_UNKNOWN, EXCEPTION_UNKNOWN,
PLATFORMS, PLATFORMS,
@ -82,7 +76,7 @@ from .const import (
SYSTEM_LOADED, SYSTEM_LOADED,
UNDO_UPDATE_LISTENER, UNDO_UPDATE_LISTENER,
UTILISATION_SENSORS, UTILISATION_SENSORS,
EntityInfo, SynologyDSMEntityDescription,
) )
CONFIG_SCHEMA = cv.deprecated(DOMAIN) CONFIG_SCHEMA = cv.deprecated(DOMAIN)
@ -109,12 +103,12 @@ async def async_setup_entry( # noqa: C901
if "SYNO." in entity_entry.unique_id: if "SYNO." in entity_entry.unique_id:
return None return None
entries = { entries = (
**STORAGE_DISK_BINARY_SENSORS, *STORAGE_DISK_BINARY_SENSORS,
**STORAGE_DISK_SENSORS, *STORAGE_DISK_SENSORS,
**STORAGE_VOL_SENSORS, *STORAGE_VOL_SENSORS,
**UTILISATION_SENSORS, *UTILISATION_SENSORS,
} )
infos = entity_entry.unique_id.split("_") infos = entity_entry.unique_id.split("_")
serial = infos.pop(0) serial = infos.pop(0)
label = infos.pop(0) label = infos.pop(0)
@ -129,22 +123,22 @@ async def async_setup_entry( # noqa: C901
return None return None
entity_type: str | None = None entity_type: str | None = None
for entity_key, entity_attrs in entries.items(): for description in entries:
if ( if (
device_id device_id
and entity_attrs[ATTR_NAME] == "Status" and description.name == "Status"
and "Status" in entity_entry.unique_id and "Status" in entity_entry.unique_id
and "(Smart)" not in entity_entry.unique_id and "(Smart)" not in entity_entry.unique_id
): ):
if "sd" in device_id and "disk" in entity_key: if "sd" in device_id and "disk" in description.key:
entity_type = entity_key entity_type = description.key
continue continue
if "volume" in device_id and "volume" in entity_key: if "volume" in device_id and "volume" in description.key:
entity_type = entity_key entity_type = description.key
continue continue
if entity_attrs[ATTR_NAME] == label: if description.name == label:
entity_type = entity_key entity_type = description.key
if entity_type is None: if entity_type is None:
return None return None
@ -604,51 +598,25 @@ class SynoApi:
class SynologyDSMBaseEntity(CoordinatorEntity): class SynologyDSMBaseEntity(CoordinatorEntity):
"""Representation of a Synology NAS entry.""" """Representation of a Synology NAS entry."""
entity_description: SynologyDSMEntityDescription
unique_id: str
_attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
def __init__( def __init__(
self, self,
api: SynoApi, api: SynoApi,
entity_type: str,
entity_info: EntityInfo,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]], coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMEntityDescription,
) -> None: ) -> None:
"""Initialize the Synology DSM entity.""" """Initialize the Synology DSM entity."""
super().__init__(coordinator) super().__init__(coordinator)
self.entity_description = description
self._api = api self._api = api
self._api_key = entity_type.split(":")[0] self._attr_name = f"{api.network.hostname} {description.name}"
self.entity_type = entity_type.split(":")[-1] self._attr_unique_id: str = (
self._name = f"{api.network.hostname} {entity_info[ATTR_NAME]}" f"{api.information.serial}_{description.api_key}:{description.key}"
self._class = entity_info[ATTR_DEVICE_CLASS] )
self._enable_default = entity_info[ENTITY_ENABLE]
self._icon = entity_info[ATTR_ICON]
self._unit = entity_info[ATTR_UNIT_OF_MEASUREMENT]
self._unique_id = f"{self._api.information.serial}_{entity_type}"
self._attr_state_class = entity_info[ATTR_STATE_CLASS]
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return self._unique_id
@property
def name(self) -> str:
"""Return the name."""
return self._name
@property
def icon(self) -> str | None:
"""Return the icon."""
return self._icon
@property
def device_class(self) -> str | None:
"""Return the class of this device."""
return self._class
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return {ATTR_ATTRIBUTION: ATTRIBUTION}
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
@ -661,14 +629,11 @@ class SynologyDSMBaseEntity(CoordinatorEntity):
"sw_version": self._api.information.version_string, "sw_version": self._api.information.version_string,
} }
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
return self._enable_default
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register entity for updates from API.""" """Register entity for updates from API."""
self.async_on_remove(self._api.subscribe(self._api_key, self.unique_id)) self.async_on_remove(
self._api.subscribe(self.entity_description.api_key, self.unique_id)
)
await super().async_added_to_hass() await super().async_added_to_hass()
@ -678,13 +643,12 @@ class SynologyDSMDeviceEntity(SynologyDSMBaseEntity):
def __init__( def __init__(
self, self,
api: SynoApi, api: SynoApi,
entity_type: str,
entity_info: EntityInfo,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]], coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMEntityDescription,
device_id: str | None = None, device_id: str | None = None,
) -> None: ) -> None:
"""Initialize the Synology DSM disk or volume entity.""" """Initialize the Synology DSM disk or volume entity."""
super().__init__(api, entity_type, entity_info, coordinator) super().__init__(api, coordinator, description)
self._device_id = device_id self._device_id = device_id
self._device_name: str | None = None self._device_name: str | None = None
self._device_manufacturer: str | None = None self._device_manufacturer: str | None = None
@ -692,7 +656,7 @@ class SynologyDSMDeviceEntity(SynologyDSMBaseEntity):
self._device_firmware: str | None = None self._device_firmware: str | None = None
self._device_type = None self._device_type = None
if "volume" in entity_type: if "volume" in description.key:
volume = self._api.storage.get_volume(self._device_id) volume = self._api.storage.get_volume(self._device_id)
# Volume does not have a name # Volume does not have a name
self._device_name = volume["id"].replace("_", " ").capitalize() self._device_name = volume["id"].replace("_", " ").capitalize()
@ -705,7 +669,7 @@ class SynologyDSMDeviceEntity(SynologyDSMBaseEntity):
.replace("raid", "RAID") .replace("raid", "RAID")
.replace("shr", "SHR") .replace("shr", "SHR")
) )
elif "disk" in entity_type: elif "disk" in description.key:
disk = self._api.storage.get_disk(self._device_id) disk = self._api.storage.get_disk(self._device_id)
self._device_name = disk["name"] self._device_name = disk["name"]
self._device_manufacturer = disk["vendor"] self._device_manufacturer = disk["vendor"]
@ -713,9 +677,9 @@ class SynologyDSMDeviceEntity(SynologyDSMBaseEntity):
self._device_firmware = disk["firm"] self._device_firmware = disk["firm"]
self._device_type = disk["diskType"] self._device_type = disk["diskType"]
self._name = ( self._name = (
f"{self._api.network.hostname} {self._device_name} {entity_info[ATTR_NAME]}" f"{self._api.network.hostname} {self._device_name} {description.name}"
) )
self._unique_id += f"_{self._device_id}" self._attr_unique_id += f"_{self._device_id}"
@property @property
def available(self) -> bool: def available(self) -> bool:

View File

@ -1,11 +1,14 @@
"""Support for Synology DSM binary sensors.""" """Support for Synology DSM binary sensors."""
from __future__ import annotations from __future__ import annotations
from typing import Any
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_DISKS from homeassistant.const import CONF_DISKS
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 DataUpdateCoordinator
from . import SynoApi, SynologyDSMBaseEntity, SynologyDSMDeviceEntity from . import SynoApi, SynologyDSMBaseEntity, SynologyDSMDeviceEntity
from .const import ( from .const import (
@ -15,6 +18,7 @@ from .const import (
STORAGE_DISK_BINARY_SENSORS, STORAGE_DISK_BINARY_SENSORS,
SYNO_API, SYNO_API,
UPGRADE_BINARY_SENSORS, UPGRADE_BINARY_SENSORS,
SynologyDSMBinarySensorEntityDescription,
) )
@ -32,39 +36,52 @@ async def async_setup_entry(
| SynoDSMUpgradeBinarySensor | SynoDSMUpgradeBinarySensor
| SynoDSMStorageBinarySensor | SynoDSMStorageBinarySensor
] = [ ] = [
SynoDSMSecurityBinarySensor(api, sensor_type, sensor, coordinator) SynoDSMSecurityBinarySensor(api, coordinator, description)
for sensor_type, sensor in SECURITY_BINARY_SENSORS.items() for description in SECURITY_BINARY_SENSORS
] ]
entities += [ entities.extend(
SynoDSMUpgradeBinarySensor(api, sensor_type, sensor, coordinator) [
for sensor_type, sensor in UPGRADE_BINARY_SENSORS.items() SynoDSMUpgradeBinarySensor(api, coordinator, description)
for description in UPGRADE_BINARY_SENSORS
] ]
)
# Handle all disks # Handle all disks
if api.storage.disks_ids: if api.storage.disks_ids:
for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids): entities.extend(
entities += [ [
SynoDSMStorageBinarySensor( SynoDSMStorageBinarySensor(api, coordinator, description, disk)
api, for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids)
sensor_type, for description in STORAGE_DISK_BINARY_SENSORS
sensor,
coordinator,
disk,
)
for sensor_type, sensor in STORAGE_DISK_BINARY_SENSORS.items()
] ]
)
async_add_entities(entities) async_add_entities(entities)
class SynoDSMSecurityBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity): class SynoDSMBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
"""Mixin for binary sensor specific attributes."""
entity_description: SynologyDSMBinarySensorEntityDescription
def __init__(
self,
api: SynoApi,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMBinarySensorEntityDescription,
) -> None:
"""Initialize the Synology DSM binary_sensor entity."""
super().__init__(api, coordinator, description)
class SynoDSMSecurityBinarySensor(SynoDSMBinarySensor):
"""Representation a Synology Security binary sensor.""" """Representation a Synology Security binary sensor."""
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
"""Return the state.""" """Return the state."""
return getattr(self._api.security, self.entity_type) != "safe" # type: ignore[no-any-return] return getattr(self._api.security, self.entity_description.key) != "safe" # type: ignore[no-any-return]
@property @property
def available(self) -> bool: def available(self) -> bool:
@ -77,22 +94,36 @@ class SynoDSMSecurityBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
return self._api.security.status_by_check # type: ignore[no-any-return] return self._api.security.status_by_check # type: ignore[no-any-return]
class SynoDSMStorageBinarySensor(SynologyDSMDeviceEntity, BinarySensorEntity): class SynoDSMStorageBinarySensor(SynologyDSMDeviceEntity, SynoDSMBinarySensor):
"""Representation a Synology Storage binary sensor.""" """Representation a Synology Storage binary sensor."""
entity_description: SynologyDSMBinarySensorEntityDescription
def __init__(
self,
api: SynoApi,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMBinarySensorEntityDescription,
device_id: str | None = None,
) -> None:
"""Initialize the Synology DSM storage binary_sensor entity."""
super().__init__(api, coordinator, description, device_id)
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
"""Return the state.""" """Return the state."""
return bool(getattr(self._api.storage, self.entity_type)(self._device_id)) return bool(
getattr(self._api.storage, self.entity_description.key)(self._device_id)
)
class SynoDSMUpgradeBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity): class SynoDSMUpgradeBinarySensor(SynoDSMBinarySensor):
"""Representation a Synology Upgrade binary sensor.""" """Representation a Synology Upgrade binary sensor."""
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
"""Return the state.""" """Return the state."""
return bool(getattr(self._api.upgrade, self.entity_type)) return bool(getattr(self._api.upgrade, self.entity_description.key))
@property @property
def available(self) -> bool: def available(self) -> bool:

View File

@ -1,6 +1,7 @@
"""Support for Synology DSM cameras.""" """Support for Synology DSM cameras."""
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass
import logging import logging
from synology_dsm.api.surveillance_station import SynoCamera, SynoSurveillanceStation from synology_dsm.api.surveillance_station import SynoCamera, SynoSurveillanceStation
@ -9,26 +10,30 @@ from synology_dsm.exceptions import (
SynologyDSMRequestException, SynologyDSMRequestException,
) )
from homeassistant.components.camera import SUPPORT_STREAM, Camera from homeassistant.components.camera import (
from homeassistant.components.sensor import ATTR_STATE_CLASS SUPPORT_STREAM,
from homeassistant.config_entries import ConfigEntry Camera,
from homeassistant.const import ( CameraEntityDescription,
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import SynoApi, SynologyDSMBaseEntity from . import SynoApi, SynologyDSMBaseEntity
from .const import COORDINATOR_CAMERAS, DOMAIN, ENTITY_ENABLE, SYNO_API from .const import COORDINATOR_CAMERAS, DOMAIN, SYNO_API, SynologyDSMEntityDescription
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@dataclass
class SynologyDSMCameraEntityDescription(
CameraEntityDescription, SynologyDSMEntityDescription
):
"""Describes Synology DSM camera entity."""
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None: ) -> None:
@ -56,6 +61,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"""Representation a Synology camera.""" """Representation a Synology camera."""
coordinator: DataUpdateCoordinator[dict[str, dict[str, SynoCamera]]] coordinator: DataUpdateCoordinator[dict[str, dict[str, SynoCamera]]]
entity_description: SynologyDSMCameraEntityDescription
def __init__( def __init__(
self, self,
@ -64,26 +70,21 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
camera_id: str, camera_id: str,
) -> None: ) -> None:
"""Initialize a Synology camera.""" """Initialize a Synology camera."""
super().__init__( description = SynologyDSMCameraEntityDescription(
api, api_key=SynoSurveillanceStation.CAMERA_API_KEY,
f"{SynoSurveillanceStation.CAMERA_API_KEY}:{camera_id}", key=camera_id,
{ name=coordinator.data["cameras"][camera_id].name,
ATTR_NAME: coordinator.data["cameras"][camera_id].name, entity_registry_enabled_default=coordinator.data["cameras"][
ENTITY_ENABLE: coordinator.data["cameras"][camera_id].is_enabled, camera_id
ATTR_DEVICE_CLASS: None, ].is_enabled,
ATTR_ICON: None,
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_STATE_CLASS: None,
},
coordinator,
) )
super().__init__(api, coordinator, description)
Camera.__init__(self) Camera.__init__(self)
self._camera_id = camera_id
@property @property
def camera_data(self) -> SynoCamera: def camera_data(self) -> SynoCamera:
"""Camera data.""" """Camera data."""
return self.coordinator.data["cameras"][self._camera_id] return self.coordinator.data["cameras"][self.entity_description.key]
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
@ -134,7 +135,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
if not self.available: if not self.available:
return None return None
try: try:
return self._api.surveillance_station.get_camera_image(self._camera_id) # type: ignore[no-any-return] return self._api.surveillance_station.get_camera_image(self.entity_description.key) # type: ignore[no-any-return]
except ( except (
SynologyDSMAPIErrorException, SynologyDSMAPIErrorException,
SynologyDSMRequestException, SynologyDSMRequestException,
@ -163,7 +164,9 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"SynoDSMCamera.enable_motion_detection(%s)", "SynoDSMCamera.enable_motion_detection(%s)",
self.camera_data.name, self.camera_data.name,
) )
self._api.surveillance_station.enable_motion_detection(self._camera_id) self._api.surveillance_station.enable_motion_detection(
self.entity_description.key
)
def disable_motion_detection(self) -> None: def disable_motion_detection(self) -> None:
"""Disable motion detection in camera.""" """Disable motion detection in camera."""
@ -171,4 +174,6 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"SynoDSMCamera.disable_motion_detection(%s)", "SynoDSMCamera.disable_motion_detection(%s)",
self.camera_data.name, self.camera_data.name,
) )
self._api.surveillance_station.disable_motion_detection(self._camera_id) self._api.surveillance_station.disable_motion_detection(
self.entity_description.key
)

View File

@ -1,7 +1,7 @@
"""Constants for Synology DSM.""" """Constants for Synology DSM."""
from __future__ import annotations from __future__ import annotations
from typing import Final, TypedDict from dataclasses import dataclass
from synology_dsm.api.core.security import SynoCoreSecurity from synology_dsm.api.core.security import SynoCoreSecurity
from synology_dsm.api.core.upgrade import SynoCoreUpgrade from synology_dsm.api.core.upgrade import SynoCoreUpgrade
@ -13,13 +13,14 @@ from synology_dsm.api.surveillance_station import SynoSurveillanceStation
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASS_SAFETY, DEVICE_CLASS_SAFETY,
DEVICE_CLASS_UPDATE, DEVICE_CLASS_UPDATE,
BinarySensorEntityDescription,
) )
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntityDescription,
)
from homeassistant.components.switch import SwitchEntityDescription
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
DATA_MEGABYTES, DATA_MEGABYTES,
DATA_RATE_KILOBYTES_PER_SECOND, DATA_RATE_KILOBYTES_PER_SECOND,
DATA_TERABYTES, DATA_TERABYTES,
@ -28,18 +29,7 @@ from homeassistant.const import (
PERCENTAGE, PERCENTAGE,
TEMP_CELSIUS, TEMP_CELSIUS,
) )
from homeassistant.helpers.entity import EntityDescription
class EntityInfo(TypedDict):
"""TypedDict for EntityInfo."""
name: str
unit_of_measurement: str | None
icon: str | None
device_class: str | None
state_class: str | None
enable: bool
DOMAIN = "synology_dsm" DOMAIN = "synology_dsm"
PLATFORMS = ["binary_sensor", "camera", "sensor", "switch"] PLATFORMS = ["binary_sensor", "camera", "sensor", "switch"]
@ -68,7 +58,6 @@ DEFAULT_SCAN_INTERVAL = 15 # min
DEFAULT_TIMEOUT = 10 # sec DEFAULT_TIMEOUT = 10 # sec
ENTITY_UNIT_LOAD = "load" ENTITY_UNIT_LOAD = "load"
ENTITY_ENABLE: Final = "enable"
# Services # Services
SERVICE_REBOOT = "reboot" SERVICE_REBOOT = "reboot"
@ -78,285 +67,302 @@ SERVICES = [
SERVICE_SHUTDOWN, SERVICE_SHUTDOWN,
] ]
# Entity keys should start with the API_KEY to fetch
@dataclass
class SynologyDSMRequiredKeysMixin:
"""Mixin for required keys."""
api_key: str
@dataclass
class SynologyDSMEntityDescription(EntityDescription, SynologyDSMRequiredKeysMixin):
"""Generic Synology DSM entity description."""
@dataclass
class SynologyDSMBinarySensorEntityDescription(
BinarySensorEntityDescription, SynologyDSMEntityDescription
):
"""Describes Synology DSM binary sensor entity."""
@dataclass
class SynologyDSMSensorEntityDescription(
SensorEntityDescription, SynologyDSMEntityDescription
):
"""Describes Synology DSM sensor entity."""
@dataclass
class SynologyDSMSwitchEntityDescription(
SwitchEntityDescription, SynologyDSMEntityDescription
):
"""Describes Synology DSM switch entity."""
# Binary sensors # Binary sensors
UPGRADE_BINARY_SENSORS: dict[str, EntityInfo] = { UPGRADE_BINARY_SENSORS: tuple[SynologyDSMBinarySensorEntityDescription, ...] = (
f"{SynoCoreUpgrade.API_KEY}:update_available": { SynologyDSMBinarySensorEntityDescription(
ATTR_NAME: "Update available", api_key=SynoCoreUpgrade.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: None, key="update_available",
ATTR_ICON: None, name="Update available",
ATTR_DEVICE_CLASS: DEVICE_CLASS_UPDATE, device_class=DEVICE_CLASS_UPDATE,
ENTITY_ENABLE: True, ),
ATTR_STATE_CLASS: None, )
},
}
SECURITY_BINARY_SENSORS: dict[str, EntityInfo] = { SECURITY_BINARY_SENSORS: tuple[SynologyDSMBinarySensorEntityDescription, ...] = (
f"{SynoCoreSecurity.API_KEY}:status": { SynologyDSMBinarySensorEntityDescription(
ATTR_NAME: "Security status", api_key=SynoCoreSecurity.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: None, key="status",
ATTR_ICON: None, name="Security status",
ATTR_DEVICE_CLASS: DEVICE_CLASS_SAFETY, device_class=DEVICE_CLASS_SAFETY,
ENTITY_ENABLE: True, ),
ATTR_STATE_CLASS: None, )
},
}
STORAGE_DISK_BINARY_SENSORS: dict[str, EntityInfo] = { STORAGE_DISK_BINARY_SENSORS: tuple[SynologyDSMBinarySensorEntityDescription, ...] = (
f"{SynoStorage.API_KEY}:disk_exceed_bad_sector_thr": { SynologyDSMBinarySensorEntityDescription(
ATTR_NAME: "Exceeded Max Bad Sectors", api_key=SynoStorage.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: None, key="disk_exceed_bad_sector_thr",
ATTR_ICON: None, name="Exceeded Max Bad Sectors",
ATTR_DEVICE_CLASS: DEVICE_CLASS_SAFETY, device_class=DEVICE_CLASS_SAFETY,
ENTITY_ENABLE: True, ),
ATTR_STATE_CLASS: None, SynologyDSMBinarySensorEntityDescription(
}, api_key=SynoStorage.API_KEY,
f"{SynoStorage.API_KEY}:disk_below_remain_life_thr": { key="disk_below_remain_life_thr",
ATTR_NAME: "Below Min Remaining Life", name="Below Min Remaining Life",
ATTR_UNIT_OF_MEASUREMENT: None, device_class=DEVICE_CLASS_SAFETY,
ATTR_ICON: None, ),
ATTR_DEVICE_CLASS: DEVICE_CLASS_SAFETY, )
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
}
# Sensors # Sensors
UTILISATION_SENSORS: dict[str, EntityInfo] = { UTILISATION_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
f"{SynoCoreUtilization.API_KEY}:cpu_other_load": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "CPU Utilization (Other)", api_key=SynoCoreUtilization.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, key="cpu_other_load",
ATTR_ICON: "mdi:chip", name="CPU Utilization (Other)",
ATTR_DEVICE_CLASS: None, native_unit_of_measurement=PERCENTAGE,
ENTITY_ENABLE: False, icon="mdi:chip",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, entity_registry_enabled_default=False,
}, state_class=STATE_CLASS_MEASUREMENT,
f"{SynoCoreUtilization.API_KEY}:cpu_user_load": { ),
ATTR_NAME: "CPU Utilization (User)", SynologyDSMSensorEntityDescription(
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, api_key=SynoCoreUtilization.API_KEY,
ATTR_ICON: "mdi:chip", key="cpu_user_load",
ATTR_DEVICE_CLASS: None, name="CPU Utilization (User)",
ENTITY_ENABLE: True, native_unit_of_measurement=PERCENTAGE,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, icon="mdi:chip",
}, state_class=STATE_CLASS_MEASUREMENT,
f"{SynoCoreUtilization.API_KEY}:cpu_system_load": { ),
ATTR_NAME: "CPU Utilization (System)", SynologyDSMSensorEntityDescription(
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, api_key=SynoCoreUtilization.API_KEY,
ATTR_ICON: "mdi:chip", key="cpu_system_load",
ATTR_DEVICE_CLASS: None, name="CPU Utilization (System)",
ENTITY_ENABLE: False, native_unit_of_measurement=PERCENTAGE,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, icon="mdi:chip",
}, entity_registry_enabled_default=False,
f"{SynoCoreUtilization.API_KEY}:cpu_total_load": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "CPU Utilization (Total)", ),
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:chip", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="cpu_total_load",
ENTITY_ENABLE: True, name="CPU Utilization (Total)",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=PERCENTAGE,
}, icon="mdi:chip",
f"{SynoCoreUtilization.API_KEY}:cpu_1min_load": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "CPU Load Average (1 min)", ),
ATTR_UNIT_OF_MEASUREMENT: ENTITY_UNIT_LOAD, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:chip", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="cpu_1min_load",
ENTITY_ENABLE: False, name="CPU Load Average (1 min)",
ATTR_STATE_CLASS: None, native_unit_of_measurement=ENTITY_UNIT_LOAD,
}, icon="mdi:chip",
f"{SynoCoreUtilization.API_KEY}:cpu_5min_load": { entity_registry_enabled_default=False,
ATTR_NAME: "CPU Load Average (5 min)", ),
ATTR_UNIT_OF_MEASUREMENT: ENTITY_UNIT_LOAD, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:chip", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="cpu_5min_load",
ENTITY_ENABLE: True, name="CPU Load Average (5 min)",
ATTR_STATE_CLASS: None, native_unit_of_measurement=ENTITY_UNIT_LOAD,
}, icon="mdi:chip",
f"{SynoCoreUtilization.API_KEY}:cpu_15min_load": { ),
ATTR_NAME: "CPU Load Average (15 min)", SynologyDSMSensorEntityDescription(
ATTR_UNIT_OF_MEASUREMENT: ENTITY_UNIT_LOAD, api_key=SynoCoreUtilization.API_KEY,
ATTR_ICON: "mdi:chip", key="cpu_15min_load",
ATTR_DEVICE_CLASS: None, name="CPU Load Average (15 min)",
ENTITY_ENABLE: True, native_unit_of_measurement=ENTITY_UNIT_LOAD,
ATTR_STATE_CLASS: None, icon="mdi:chip",
}, ),
f"{SynoCoreUtilization.API_KEY}:memory_real_usage": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "Memory Usage (Real)", api_key=SynoCoreUtilization.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, key="memory_real_usage",
ATTR_ICON: "mdi:memory", name="Memory Usage (Real)",
ATTR_DEVICE_CLASS: None, native_unit_of_measurement=PERCENTAGE,
ENTITY_ENABLE: True, icon="mdi:memory",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
}, ),
f"{SynoCoreUtilization.API_KEY}:memory_size": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "Memory Size", api_key=SynoCoreUtilization.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES, key="memory_size",
ATTR_ICON: "mdi:memory", name="Memory Size",
ATTR_DEVICE_CLASS: None, native_unit_of_measurement=DATA_MEGABYTES,
ENTITY_ENABLE: False, icon="mdi:memory",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, entity_registry_enabled_default=False,
}, state_class=STATE_CLASS_MEASUREMENT,
f"{SynoCoreUtilization.API_KEY}:memory_cached": { ),
ATTR_NAME: "Memory Cached", SynologyDSMSensorEntityDescription(
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES, api_key=SynoCoreUtilization.API_KEY,
ATTR_ICON: "mdi:memory", key="memory_cached",
ATTR_DEVICE_CLASS: None, name="Memory Cached",
ENTITY_ENABLE: False, native_unit_of_measurement=DATA_MEGABYTES,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, icon="mdi:memory",
}, entity_registry_enabled_default=False,
f"{SynoCoreUtilization.API_KEY}:memory_available_swap": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "Memory Available (Swap)", ),
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:memory", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="memory_available_swap",
ENTITY_ENABLE: True, name="Memory Available (Swap)",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=DATA_MEGABYTES,
}, icon="mdi:memory",
f"{SynoCoreUtilization.API_KEY}:memory_available_real": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "Memory Available (Real)", ),
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:memory", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="memory_available_real",
ENTITY_ENABLE: True, name="Memory Available (Real)",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=DATA_MEGABYTES,
}, icon="mdi:memory",
f"{SynoCoreUtilization.API_KEY}:memory_total_swap": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "Memory Total (Swap)", ),
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:memory", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="memory_total_swap",
ENTITY_ENABLE: True, name="Memory Total (Swap)",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=DATA_MEGABYTES,
}, icon="mdi:memory",
f"{SynoCoreUtilization.API_KEY}:memory_total_real": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "Memory Total (Real)", ),
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:memory", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="memory_total_real",
ENTITY_ENABLE: True, name="Memory Total (Real)",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=DATA_MEGABYTES,
}, icon="mdi:memory",
f"{SynoCoreUtilization.API_KEY}:network_up": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "Upload Throughput", ),
ATTR_UNIT_OF_MEASUREMENT: DATA_RATE_KILOBYTES_PER_SECOND, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:upload", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="network_up",
ENTITY_ENABLE: True, name="Upload Throughput",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=DATA_RATE_KILOBYTES_PER_SECOND,
}, icon="mdi:upload",
f"{SynoCoreUtilization.API_KEY}:network_down": { state_class=STATE_CLASS_MEASUREMENT,
ATTR_NAME: "Download Throughput", ),
ATTR_UNIT_OF_MEASUREMENT: DATA_RATE_KILOBYTES_PER_SECOND, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:download", api_key=SynoCoreUtilization.API_KEY,
ATTR_DEVICE_CLASS: None, key="network_down",
ENTITY_ENABLE: True, name="Download Throughput",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, native_unit_of_measurement=DATA_RATE_KILOBYTES_PER_SECOND,
}, icon="mdi:download",
} state_class=STATE_CLASS_MEASUREMENT,
STORAGE_VOL_SENSORS: dict[str, EntityInfo] = { ),
f"{SynoStorage.API_KEY}:volume_status": { )
ATTR_NAME: "Status", STORAGE_VOL_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
ATTR_UNIT_OF_MEASUREMENT: None, SynologyDSMSensorEntityDescription(
ATTR_ICON: "mdi:checkbox-marked-circle-outline", api_key=SynoStorage.API_KEY,
ATTR_DEVICE_CLASS: None, key="volume_status",
ENTITY_ENABLE: True, name="Status",
ATTR_STATE_CLASS: None, icon="mdi:checkbox-marked-circle-outline",
}, ),
f"{SynoStorage.API_KEY}:volume_size_total": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "Total Size", api_key=SynoStorage.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: DATA_TERABYTES, key="volume_size_total",
ATTR_ICON: "mdi:chart-pie", name="Total Size",
ATTR_DEVICE_CLASS: None, native_unit_of_measurement=DATA_TERABYTES,
ENTITY_ENABLE: False, icon="mdi:chart-pie",
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, entity_registry_enabled_default=False,
}, state_class=STATE_CLASS_MEASUREMENT,
f"{SynoStorage.API_KEY}:volume_size_used": { ),
ATTR_NAME: "Used Space", SynologyDSMSensorEntityDescription(
ATTR_UNIT_OF_MEASUREMENT: DATA_TERABYTES, api_key=SynoStorage.API_KEY,
ATTR_ICON: "mdi:chart-pie", key="volume_size_used",
ATTR_DEVICE_CLASS: None, name="Used Space",
ENTITY_ENABLE: True, native_unit_of_measurement=DATA_TERABYTES,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, icon="mdi:chart-pie",
}, state_class=STATE_CLASS_MEASUREMENT,
f"{SynoStorage.API_KEY}:volume_percentage_used": { ),
ATTR_NAME: "Volume Used", SynologyDSMSensorEntityDescription(
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, api_key=SynoStorage.API_KEY,
ATTR_ICON: "mdi:chart-pie", key="volume_percentage_used",
ATTR_DEVICE_CLASS: None, name="Volume Used",
ENTITY_ENABLE: True, native_unit_of_measurement=PERCENTAGE,
ATTR_STATE_CLASS: None, icon="mdi:chart-pie",
}, ),
f"{SynoStorage.API_KEY}:volume_disk_temp_avg": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "Average Disk Temp", api_key=SynoStorage.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, key="volume_disk_temp_avg",
ATTR_ICON: None, name="Average Disk Temp",
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, native_unit_of_measurement=TEMP_CELSIUS,
ENTITY_ENABLE: True, device_class=DEVICE_CLASS_TEMPERATURE,
ATTR_STATE_CLASS: None, ),
}, SynologyDSMSensorEntityDescription(
f"{SynoStorage.API_KEY}:volume_disk_temp_max": { api_key=SynoStorage.API_KEY,
ATTR_NAME: "Maximum Disk Temp", key="volume_disk_temp_max",
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, name="Maximum Disk Temp",
ATTR_ICON: None, native_unit_of_measurement=TEMP_CELSIUS,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, device_class=DEVICE_CLASS_TEMPERATURE,
ENTITY_ENABLE: False, entity_registry_enabled_default=False,
ATTR_STATE_CLASS: None, ),
}, )
} STORAGE_DISK_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
STORAGE_DISK_SENSORS: dict[str, EntityInfo] = { SynologyDSMSensorEntityDescription(
f"{SynoStorage.API_KEY}:disk_smart_status": { api_key=SynoStorage.API_KEY,
ATTR_NAME: "Status (Smart)", key="disk_smart_status",
ATTR_UNIT_OF_MEASUREMENT: None, name="Status (Smart)",
ATTR_ICON: "mdi:checkbox-marked-circle-outline", icon="mdi:checkbox-marked-circle-outline",
ATTR_DEVICE_CLASS: None, entity_registry_enabled_default=False,
ENTITY_ENABLE: False, ),
ATTR_STATE_CLASS: None, SynologyDSMSensorEntityDescription(
}, api_key=SynoStorage.API_KEY,
f"{SynoStorage.API_KEY}:disk_status": { key="disk_status",
ATTR_NAME: "Status", name="Status",
ATTR_UNIT_OF_MEASUREMENT: None, icon="mdi:checkbox-marked-circle-outline",
ATTR_ICON: "mdi:checkbox-marked-circle-outline", ),
ATTR_DEVICE_CLASS: None, SynologyDSMSensorEntityDescription(
ENTITY_ENABLE: True, api_key=SynoStorage.API_KEY,
ATTR_STATE_CLASS: None, key="disk_temp",
}, name="Temperature",
f"{SynoStorage.API_KEY}:disk_temp": { native_unit_of_measurement=TEMP_CELSIUS,
ATTR_NAME: "Temperature", device_class=DEVICE_CLASS_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, state_class=STATE_CLASS_MEASUREMENT,
ATTR_ICON: None, ),
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, )
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
}
INFORMATION_SENSORS: dict[str, EntityInfo] = { INFORMATION_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
f"{SynoDSMInformation.API_KEY}:temperature": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "temperature", api_key=SynoDSMInformation.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, key="temperature",
ATTR_ICON: None, name="temperature",
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, native_unit_of_measurement=TEMP_CELSIUS,
ENTITY_ENABLE: True, device_class=DEVICE_CLASS_TEMPERATURE,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
}, ),
f"{SynoDSMInformation.API_KEY}:uptime": { SynologyDSMSensorEntityDescription(
ATTR_NAME: "last boot", api_key=SynoDSMInformation.API_KEY,
ATTR_UNIT_OF_MEASUREMENT: None, key="uptime",
ATTR_ICON: None, name="last boot",
ATTR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP, device_class=DEVICE_CLASS_TIMESTAMP,
ENTITY_ENABLE: False, entity_registry_enabled_default=False,
ATTR_STATE_CLASS: None, ),
}, )
}
# Switch # Switch
SURVEILLANCE_SWITCH: dict[str, EntityInfo] = { SURVEILLANCE_SWITCH: tuple[SynologyDSMSwitchEntityDescription, ...] = (
f"{SynoSurveillanceStation.HOME_MODE_API_KEY}:home_mode": { SynologyDSMSwitchEntityDescription(
ATTR_NAME: "home mode", api_key=SynoSurveillanceStation.HOME_MODE_API_KEY,
ATTR_UNIT_OF_MEASUREMENT: None, key="home_mode",
ATTR_ICON: "mdi:home-account", name="home mode",
ATTR_DEVICE_CLASS: None, icon="mdi:home-account",
ENTITY_ENABLE: True, ),
ATTR_STATE_CLASS: None, )
},
}

View File

@ -28,7 +28,7 @@ from .const import (
STORAGE_VOL_SENSORS, STORAGE_VOL_SENSORS,
SYNO_API, SYNO_API,
UTILISATION_SENSORS, UTILISATION_SENSORS,
EntityInfo, SynologyDSMSensorEntityDescription,
) )
@ -42,77 +42,77 @@ async def async_setup_entry(
coordinator = data[COORDINATOR_CENTRAL] coordinator = data[COORDINATOR_CENTRAL]
entities: list[SynoDSMUtilSensor | SynoDSMStorageSensor | SynoDSMInfoSensor] = [ entities: list[SynoDSMUtilSensor | SynoDSMStorageSensor | SynoDSMInfoSensor] = [
SynoDSMUtilSensor(api, sensor_type, sensor, coordinator) SynoDSMUtilSensor(api, coordinator, description)
for sensor_type, sensor in UTILISATION_SENSORS.items() for description in UTILISATION_SENSORS
] ]
# Handle all volumes # Handle all volumes
if api.storage.volumes_ids: if api.storage.volumes_ids:
for volume in entry.data.get(CONF_VOLUMES, api.storage.volumes_ids): entities.extend(
entities += [ [
SynoDSMStorageSensor( SynoDSMStorageSensor(api, coordinator, description, volume)
api, for volume in entry.data.get(CONF_VOLUMES, api.storage.volumes_ids)
sensor_type, for description in STORAGE_VOL_SENSORS
sensor,
coordinator,
volume,
)
for sensor_type, sensor in STORAGE_VOL_SENSORS.items()
] ]
)
# Handle all disks # Handle all disks
if api.storage.disks_ids: if api.storage.disks_ids:
for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids): entities.extend(
entities += [ [
SynoDSMStorageSensor( SynoDSMStorageSensor(api, coordinator, description, disk)
api, for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids)
sensor_type, for description in STORAGE_DISK_SENSORS
sensor, ]
coordinator,
disk,
) )
for sensor_type, sensor in STORAGE_DISK_SENSORS.items()
]
entities += [ entities.extend(
SynoDSMInfoSensor(api, sensor_type, sensor, coordinator) [
for sensor_type, sensor in INFORMATION_SENSORS.items() SynoDSMInfoSensor(api, coordinator, description)
for description in INFORMATION_SENSORS
] ]
)
async_add_entities(entities) async_add_entities(entities)
class SynoDSMSensor(SynologyDSMBaseEntity): class SynoDSMSensor(SynologyDSMBaseEntity, SensorEntity):
"""Mixin for sensor specific attributes.""" """Mixin for sensor specific attributes."""
@property entity_description: SynologyDSMSensorEntityDescription
def native_unit_of_measurement(self) -> str | None:
"""Return the unit the value is expressed in.""" def __init__(
return self._unit self,
api: SynoApi,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMSensorEntityDescription,
) -> None:
"""Initialize the Synology DSM sensor entity."""
super().__init__(api, coordinator, description)
class SynoDSMUtilSensor(SynoDSMSensor, SensorEntity): class SynoDSMUtilSensor(SynoDSMSensor):
"""Representation a Synology Utilisation sensor.""" """Representation a Synology Utilisation sensor."""
@property @property
def native_value(self) -> Any | None: def native_value(self) -> Any | None:
"""Return the state.""" """Return the state."""
attr = getattr(self._api.utilisation, self.entity_type) attr = getattr(self._api.utilisation, self.entity_description.key)
if callable(attr): if callable(attr):
attr = attr() attr = attr()
if attr is None: if attr is None:
return None return None
# Data (RAM) # Data (RAM)
if self._unit == DATA_MEGABYTES: if self.native_unit_of_measurement == DATA_MEGABYTES:
return round(attr / 1024.0 ** 2, 1) return round(attr / 1024.0 ** 2, 1)
# Network # Network
if self._unit == DATA_RATE_KILOBYTES_PER_SECOND: if self.native_unit_of_measurement == DATA_RATE_KILOBYTES_PER_SECOND:
return round(attr / 1024.0, 1) return round(attr / 1024.0, 1)
# CPU load average # CPU load average
if self._unit == ENTITY_UNIT_LOAD: if self.native_unit_of_measurement == ENTITY_UNIT_LOAD:
return round(attr / 100, 2) return round(attr / 100, 2)
return attr return attr
@ -123,46 +123,57 @@ class SynoDSMUtilSensor(SynoDSMSensor, SensorEntity):
return bool(self._api.utilisation) return bool(self._api.utilisation)
class SynoDSMStorageSensor(SynologyDSMDeviceEntity, SynoDSMSensor, SensorEntity): class SynoDSMStorageSensor(SynologyDSMDeviceEntity, SynoDSMSensor):
"""Representation a Synology Storage sensor.""" """Representation a Synology Storage sensor."""
entity_description: SynologyDSMSensorEntityDescription
def __init__(
self,
api: SynoApi,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMSensorEntityDescription,
device_id: str | None = None,
) -> None:
"""Initialize the Synology DSM storage sensor entity."""
super().__init__(api, coordinator, description, device_id)
@property @property
def native_value(self) -> Any | None: def native_value(self) -> Any | None:
"""Return the state.""" """Return the state."""
attr = getattr(self._api.storage, self.entity_type)(self._device_id) attr = getattr(self._api.storage, self.entity_description.key)(self._device_id)
if attr is None: if attr is None:
return None return None
# Data (disk space) # Data (disk space)
if self._unit == DATA_TERABYTES: if self.native_unit_of_measurement == DATA_TERABYTES:
return round(attr / 1024.0 ** 4, 2) return round(attr / 1024.0 ** 4, 2)
return attr return attr
class SynoDSMInfoSensor(SynoDSMSensor, SensorEntity): class SynoDSMInfoSensor(SynoDSMSensor):
"""Representation a Synology information sensor.""" """Representation a Synology information sensor."""
def __init__( def __init__(
self, self,
api: SynoApi, api: SynoApi,
entity_type: str,
entity_info: EntityInfo,
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]], coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
description: SynologyDSMSensorEntityDescription,
) -> None: ) -> None:
"""Initialize the Synology SynoDSMInfoSensor entity.""" """Initialize the Synology SynoDSMInfoSensor entity."""
super().__init__(api, entity_type, entity_info, coordinator) super().__init__(api, coordinator, description)
self._previous_uptime: str | None = None self._previous_uptime: str | None = None
self._last_boot: str | None = None self._last_boot: str | None = None
@property @property
def native_value(self) -> Any | None: def native_value(self) -> Any | None:
"""Return the state.""" """Return the state."""
attr = getattr(self._api.information, self.entity_type) attr = getattr(self._api.information, self.entity_description.key)
if attr is None: if attr is None:
return None return None
if self.entity_type == "uptime": if self.entity_description.key == "uptime":
# reboot happened or entity creation # reboot happened or entity creation
if self._previous_uptime is None or self._previous_uptime > attr: if self._previous_uptime is None or self._previous_uptime > attr:
last_boot = utcnow() - timedelta(seconds=attr) last_boot = utcnow() - timedelta(seconds=attr)

View File

@ -19,7 +19,7 @@ from .const import (
DOMAIN, DOMAIN,
SURVEILLANCE_SWITCH, SURVEILLANCE_SWITCH,
SYNO_API, SYNO_API,
EntityInfo, SynologyDSMSwitchEntityDescription,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -42,12 +42,14 @@ async def async_setup_entry(
# initial data fetch # initial data fetch
coordinator: DataUpdateCoordinator = data[COORDINATOR_SWITCHES] coordinator: DataUpdateCoordinator = data[COORDINATOR_SWITCHES]
await coordinator.async_refresh() await coordinator.async_refresh()
entities += [ entities.extend(
[
SynoDSMSurveillanceHomeModeToggle( SynoDSMSurveillanceHomeModeToggle(
api, sensor_type, switch, version, coordinator api, version, coordinator, description
) )
for sensor_type, switch in SURVEILLANCE_SWITCH.items() for description in SURVEILLANCE_SWITCH
] ]
)
async_add_entities(entities, True) async_add_entities(entities, True)
@ -56,28 +58,23 @@ class SynoDSMSurveillanceHomeModeToggle(SynologyDSMBaseEntity, ToggleEntity):
"""Representation a Synology Surveillance Station Home Mode toggle.""" """Representation a Synology Surveillance Station Home Mode toggle."""
coordinator: DataUpdateCoordinator[dict[str, dict[str, bool]]] coordinator: DataUpdateCoordinator[dict[str, dict[str, bool]]]
entity_description: SynologyDSMSwitchEntityDescription
def __init__( def __init__(
self, self,
api: SynoApi, api: SynoApi,
entity_type: str,
entity_info: EntityInfo,
version: str, version: str,
coordinator: DataUpdateCoordinator[dict[str, dict[str, bool]]], coordinator: DataUpdateCoordinator[dict[str, dict[str, bool]]],
description: SynologyDSMSwitchEntityDescription,
) -> None: ) -> None:
"""Initialize a Synology Surveillance Station Home Mode.""" """Initialize a Synology Surveillance Station Home Mode."""
super().__init__( super().__init__(api, coordinator, description)
api,
entity_type,
entity_info,
coordinator,
)
self._version = version self._version = version
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
"""Return the state.""" """Return the state."""
return self.coordinator.data["switches"][self.entity_type] return self.coordinator.data["switches"][self.entity_description.key]
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on Home mode.""" """Turn on Home mode."""