200 lines
5.9 KiB
Python
200 lines
5.9 KiB
Python
"""Support for Synology DSM Sensors."""
|
|
from typing import Dict
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import (
|
|
ATTR_ATTRIBUTION,
|
|
CONF_DISKS,
|
|
DATA_MEGABYTES,
|
|
DATA_RATE_KILOBYTES_PER_SECOND,
|
|
TEMP_CELSIUS,
|
|
)
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|
from homeassistant.helpers.entity import Entity
|
|
from homeassistant.helpers.typing import HomeAssistantType
|
|
|
|
from . import SynoApi
|
|
from .const import (
|
|
BASE_NAME,
|
|
CONF_VOLUMES,
|
|
DOMAIN,
|
|
STORAGE_DISK_SENSORS,
|
|
STORAGE_VOL_SENSORS,
|
|
TEMP_SENSORS_KEYS,
|
|
UTILISATION_SENSORS,
|
|
)
|
|
|
|
ATTRIBUTION = "Data provided by Synology"
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
|
|
) -> None:
|
|
"""Set up the Synology NAS Sensor."""
|
|
|
|
api = hass.data[DOMAIN][entry.unique_id]
|
|
|
|
sensors = [
|
|
SynoNasUtilSensor(api, sensor_type, UTILISATION_SENSORS[sensor_type])
|
|
for sensor_type in UTILISATION_SENSORS
|
|
]
|
|
|
|
# Handle all volumes
|
|
if api.storage.volumes_ids:
|
|
for volume in entry.data.get(CONF_VOLUMES, api.storage.volumes_ids):
|
|
sensors += [
|
|
SynoNasStorageSensor(
|
|
api, sensor_type, STORAGE_VOL_SENSORS[sensor_type], volume
|
|
)
|
|
for sensor_type in STORAGE_VOL_SENSORS
|
|
]
|
|
|
|
# Handle all disks
|
|
if api.storage.disks_ids:
|
|
for disk in entry.data.get(CONF_DISKS, api.storage.disks_ids):
|
|
sensors += [
|
|
SynoNasStorageSensor(
|
|
api, sensor_type, STORAGE_DISK_SENSORS[sensor_type], disk
|
|
)
|
|
for sensor_type in STORAGE_DISK_SENSORS
|
|
]
|
|
|
|
async_add_entities(sensors, True)
|
|
|
|
|
|
class SynoNasSensor(Entity):
|
|
"""Representation of a Synology NAS Sensor."""
|
|
|
|
def __init__(
|
|
self,
|
|
api: SynoApi,
|
|
sensor_type: str,
|
|
sensor_info: Dict[str, str],
|
|
monitored_device: str = None,
|
|
):
|
|
"""Initialize the sensor."""
|
|
self._api = api
|
|
self.sensor_type = sensor_type
|
|
self._name = f"{BASE_NAME} {sensor_info[0]}"
|
|
self._unit = sensor_info[1]
|
|
self._icon = sensor_info[2]
|
|
self.monitored_device = monitored_device
|
|
self._unique_id = f"{self._api.information.serial}_{sensor_info[0]}"
|
|
|
|
if self.monitored_device:
|
|
self._name += f" ({self.monitored_device})"
|
|
self._unique_id += f"_{self.monitored_device}"
|
|
|
|
self._unsub_dispatcher = None
|
|
|
|
@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:
|
|
"""Return the icon."""
|
|
return self._icon
|
|
|
|
@property
|
|
def unit_of_measurement(self) -> str:
|
|
"""Return the unit the value is expressed in."""
|
|
if self.sensor_type in TEMP_SENSORS_KEYS:
|
|
return self._api.temp_unit
|
|
return self._unit
|
|
|
|
@property
|
|
def device_state_attributes(self) -> Dict[str, any]:
|
|
"""Return the state attributes."""
|
|
return {ATTR_ATTRIBUTION: ATTRIBUTION}
|
|
|
|
@property
|
|
def device_info(self) -> Dict[str, any]:
|
|
"""Return the device information."""
|
|
return {
|
|
"identifiers": {(DOMAIN, self._api.information.serial)},
|
|
"name": "Synology NAS",
|
|
"manufacturer": "Synology",
|
|
"model": self._api.information.model,
|
|
"sw_version": self._api.information.version_string,
|
|
}
|
|
|
|
@property
|
|
def should_poll(self) -> bool:
|
|
"""No polling needed."""
|
|
return False
|
|
|
|
async def async_added_to_hass(self):
|
|
"""Register state update callback."""
|
|
self._unsub_dispatcher = async_dispatcher_connect(
|
|
self.hass, self._api.signal_sensor_update, self.async_write_ha_state
|
|
)
|
|
|
|
async def async_will_remove_from_hass(self):
|
|
"""Clean up after entity before removal."""
|
|
self._unsub_dispatcher()
|
|
|
|
|
|
class SynoNasUtilSensor(SynoNasSensor):
|
|
"""Representation a Synology Utilisation Sensor."""
|
|
|
|
@property
|
|
def state(self):
|
|
"""Return the state."""
|
|
if self._unit == DATA_RATE_KILOBYTES_PER_SECOND or self._unit == DATA_MEGABYTES:
|
|
attr = getattr(self._api.utilisation, self.sensor_type)(False)
|
|
|
|
if attr is None:
|
|
return None
|
|
|
|
if self._unit == DATA_RATE_KILOBYTES_PER_SECOND:
|
|
return round(attr / 1024.0, 1)
|
|
if self._unit == DATA_MEGABYTES:
|
|
return round(attr / 1024.0 / 1024.0, 1)
|
|
else:
|
|
return getattr(self._api.utilisation, self.sensor_type)
|
|
|
|
|
|
class SynoNasStorageSensor(SynoNasSensor):
|
|
"""Representation a Synology Storage Sensor."""
|
|
|
|
@property
|
|
def state(self):
|
|
"""Return the state."""
|
|
if self.monitored_device:
|
|
if self.sensor_type in TEMP_SENSORS_KEYS:
|
|
attr = getattr(self._api.storage, self.sensor_type)(
|
|
self.monitored_device
|
|
)
|
|
|
|
if attr is None:
|
|
return None
|
|
|
|
if self._api.temp_unit == TEMP_CELSIUS:
|
|
return attr
|
|
|
|
return round(attr * 1.8 + 32.0, 1)
|
|
|
|
return getattr(self._api.storage, self.sensor_type)(self.monitored_device)
|
|
return None
|
|
|
|
@property
|
|
def device_info(self) -> Dict[str, any]:
|
|
"""Return the device information."""
|
|
return {
|
|
"identifiers": {
|
|
(DOMAIN, self._api.information.serial, self.monitored_device)
|
|
},
|
|
"name": f"Synology NAS ({self.monitored_device})",
|
|
"manufacturer": "Synology",
|
|
"model": self._api.information.model,
|
|
"sw_version": self._api.information.version_string,
|
|
"via_device": (DOMAIN, self._api.information.serial),
|
|
}
|