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

View File

@ -1,11 +1,14 @@
"""Support for Synology DSM binary sensors."""
from __future__ import annotations
from typing import Any
from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_DISKS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import SynoApi, SynologyDSMBaseEntity, SynologyDSMDeviceEntity
from .const import (
@ -15,6 +18,7 @@ from .const import (
STORAGE_DISK_BINARY_SENSORS,
SYNO_API,
UPGRADE_BINARY_SENSORS,
SynologyDSMBinarySensorEntityDescription,
)
@ -32,39 +36,52 @@ async def async_setup_entry(
| SynoDSMUpgradeBinarySensor
| SynoDSMStorageBinarySensor
] = [
SynoDSMSecurityBinarySensor(api, sensor_type, sensor, coordinator)
for sensor_type, sensor in SECURITY_BINARY_SENSORS.items()
SynoDSMSecurityBinarySensor(api, coordinator, description)
for description in SECURITY_BINARY_SENSORS
]
entities += [
SynoDSMUpgradeBinarySensor(api, sensor_type, sensor, coordinator)
for sensor_type, sensor in UPGRADE_BINARY_SENSORS.items()
]
entities.extend(
[
SynoDSMUpgradeBinarySensor(api, coordinator, description)
for description in UPGRADE_BINARY_SENSORS
]
)
# Handle all disks
if api.storage.disks_ids:
for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids):
entities += [
SynoDSMStorageBinarySensor(
api,
sensor_type,
sensor,
coordinator,
disk,
)
for sensor_type, sensor in STORAGE_DISK_BINARY_SENSORS.items()
entities.extend(
[
SynoDSMStorageBinarySensor(api, coordinator, description, disk)
for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids)
for description in STORAGE_DISK_BINARY_SENSORS
]
)
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."""
@property
def is_on(self) -> bool:
"""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
def available(self) -> bool:
@ -77,22 +94,36 @@ class SynoDSMSecurityBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
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."""
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
def is_on(self) -> bool:
"""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."""
@property
def is_on(self) -> bool:
"""Return the state."""
return bool(getattr(self._api.upgrade, self.entity_type))
return bool(getattr(self._api.upgrade, self.entity_description.key))
@property
def available(self) -> bool:

View File

@ -1,6 +1,7 @@
"""Support for Synology DSM cameras."""
from __future__ import annotations
from dataclasses import dataclass
import logging
from synology_dsm.api.surveillance_station import SynoCamera, SynoSurveillanceStation
@ -9,26 +10,30 @@ from synology_dsm.exceptions import (
SynologyDSMRequestException,
)
from homeassistant.components.camera import SUPPORT_STREAM, Camera
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
from homeassistant.components.camera import (
SUPPORT_STREAM,
Camera,
CameraEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
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__)
@dataclass
class SynologyDSMCameraEntityDescription(
CameraEntityDescription, SynologyDSMEntityDescription
):
"""Describes Synology DSM camera entity."""
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
@ -56,6 +61,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"""Representation a Synology camera."""
coordinator: DataUpdateCoordinator[dict[str, dict[str, SynoCamera]]]
entity_description: SynologyDSMCameraEntityDescription
def __init__(
self,
@ -64,26 +70,21 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
camera_id: str,
) -> None:
"""Initialize a Synology camera."""
super().__init__(
api,
f"{SynoSurveillanceStation.CAMERA_API_KEY}:{camera_id}",
{
ATTR_NAME: coordinator.data["cameras"][camera_id].name,
ENTITY_ENABLE: coordinator.data["cameras"][camera_id].is_enabled,
ATTR_DEVICE_CLASS: None,
ATTR_ICON: None,
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_STATE_CLASS: None,
},
coordinator,
description = SynologyDSMCameraEntityDescription(
api_key=SynoSurveillanceStation.CAMERA_API_KEY,
key=camera_id,
name=coordinator.data["cameras"][camera_id].name,
entity_registry_enabled_default=coordinator.data["cameras"][
camera_id
].is_enabled,
)
super().__init__(api, coordinator, description)
Camera.__init__(self)
self._camera_id = camera_id
@property
def camera_data(self) -> SynoCamera:
"""Camera data."""
return self.coordinator.data["cameras"][self._camera_id]
return self.coordinator.data["cameras"][self.entity_description.key]
@property
def device_info(self) -> DeviceInfo:
@ -134,7 +135,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
if not self.available:
return None
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 (
SynologyDSMAPIErrorException,
SynologyDSMRequestException,
@ -163,7 +164,9 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"SynoDSMCamera.enable_motion_detection(%s)",
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:
"""Disable motion detection in camera."""
@ -171,4 +174,6 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
"SynoDSMCamera.disable_motion_detection(%s)",
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."""
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.upgrade import SynoCoreUpgrade
@ -13,13 +13,14 @@ from synology_dsm.api.surveillance_station import SynoSurveillanceStation
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_SAFETY,
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 (
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
DATA_MEGABYTES,
DATA_RATE_KILOBYTES_PER_SECOND,
DATA_TERABYTES,
@ -28,18 +29,7 @@ from homeassistant.const import (
PERCENTAGE,
TEMP_CELSIUS,
)
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
from homeassistant.helpers.entity import EntityDescription
DOMAIN = "synology_dsm"
PLATFORMS = ["binary_sensor", "camera", "sensor", "switch"]
@ -68,7 +58,6 @@ DEFAULT_SCAN_INTERVAL = 15 # min
DEFAULT_TIMEOUT = 10 # sec
ENTITY_UNIT_LOAD = "load"
ENTITY_ENABLE: Final = "enable"
# Services
SERVICE_REBOOT = "reboot"
@ -78,285 +67,302 @@ SERVICES = [
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
UPGRADE_BINARY_SENSORS: dict[str, EntityInfo] = {
f"{SynoCoreUpgrade.API_KEY}:update_available": {
ATTR_NAME: "Update available",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_UPDATE,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
}
UPGRADE_BINARY_SENSORS: tuple[SynologyDSMBinarySensorEntityDescription, ...] = (
SynologyDSMBinarySensorEntityDescription(
api_key=SynoCoreUpgrade.API_KEY,
key="update_available",
name="Update available",
device_class=DEVICE_CLASS_UPDATE,
),
)
SECURITY_BINARY_SENSORS: dict[str, EntityInfo] = {
f"{SynoCoreSecurity.API_KEY}:status": {
ATTR_NAME: "Security status",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_SAFETY,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
}
SECURITY_BINARY_SENSORS: tuple[SynologyDSMBinarySensorEntityDescription, ...] = (
SynologyDSMBinarySensorEntityDescription(
api_key=SynoCoreSecurity.API_KEY,
key="status",
name="Security status",
device_class=DEVICE_CLASS_SAFETY,
),
)
STORAGE_DISK_BINARY_SENSORS: dict[str, EntityInfo] = {
f"{SynoStorage.API_KEY}:disk_exceed_bad_sector_thr": {
ATTR_NAME: "Exceeded Max Bad Sectors",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_SAFETY,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoStorage.API_KEY}:disk_below_remain_life_thr": {
ATTR_NAME: "Below Min Remaining Life",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_SAFETY,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
}
STORAGE_DISK_BINARY_SENSORS: tuple[SynologyDSMBinarySensorEntityDescription, ...] = (
SynologyDSMBinarySensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="disk_exceed_bad_sector_thr",
name="Exceeded Max Bad Sectors",
device_class=DEVICE_CLASS_SAFETY,
),
SynologyDSMBinarySensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="disk_below_remain_life_thr",
name="Below Min Remaining Life",
device_class=DEVICE_CLASS_SAFETY,
),
)
# Sensors
UTILISATION_SENSORS: dict[str, EntityInfo] = {
f"{SynoCoreUtilization.API_KEY}:cpu_other_load": {
ATTR_NAME: "CPU Utilization (Other)",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:cpu_user_load": {
ATTR_NAME: "CPU Utilization (User)",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:cpu_system_load": {
ATTR_NAME: "CPU Utilization (System)",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:cpu_total_load": {
ATTR_NAME: "CPU Utilization (Total)",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:cpu_1min_load": {
ATTR_NAME: "CPU Load Average (1 min)",
ATTR_UNIT_OF_MEASUREMENT: ENTITY_UNIT_LOAD,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: None,
},
f"{SynoCoreUtilization.API_KEY}:cpu_5min_load": {
ATTR_NAME: "CPU Load Average (5 min)",
ATTR_UNIT_OF_MEASUREMENT: ENTITY_UNIT_LOAD,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoCoreUtilization.API_KEY}:cpu_15min_load": {
ATTR_NAME: "CPU Load Average (15 min)",
ATTR_UNIT_OF_MEASUREMENT: ENTITY_UNIT_LOAD,
ATTR_ICON: "mdi:chip",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoCoreUtilization.API_KEY}:memory_real_usage": {
ATTR_NAME: "Memory Usage (Real)",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:memory_size": {
ATTR_NAME: "Memory Size",
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:memory_cached": {
ATTR_NAME: "Memory Cached",
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:memory_available_swap": {
ATTR_NAME: "Memory Available (Swap)",
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:memory_available_real": {
ATTR_NAME: "Memory Available (Real)",
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:memory_total_swap": {
ATTR_NAME: "Memory Total (Swap)",
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:memory_total_real": {
ATTR_NAME: "Memory Total (Real)",
ATTR_UNIT_OF_MEASUREMENT: DATA_MEGABYTES,
ATTR_ICON: "mdi:memory",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:network_up": {
ATTR_NAME: "Upload Throughput",
ATTR_UNIT_OF_MEASUREMENT: DATA_RATE_KILOBYTES_PER_SECOND,
ATTR_ICON: "mdi:upload",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoCoreUtilization.API_KEY}:network_down": {
ATTR_NAME: "Download Throughput",
ATTR_UNIT_OF_MEASUREMENT: DATA_RATE_KILOBYTES_PER_SECOND,
ATTR_ICON: "mdi:download",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
}
STORAGE_VOL_SENSORS: dict[str, EntityInfo] = {
f"{SynoStorage.API_KEY}:volume_status": {
ATTR_NAME: "Status",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: "mdi:checkbox-marked-circle-outline",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoStorage.API_KEY}:volume_size_total": {
ATTR_NAME: "Total Size",
ATTR_UNIT_OF_MEASUREMENT: DATA_TERABYTES,
ATTR_ICON: "mdi:chart-pie",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoStorage.API_KEY}:volume_size_used": {
ATTR_NAME: "Used Space",
ATTR_UNIT_OF_MEASUREMENT: DATA_TERABYTES,
ATTR_ICON: "mdi:chart-pie",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoStorage.API_KEY}:volume_percentage_used": {
ATTR_NAME: "Volume Used",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_ICON: "mdi:chart-pie",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoStorage.API_KEY}:volume_disk_temp_avg": {
ATTR_NAME: "Average Disk Temp",
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoStorage.API_KEY}:volume_disk_temp_max": {
ATTR_NAME: "Maximum Disk Temp",
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: None,
},
}
STORAGE_DISK_SENSORS: dict[str, EntityInfo] = {
f"{SynoStorage.API_KEY}:disk_smart_status": {
ATTR_NAME: "Status (Smart)",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: "mdi:checkbox-marked-circle-outline",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: None,
},
f"{SynoStorage.API_KEY}:disk_status": {
ATTR_NAME: "Status",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: "mdi:checkbox-marked-circle-outline",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
f"{SynoStorage.API_KEY}:disk_temp": {
ATTR_NAME: "Temperature",
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
}
UTILISATION_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_other_load",
name="CPU Utilization (Other)",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:chip",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_user_load",
name="CPU Utilization (User)",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:chip",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_system_load",
name="CPU Utilization (System)",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:chip",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_total_load",
name="CPU Utilization (Total)",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:chip",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_1min_load",
name="CPU Load Average (1 min)",
native_unit_of_measurement=ENTITY_UNIT_LOAD,
icon="mdi:chip",
entity_registry_enabled_default=False,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_5min_load",
name="CPU Load Average (5 min)",
native_unit_of_measurement=ENTITY_UNIT_LOAD,
icon="mdi:chip",
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="cpu_15min_load",
name="CPU Load Average (15 min)",
native_unit_of_measurement=ENTITY_UNIT_LOAD,
icon="mdi:chip",
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_real_usage",
name="Memory Usage (Real)",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:memory",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_size",
name="Memory Size",
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:memory",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_cached",
name="Memory Cached",
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:memory",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_available_swap",
name="Memory Available (Swap)",
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:memory",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_available_real",
name="Memory Available (Real)",
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:memory",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_total_swap",
name="Memory Total (Swap)",
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:memory",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="memory_total_real",
name="Memory Total (Real)",
native_unit_of_measurement=DATA_MEGABYTES,
icon="mdi:memory",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="network_up",
name="Upload Throughput",
native_unit_of_measurement=DATA_RATE_KILOBYTES_PER_SECOND,
icon="mdi:upload",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoCoreUtilization.API_KEY,
key="network_down",
name="Download Throughput",
native_unit_of_measurement=DATA_RATE_KILOBYTES_PER_SECOND,
icon="mdi:download",
state_class=STATE_CLASS_MEASUREMENT,
),
)
STORAGE_VOL_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="volume_status",
name="Status",
icon="mdi:checkbox-marked-circle-outline",
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="volume_size_total",
name="Total Size",
native_unit_of_measurement=DATA_TERABYTES,
icon="mdi:chart-pie",
entity_registry_enabled_default=False,
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="volume_size_used",
name="Used Space",
native_unit_of_measurement=DATA_TERABYTES,
icon="mdi:chart-pie",
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="volume_percentage_used",
name="Volume Used",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:chart-pie",
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="volume_disk_temp_avg",
name="Average Disk Temp",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="volume_disk_temp_max",
name="Maximum Disk Temp",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
entity_registry_enabled_default=False,
),
)
STORAGE_DISK_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="disk_smart_status",
name="Status (Smart)",
icon="mdi:checkbox-marked-circle-outline",
entity_registry_enabled_default=False,
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="disk_status",
name="Status",
icon="mdi:checkbox-marked-circle-outline",
),
SynologyDSMSensorEntityDescription(
api_key=SynoStorage.API_KEY,
key="disk_temp",
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
)
INFORMATION_SENSORS: dict[str, EntityInfo] = {
f"{SynoDSMInformation.API_KEY}:temperature": {
ATTR_NAME: "temperature",
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
f"{SynoDSMInformation.API_KEY}:uptime": {
ATTR_NAME: "last boot",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP,
ENTITY_ENABLE: False,
ATTR_STATE_CLASS: None,
},
}
INFORMATION_SENSORS: tuple[SynologyDSMSensorEntityDescription, ...] = (
SynologyDSMSensorEntityDescription(
api_key=SynoDSMInformation.API_KEY,
key="temperature",
name="temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SynologyDSMSensorEntityDescription(
api_key=SynoDSMInformation.API_KEY,
key="uptime",
name="last boot",
device_class=DEVICE_CLASS_TIMESTAMP,
entity_registry_enabled_default=False,
),
)
# Switch
SURVEILLANCE_SWITCH: dict[str, EntityInfo] = {
f"{SynoSurveillanceStation.HOME_MODE_API_KEY}:home_mode": {
ATTR_NAME: "home mode",
ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_ICON: "mdi:home-account",
ATTR_DEVICE_CLASS: None,
ENTITY_ENABLE: True,
ATTR_STATE_CLASS: None,
},
}
SURVEILLANCE_SWITCH: tuple[SynologyDSMSwitchEntityDescription, ...] = (
SynologyDSMSwitchEntityDescription(
api_key=SynoSurveillanceStation.HOME_MODE_API_KEY,
key="home_mode",
name="home mode",
icon="mdi:home-account",
),
)

View File

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

View File

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