core/homeassistant/components/synology_dsm/sensor.py

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),
}