Improve typing for synology_dsm (#49656)
parent
717f4e69d5
commit
042822e35e
|
@ -40,6 +40,7 @@ homeassistant.components.slack.*
|
|||
homeassistant.components.sonos.media_player
|
||||
homeassistant.components.sun.*
|
||||
homeassistant.components.switch.*
|
||||
homeassistant.components.synology_dsm.*
|
||||
homeassistant.components.systemmonitor.*
|
||||
homeassistant.components.tts.*
|
||||
homeassistant.components.vacuum.*
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
from typing import Any, Callable
|
||||
|
||||
import async_timeout
|
||||
from synology_dsm import SynologyDSM
|
||||
|
@ -15,6 +15,7 @@ from synology_dsm.api.dsm.information import SynoDSMInformation
|
|||
from synology_dsm.api.dsm.network import SynoDSMNetwork
|
||||
from synology_dsm.api.storage.storage import SynoStorage
|
||||
from synology_dsm.api.surveillance_station import SynoSurveillanceStation
|
||||
from synology_dsm.api.surveillance_station.camera import SynoCamera
|
||||
from synology_dsm.exceptions import (
|
||||
SynologyDSMAPIErrorException,
|
||||
SynologyDSMLoginFailedException,
|
||||
|
@ -38,9 +39,14 @@ from homeassistant.const import (
|
|||
)
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers import device_registry, entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.device_registry import (
|
||||
DeviceEntry,
|
||||
async_get_registry as get_dev_reg,
|
||||
)
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
|
@ -74,6 +80,7 @@ from .const import (
|
|||
SYSTEM_LOADED,
|
||||
UNDO_UPDATE_LISTENER,
|
||||
UTILISATION_SENSORS,
|
||||
EntityInfo,
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
|
@ -103,7 +110,7 @@ ATTRIBUTION = "Data provided by Synology"
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up Synology DSM sensors from legacy config file."""
|
||||
|
||||
conf = config.get(DOMAIN)
|
||||
|
@ -122,12 +129,16 @@ async def async_setup(hass, config):
|
|||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def async_setup_entry( # noqa: C901
|
||||
hass: HomeAssistant, entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up Synology DSM sensors."""
|
||||
|
||||
# Migrate old unique_id
|
||||
@callback
|
||||
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
||||
def _async_migrator(
|
||||
entity_entry: entity_registry.RegistryEntry,
|
||||
) -> dict[str, str] | None:
|
||||
"""Migrate away from ID using label."""
|
||||
# Reject if new unique_id
|
||||
if "SYNO." in entity_entry.unique_id:
|
||||
|
@ -152,7 +163,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
):
|
||||
return None
|
||||
|
||||
entity_type = None
|
||||
entity_type: str | None = None
|
||||
for entity_key, entity_attrs in entries.items():
|
||||
if (
|
||||
device_id
|
||||
|
@ -170,6 +181,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
if entity_attrs[ENTITY_NAME] == label:
|
||||
entity_type = entity_key
|
||||
|
||||
if entity_type is None:
|
||||
return None
|
||||
|
||||
new_unique_id = "_".join([serial, entity_type])
|
||||
if device_id:
|
||||
new_unique_id += f"_{device_id}"
|
||||
|
@ -183,6 +197,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
|
||||
await entity_registry.async_migrate_entries(hass, entry.entry_id, _async_migrator)
|
||||
|
||||
# migrate device indetifiers
|
||||
dev_reg = await get_dev_reg(hass)
|
||||
devices: list[DeviceEntry] = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, entry.entry_id
|
||||
)
|
||||
for device in devices:
|
||||
old_identifier = list(next(iter(device.identifiers)))
|
||||
if len(old_identifier) > 2:
|
||||
new_identifier: set[tuple[str, ...]] = {
|
||||
(old_identifier.pop(0), "_".join([str(x) for x in old_identifier]))
|
||||
}
|
||||
_LOGGER.debug(
|
||||
"migrate identifier '%s' to '%s'", device.identifiers, new_identifier
|
||||
)
|
||||
dev_reg.async_update_device(device.id, new_identifiers=new_identifier)
|
||||
|
||||
# Migrate existing entry configuration
|
||||
if entry.data.get(CONF_VERIFY_SSL) is None:
|
||||
hass.config_entries.async_update_entry(
|
||||
|
@ -216,7 +246,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
entry, data={**entry.data, CONF_MAC: network.macs}
|
||||
)
|
||||
|
||||
async def async_coordinator_update_data_cameras():
|
||||
async def async_coordinator_update_data_cameras() -> dict[
|
||||
str, dict[str, SynoCamera]
|
||||
] | None:
|
||||
"""Fetch all camera data from api."""
|
||||
if not hass.data[DOMAIN][entry.unique_id][SYSTEM_LOADED]:
|
||||
raise UpdateFailed("System not fully loaded")
|
||||
|
@ -238,7 +270,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
}
|
||||
}
|
||||
|
||||
async def async_coordinator_update_data_central():
|
||||
async def async_coordinator_update_data_central() -> None:
|
||||
"""Fetch all device and sensor data from api."""
|
||||
try:
|
||||
await api.async_update()
|
||||
|
@ -246,7 +278,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
raise UpdateFailed(f"Error communicating with API: {err}") from err
|
||||
return None
|
||||
|
||||
async def async_coordinator_update_data_switches():
|
||||
async def async_coordinator_update_data_switches() -> dict[
|
||||
str, dict[str, Any]
|
||||
] | None:
|
||||
"""Fetch all switch data from api."""
|
||||
if not hass.data[DOMAIN][entry.unique_id][SYSTEM_LOADED]:
|
||||
raise UpdateFailed("System not fully loaded")
|
||||
|
@ -294,7 +328,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload Synology DSM sensors."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if unload_ok:
|
||||
|
@ -306,15 +340,15 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
return unload_ok
|
||||
|
||||
|
||||
async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Handle options update."""
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
|
||||
|
||||
async def _async_setup_services(hass: HomeAssistant):
|
||||
async def _async_setup_services(hass: HomeAssistant) -> None:
|
||||
"""Service handler setup."""
|
||||
|
||||
async def service_handler(call: ServiceCall):
|
||||
async def service_handler(call: ServiceCall) -> None:
|
||||
"""Handle service call."""
|
||||
serial = call.data.get(CONF_SERIAL)
|
||||
dsm_devices = hass.data[DOMAIN]
|
||||
|
@ -350,7 +384,7 @@ async def _async_setup_services(hass: HomeAssistant):
|
|||
class SynoApi:
|
||||
"""Class to interface with Synology DSM API."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, entry: ConfigEntry):
|
||||
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Initialize the API wrapper class."""
|
||||
self._hass = hass
|
||||
self._entry = entry
|
||||
|
@ -367,7 +401,7 @@ class SynoApi:
|
|||
self.utilisation: SynoCoreUtilization = None
|
||||
|
||||
# Should we fetch them
|
||||
self._fetching_entities = {}
|
||||
self._fetching_entities: dict[str, set[str]] = {}
|
||||
self._with_information = True
|
||||
self._with_security = True
|
||||
self._with_storage = True
|
||||
|
@ -376,7 +410,7 @@ class SynoApi:
|
|||
self._with_upgrade = True
|
||||
self._with_utilisation = True
|
||||
|
||||
async def async_setup(self):
|
||||
async def async_setup(self) -> None:
|
||||
"""Start interacting with the NAS."""
|
||||
self.dsm = SynologyDSM(
|
||||
self._entry.data[CONF_HOST],
|
||||
|
@ -406,7 +440,7 @@ class SynoApi:
|
|||
await self.async_update()
|
||||
|
||||
@callback
|
||||
def subscribe(self, api_key, unique_id):
|
||||
def subscribe(self, api_key: str, unique_id: str) -> Callable[[], None]:
|
||||
"""Subscribe an entity to API fetches."""
|
||||
_LOGGER.debug("Subscribe new entity: %s", unique_id)
|
||||
if api_key not in self._fetching_entities:
|
||||
|
@ -424,7 +458,7 @@ class SynoApi:
|
|||
return unsubscribe
|
||||
|
||||
@callback
|
||||
def _async_setup_api_requests(self):
|
||||
def _async_setup_api_requests(self) -> None:
|
||||
"""Determine if we should fetch each API, if one entity needs it."""
|
||||
# Entities not added yet, fetch all
|
||||
if not self._fetching_entities:
|
||||
|
@ -488,7 +522,7 @@ class SynoApi:
|
|||
self.dsm.reset(self.utilisation)
|
||||
self.utilisation = None
|
||||
|
||||
def _fetch_device_configuration(self):
|
||||
def _fetch_device_configuration(self) -> None:
|
||||
"""Fetch initial device config."""
|
||||
self.information = self.dsm.information
|
||||
self.network = self.dsm.network
|
||||
|
@ -523,7 +557,7 @@ class SynoApi:
|
|||
)
|
||||
self.surveillance_station = self.dsm.surveillance_station
|
||||
|
||||
async def async_reboot(self):
|
||||
async def async_reboot(self) -> None:
|
||||
"""Reboot NAS."""
|
||||
try:
|
||||
await self._hass.async_add_executor_job(self.system.reboot)
|
||||
|
@ -534,7 +568,7 @@ class SynoApi:
|
|||
)
|
||||
_LOGGER.debug("Exception:%s", err)
|
||||
|
||||
async def async_shutdown(self):
|
||||
async def async_shutdown(self) -> None:
|
||||
"""Shutdown NAS."""
|
||||
try:
|
||||
await self._hass.async_add_executor_job(self.system.shutdown)
|
||||
|
@ -545,7 +579,7 @@ class SynoApi:
|
|||
)
|
||||
_LOGGER.debug("Exception:%s", err)
|
||||
|
||||
async def async_unload(self):
|
||||
async def async_unload(self) -> None:
|
||||
"""Stop interacting with the NAS and prepare for removal from hass."""
|
||||
try:
|
||||
await self._hass.async_add_executor_job(self.dsm.logout)
|
||||
|
@ -554,7 +588,7 @@ class SynoApi:
|
|||
"Logout from '%s' not possible:%s", self._entry.unique_id, err
|
||||
)
|
||||
|
||||
async def async_update(self, now=None):
|
||||
async def async_update(self, now: timedelta | None = None) -> None:
|
||||
"""Update function for updating API information."""
|
||||
_LOGGER.debug("Start data update for '%s'", self._entry.unique_id)
|
||||
self._async_setup_api_requests()
|
||||
|
@ -582,9 +616,9 @@ class SynologyDSMBaseEntity(CoordinatorEntity):
|
|||
self,
|
||||
api: SynoApi,
|
||||
entity_type: str,
|
||||
entity_info: dict[str, str],
|
||||
coordinator: DataUpdateCoordinator,
|
||||
):
|
||||
entity_info: EntityInfo,
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
|
||||
) -> None:
|
||||
"""Initialize the Synology DSM entity."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
|
@ -609,12 +643,12 @@ class SynologyDSMBaseEntity(CoordinatorEntity):
|
|||
return self._name
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
def icon(self) -> str | None:
|
||||
"""Return the icon."""
|
||||
return self._icon
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
def device_class(self) -> str | None:
|
||||
"""Return the class of this device."""
|
||||
return self._class
|
||||
|
||||
|
@ -639,7 +673,7 @@ class SynologyDSMBaseEntity(CoordinatorEntity):
|
|||
"""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):
|
||||
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))
|
||||
await super().async_added_to_hass()
|
||||
|
@ -652,10 +686,10 @@ class SynologyDSMDeviceEntity(SynologyDSMBaseEntity):
|
|||
self,
|
||||
api: SynoApi,
|
||||
entity_type: str,
|
||||
entity_info: dict[str, str],
|
||||
coordinator: DataUpdateCoordinator,
|
||||
device_id: str = None,
|
||||
):
|
||||
entity_info: EntityInfo,
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
|
||||
device_id: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize the Synology DSM disk or volume entity."""
|
||||
super().__init__(api, entity_type, entity_info, coordinator)
|
||||
self._device_id = device_id
|
||||
|
@ -691,16 +725,18 @@ class SynologyDSMDeviceEntity(SynologyDSMBaseEntity):
|
|||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return True if entity is available."""
|
||||
return bool(self._api.storage)
|
||||
return self._api.storage # type: ignore [no-any-return]
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return the device information."""
|
||||
return {
|
||||
"identifiers": {(DOMAIN, self._api.information.serial, self._device_id)},
|
||||
"identifiers": {
|
||||
(DOMAIN, f"{self._api.information.serial}_{self._device_id}")
|
||||
},
|
||||
"name": f"Synology NAS ({self._device_name} - {self._device_type})",
|
||||
"manufacturer": self._device_manufacturer,
|
||||
"model": self._device_model,
|
||||
"sw_version": self._device_firmware,
|
||||
"manufacturer": self._device_manufacturer, # type: ignore[typeddict-item]
|
||||
"model": self._device_model, # type: ignore[typeddict-item]
|
||||
"sw_version": self._device_firmware, # type: ignore[typeddict-item]
|
||||
"via_device": (DOMAIN, self._api.information.serial),
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@ 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 . import SynologyDSMBaseEntity, SynologyDSMDeviceEntity
|
||||
from . import SynoApi, SynologyDSMBaseEntity, SynologyDSMDeviceEntity
|
||||
from .const import (
|
||||
COORDINATOR_CENTRAL,
|
||||
DOMAIN,
|
||||
|
@ -18,15 +19,19 @@ from .const import (
|
|||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the Synology NAS binary sensor."""
|
||||
|
||||
data = hass.data[DOMAIN][entry.unique_id]
|
||||
api = data[SYNO_API]
|
||||
api: SynoApi = data[SYNO_API]
|
||||
coordinator = data[COORDINATOR_CENTRAL]
|
||||
|
||||
entities = [
|
||||
entities: list[
|
||||
SynoDSMSecurityBinarySensor
|
||||
| SynoDSMUpgradeBinarySensor
|
||||
| SynoDSMStorageBinarySensor
|
||||
] = [
|
||||
SynoDSMSecurityBinarySensor(
|
||||
api, sensor_type, SECURITY_BINARY_SENSORS[sensor_type], coordinator
|
||||
)
|
||||
|
@ -63,7 +68,7 @@ class SynoDSMSecurityBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return the state."""
|
||||
return getattr(self._api.security, self.entity_type) != "safe"
|
||||
return getattr(self._api.security, self.entity_type) != "safe" # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
|
@ -73,7 +78,7 @@ class SynoDSMSecurityBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
|
|||
@property
|
||||
def extra_state_attributes(self) -> dict[str, str]:
|
||||
"""Return security checks details."""
|
||||
return self._api.security.status_by_check
|
||||
return self._api.security.status_by_check # type: ignore[no-any-return]
|
||||
|
||||
|
||||
class SynoDSMStorageBinarySensor(SynologyDSMDeviceEntity, BinarySensorEntity):
|
||||
|
@ -82,7 +87,7 @@ class SynoDSMStorageBinarySensor(SynologyDSMDeviceEntity, BinarySensorEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return the state."""
|
||||
return getattr(self._api.storage, self.entity_type)(self._device_id)
|
||||
return bool(getattr(self._api.storage, self.entity_type)(self._device_id))
|
||||
|
||||
|
||||
class SynoDSMUpgradeBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
|
||||
|
@ -91,7 +96,7 @@ class SynoDSMUpgradeBinarySensor(SynologyDSMBaseEntity, BinarySensorEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return the state."""
|
||||
return getattr(self._api.upgrade, self.entity_type)
|
||||
return bool(getattr(self._api.upgrade, self.entity_type))
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
|
||||
import logging
|
||||
|
||||
from synology_dsm.api.surveillance_station import SynoSurveillanceStation
|
||||
from synology_dsm.api.surveillance_station import SynoCamera, SynoSurveillanceStation
|
||||
from synology_dsm.exceptions import (
|
||||
SynologyDSMAPIErrorException,
|
||||
SynologyDSMRequestException,
|
||||
|
@ -13,6 +13,7 @@ from homeassistant.components.camera import SUPPORT_STREAM, Camera
|
|||
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
|
||||
|
@ -31,19 +32,21 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the Synology NAS cameras."""
|
||||
|
||||
data = hass.data[DOMAIN][entry.unique_id]
|
||||
api = data[SYNO_API]
|
||||
api: SynoApi = data[SYNO_API]
|
||||
|
||||
if SynoSurveillanceStation.CAMERA_API_KEY not in api.dsm.apis:
|
||||
return
|
||||
|
||||
# initial data fetch
|
||||
coordinator = data[COORDINATOR_CAMERAS]
|
||||
await coordinator.async_refresh()
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, SynoCamera]]] = data[
|
||||
COORDINATOR_CAMERAS
|
||||
]
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
async_add_entities(
|
||||
SynoDSMCamera(api, coordinator, camera_id)
|
||||
|
@ -54,9 +57,14 @@ async def async_setup_entry(
|
|||
class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
||||
"""Representation a Synology camera."""
|
||||
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, SynoCamera]]]
|
||||
|
||||
def __init__(
|
||||
self, api: SynoApi, coordinator: DataUpdateCoordinator, camera_id: int
|
||||
):
|
||||
self,
|
||||
api: SynoApi,
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, SynoCamera]]],
|
||||
camera_id: str,
|
||||
) -> None:
|
||||
"""Initialize a Synology camera."""
|
||||
super().__init__(
|
||||
api,
|
||||
|
@ -70,13 +78,11 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
},
|
||||
coordinator,
|
||||
)
|
||||
Camera.__init__(self)
|
||||
|
||||
Camera.__init__(self) # type: ignore[no-untyped-call]
|
||||
self._camera_id = camera_id
|
||||
self._api = api
|
||||
|
||||
@property
|
||||
def camera_data(self):
|
||||
def camera_data(self) -> SynoCamera:
|
||||
"""Camera data."""
|
||||
return self.coordinator.data["cameras"][self._camera_id]
|
||||
|
||||
|
@ -87,16 +93,14 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
"identifiers": {
|
||||
(
|
||||
DOMAIN,
|
||||
self._api.information.serial,
|
||||
self.camera_data.id,
|
||||
f"{self._api.information.serial}_{self.camera_data.id}",
|
||||
)
|
||||
},
|
||||
"name": self.camera_data.name,
|
||||
"model": self.camera_data.model,
|
||||
"via_device": (
|
||||
DOMAIN,
|
||||
self._api.information.serial,
|
||||
SynoSurveillanceStation.INFO_API_KEY,
|
||||
f"{self._api.information.serial}_{SynoSurveillanceStation.INFO_API_KEY}",
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -111,16 +115,16 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
return SUPPORT_STREAM
|
||||
|
||||
@property
|
||||
def is_recording(self):
|
||||
def is_recording(self) -> bool:
|
||||
"""Return true if the device is recording."""
|
||||
return self.camera_data.is_recording
|
||||
return self.camera_data.is_recording # type: ignore[no-any-return]
|
||||
|
||||
@property
|
||||
def motion_detection_enabled(self):
|
||||
def motion_detection_enabled(self) -> bool:
|
||||
"""Return the camera motion detection status."""
|
||||
return self.camera_data.is_motion_detection_enabled
|
||||
return self.camera_data.is_motion_detection_enabled # type: ignore[no-any-return]
|
||||
|
||||
def camera_image(self) -> bytes:
|
||||
def camera_image(self) -> bytes | None:
|
||||
"""Return bytes of camera image."""
|
||||
_LOGGER.debug(
|
||||
"SynoDSMCamera.camera_image(%s)",
|
||||
|
@ -129,7 +133,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
if not self.available:
|
||||
return None
|
||||
try:
|
||||
return self._api.surveillance_station.get_camera_image(self._camera_id)
|
||||
return self._api.surveillance_station.get_camera_image(self._camera_id) # type: ignore[no-any-return]
|
||||
except (
|
||||
SynologyDSMAPIErrorException,
|
||||
SynologyDSMRequestException,
|
||||
|
@ -142,7 +146,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
)
|
||||
return None
|
||||
|
||||
async def stream_source(self) -> str:
|
||||
async def stream_source(self) -> str | None:
|
||||
"""Return the source of the stream."""
|
||||
_LOGGER.debug(
|
||||
"SynoDSMCamera.stream_source(%s)",
|
||||
|
@ -150,9 +154,9 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
)
|
||||
if not self.available:
|
||||
return None
|
||||
return self.camera_data.live_view.rtsp
|
||||
return self.camera_data.live_view.rtsp # type: ignore[no-any-return]
|
||||
|
||||
def enable_motion_detection(self):
|
||||
def enable_motion_detection(self) -> None:
|
||||
"""Enable motion detection in the camera."""
|
||||
_LOGGER.debug(
|
||||
"SynoDSMCamera.enable_motion_detection(%s)",
|
||||
|
@ -160,7 +164,7 @@ class SynoDSMCamera(SynologyDSMBaseEntity, Camera):
|
|||
)
|
||||
self._api.surveillance_station.enable_motion_detection(self._camera_id)
|
||||
|
||||
def disable_motion_detection(self):
|
||||
def disable_motion_detection(self) -> None:
|
||||
"""Disable motion detection in camera."""
|
||||
_LOGGER.debug(
|
||||
"SynoDSMCamera.disable_motion_detection(%s)",
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
"""Config flow to configure the Synology DSM integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from synology_dsm import SynologyDSM
|
||||
|
@ -12,8 +15,14 @@ from synology_dsm.exceptions import (
|
|||
)
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, exceptions
|
||||
from homeassistant import exceptions
|
||||
from homeassistant.components import ssdp
|
||||
from homeassistant.config_entries import (
|
||||
CONN_CLASS_CLOUD_POLL,
|
||||
ConfigEntry,
|
||||
ConfigFlow,
|
||||
OptionsFlow,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONF_DISKS,
|
||||
CONF_HOST,
|
||||
|
@ -28,7 +37,9 @@ from homeassistant.const import (
|
|||
CONF_VERIFY_SSL,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||
|
||||
from .const import (
|
||||
CONF_DEVICE_TOKEN,
|
||||
|
@ -47,11 +58,11 @@ _LOGGER = logging.getLogger(__name__)
|
|||
CONF_OTP_CODE = "otp_code"
|
||||
|
||||
|
||||
def _discovery_schema_with_defaults(discovery_info):
|
||||
def _discovery_schema_with_defaults(discovery_info: DiscoveryInfoType) -> vol.Schema:
|
||||
return vol.Schema(_ordered_shared_schema(discovery_info))
|
||||
|
||||
|
||||
def _user_schema_with_defaults(user_input):
|
||||
def _user_schema_with_defaults(user_input: dict[str, Any]) -> vol.Schema:
|
||||
user_schema = {
|
||||
vol.Required(CONF_HOST, default=user_input.get(CONF_HOST, "")): str,
|
||||
}
|
||||
|
@ -60,7 +71,9 @@ def _user_schema_with_defaults(user_input):
|
|||
return vol.Schema(user_schema)
|
||||
|
||||
|
||||
def _ordered_shared_schema(schema_input):
|
||||
def _ordered_shared_schema(
|
||||
schema_input: dict[str, Any]
|
||||
) -> dict[vol.Required | vol.Optional, Any]:
|
||||
return {
|
||||
vol.Required(CONF_USERNAME, default=schema_input.get(CONF_USERNAME, "")): str,
|
||||
vol.Required(CONF_PASSWORD, default=schema_input.get(CONF_PASSWORD, "")): str,
|
||||
|
@ -75,23 +88,30 @@ def _ordered_shared_schema(schema_input):
|
|||
}
|
||||
|
||||
|
||||
class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
class SynologyDSMFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = CONN_CLASS_CLOUD_POLL
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry):
|
||||
def async_get_options_flow(
|
||||
config_entry: ConfigEntry,
|
||||
) -> SynologyDSMOptionsFlowHandler:
|
||||
"""Get the options flow for this handler."""
|
||||
return SynologyDSMOptionsFlowHandler(config_entry)
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the synology_dsm config flow."""
|
||||
self.saved_user_input = {}
|
||||
self.discovered_conf = {}
|
||||
self.saved_user_input: dict[str, Any] = {}
|
||||
self.discovered_conf: dict[str, Any] = {}
|
||||
|
||||
async def _show_setup_form(self, user_input=None, errors=None):
|
||||
async def _show_setup_form(
|
||||
self,
|
||||
user_input: dict[str, Any] | None = None,
|
||||
errors: dict[str, str] | None = None,
|
||||
) -> FlowResult:
|
||||
"""Show the setup form to the user."""
|
||||
if not user_input:
|
||||
user_input = {}
|
||||
|
@ -111,7 +131,9 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
description_placeholders=self.discovered_conf or {},
|
||||
)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initiated by the user."""
|
||||
errors = {}
|
||||
|
||||
|
@ -188,7 +210,7 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
return self.async_create_entry(title=host, data=config_data)
|
||||
|
||||
async def async_step_ssdp(self, discovery_info):
|
||||
async def async_step_ssdp(self, discovery_info: DiscoveryInfoType) -> FlowResult:
|
||||
"""Handle a discovered synology_dsm."""
|
||||
parsed_url = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION])
|
||||
friendly_name = (
|
||||
|
@ -211,15 +233,19 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
self.context["title_placeholders"] = self.discovered_conf
|
||||
return await self.async_step_user()
|
||||
|
||||
async def async_step_import(self, user_input=None):
|
||||
async def async_step_import(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Import a config entry."""
|
||||
return await self.async_step_user(user_input)
|
||||
|
||||
async def async_step_link(self, user_input):
|
||||
async def async_step_link(self, user_input: dict[str, Any]) -> FlowResult:
|
||||
"""Link a config entry from discovery."""
|
||||
return await self.async_step_user(user_input)
|
||||
|
||||
async def async_step_2sa(self, user_input, errors=None):
|
||||
async def async_step_2sa(
|
||||
self, user_input: dict[str, Any], errors: dict[str, str] | None = None
|
||||
) -> FlowResult:
|
||||
"""Enter 2SA code to anthenticate."""
|
||||
if not self.saved_user_input:
|
||||
self.saved_user_input = user_input
|
||||
|
@ -236,7 +262,7 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
return await self.async_step_user(user_input)
|
||||
|
||||
def _mac_already_configured(self, mac):
|
||||
def _mac_already_configured(self, mac: str) -> bool:
|
||||
"""See if we already have configured a NAS with this MAC address."""
|
||||
existing_macs = [
|
||||
mac.replace("-", "")
|
||||
|
@ -246,14 +272,16 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
return mac in existing_macs
|
||||
|
||||
|
||||
class SynologyDSMOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
class SynologyDSMOptionsFlowHandler(OptionsFlow):
|
||||
"""Handle a option flow."""
|
||||
|
||||
def __init__(self, config_entry: config_entries.ConfigEntry):
|
||||
def __init__(self, config_entry: ConfigEntry):
|
||||
"""Initialize options flow."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle options flow."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
@ -277,7 +305,7 @@ class SynologyDSMOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
return self.async_show_form(step_id="init", data_schema=data_schema)
|
||||
|
||||
|
||||
def _login_and_fetch_syno_info(api, otp_code):
|
||||
def _login_and_fetch_syno_info(api: SynologyDSM, otp_code: str) -> str:
|
||||
"""Login to the NAS and fetch basic data."""
|
||||
# These do i/o
|
||||
api.login(otp_code)
|
||||
|
@ -293,7 +321,7 @@ def _login_and_fetch_syno_info(api, otp_code):
|
|||
):
|
||||
raise InvalidData
|
||||
|
||||
return api.information.serial
|
||||
return api.information.serial # type: ignore[no-any-return]
|
||||
|
||||
|
||||
class InvalidData(exceptions.HomeAssistantError):
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
"""Constants for Synology DSM."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final, TypedDict
|
||||
|
||||
from synology_dsm.api.core.security import SynoCoreSecurity
|
||||
from synology_dsm.api.core.upgrade import SynoCoreUpgrade
|
||||
|
@ -17,6 +20,17 @@ from homeassistant.const import (
|
|||
PERCENTAGE,
|
||||
)
|
||||
|
||||
|
||||
class EntityInfo(TypedDict):
|
||||
"""TypedDict for EntityInfo."""
|
||||
|
||||
name: str
|
||||
unit: str | None
|
||||
icon: str | None
|
||||
device_class: str | None
|
||||
enable: bool
|
||||
|
||||
|
||||
DOMAIN = "synology_dsm"
|
||||
PLATFORMS = ["binary_sensor", "camera", "sensor", "switch"]
|
||||
COORDINATOR_CAMERAS = "coordinator_cameras"
|
||||
|
@ -43,11 +57,11 @@ DEFAULT_TIMEOUT = 10 # sec
|
|||
|
||||
ENTITY_UNIT_LOAD = "load"
|
||||
|
||||
ENTITY_NAME = "name"
|
||||
ENTITY_UNIT = "unit"
|
||||
ENTITY_ICON = "icon"
|
||||
ENTITY_CLASS = "device_class"
|
||||
ENTITY_ENABLE = "enable"
|
||||
ENTITY_NAME: Final = "name"
|
||||
ENTITY_UNIT: Final = "unit"
|
||||
ENTITY_ICON: Final = "icon"
|
||||
ENTITY_CLASS: Final = "device_class"
|
||||
ENTITY_ENABLE: Final = "enable"
|
||||
|
||||
# Services
|
||||
SERVICE_REBOOT = "reboot"
|
||||
|
@ -60,7 +74,7 @@ SERVICES = [
|
|||
# Entity keys should start with the API_KEY to fetch
|
||||
|
||||
# Binary sensors
|
||||
UPGRADE_BINARY_SENSORS = {
|
||||
UPGRADE_BINARY_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoCoreUpgrade.API_KEY}:update_available": {
|
||||
ENTITY_NAME: "Update available",
|
||||
ENTITY_UNIT: None,
|
||||
|
@ -70,7 +84,7 @@ UPGRADE_BINARY_SENSORS = {
|
|||
},
|
||||
}
|
||||
|
||||
SECURITY_BINARY_SENSORS = {
|
||||
SECURITY_BINARY_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoCoreSecurity.API_KEY}:status": {
|
||||
ENTITY_NAME: "Security status",
|
||||
ENTITY_UNIT: None,
|
||||
|
@ -80,7 +94,7 @@ SECURITY_BINARY_SENSORS = {
|
|||
},
|
||||
}
|
||||
|
||||
STORAGE_DISK_BINARY_SENSORS = {
|
||||
STORAGE_DISK_BINARY_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoStorage.API_KEY}:disk_exceed_bad_sector_thr": {
|
||||
ENTITY_NAME: "Exceeded Max Bad Sectors",
|
||||
ENTITY_UNIT: None,
|
||||
|
@ -98,7 +112,7 @@ STORAGE_DISK_BINARY_SENSORS = {
|
|||
}
|
||||
|
||||
# Sensors
|
||||
UTILISATION_SENSORS = {
|
||||
UTILISATION_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoCoreUtilization.API_KEY}:cpu_other_load": {
|
||||
ENTITY_NAME: "CPU Utilization (Other)",
|
||||
ENTITY_UNIT: PERCENTAGE,
|
||||
|
@ -212,7 +226,7 @@ UTILISATION_SENSORS = {
|
|||
ENTITY_ENABLE: True,
|
||||
},
|
||||
}
|
||||
STORAGE_VOL_SENSORS = {
|
||||
STORAGE_VOL_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoStorage.API_KEY}:volume_status": {
|
||||
ENTITY_NAME: "Status",
|
||||
ENTITY_UNIT: None,
|
||||
|
@ -256,7 +270,7 @@ STORAGE_VOL_SENSORS = {
|
|||
ENTITY_ENABLE: False,
|
||||
},
|
||||
}
|
||||
STORAGE_DISK_SENSORS = {
|
||||
STORAGE_DISK_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoStorage.API_KEY}:disk_smart_status": {
|
||||
ENTITY_NAME: "Status (Smart)",
|
||||
ENTITY_UNIT: None,
|
||||
|
@ -280,7 +294,7 @@ STORAGE_DISK_SENSORS = {
|
|||
},
|
||||
}
|
||||
|
||||
INFORMATION_SENSORS = {
|
||||
INFORMATION_SENSORS: dict[str, EntityInfo] = {
|
||||
f"{SynoDSMInformation.API_KEY}:temperature": {
|
||||
ENTITY_NAME: "temperature",
|
||||
ENTITY_UNIT: None,
|
||||
|
@ -298,7 +312,7 @@ INFORMATION_SENSORS = {
|
|||
}
|
||||
|
||||
# Switch
|
||||
SURVEILLANCE_SWITCH = {
|
||||
SURVEILLANCE_SWITCH: dict[str, EntityInfo] = {
|
||||
f"{SynoSurveillanceStation.HOME_MODE_API_KEY}:home_mode": {
|
||||
ENTITY_NAME: "home mode",
|
||||
ENTITY_UNIT: None,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -14,6 +15,7 @@ from homeassistant.const import (
|
|||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.temperature import display_temp
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
@ -30,19 +32,20 @@ from .const import (
|
|||
SYNO_API,
|
||||
TEMP_SENSORS_KEYS,
|
||||
UTILISATION_SENSORS,
|
||||
EntityInfo,
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the Synology NAS Sensor."""
|
||||
|
||||
data = hass.data[DOMAIN][entry.unique_id]
|
||||
api = data[SYNO_API]
|
||||
api: SynoApi = data[SYNO_API]
|
||||
coordinator = data[COORDINATOR_CENTRAL]
|
||||
|
||||
entities = [
|
||||
entities: list[SynoDSMUtilSensor | SynoDSMStorageSensor | SynoDSMInfoSensor] = [
|
||||
SynoDSMUtilSensor(
|
||||
api, sensor_type, UTILISATION_SENSORS[sensor_type], coordinator
|
||||
)
|
||||
|
@ -91,7 +94,7 @@ class SynoDSMSensor(SynologyDSMBaseEntity):
|
|||
"""Mixin for sensor specific attributes."""
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
def unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit the value is expressed in."""
|
||||
if self.entity_type in TEMP_SENSORS_KEYS:
|
||||
return self.hass.config.units.temperature_unit
|
||||
|
@ -102,7 +105,7 @@ class SynoDSMUtilSensor(SynoDSMSensor, SensorEntity):
|
|||
"""Representation a Synology Utilisation sensor."""
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> Any | None:
|
||||
"""Return the state."""
|
||||
attr = getattr(self._api.utilisation, self.entity_type)
|
||||
if callable(attr):
|
||||
|
@ -134,7 +137,7 @@ class SynoDSMStorageSensor(SynologyDSMDeviceEntity, SynoDSMSensor, SensorEntity)
|
|||
"""Representation a Synology Storage sensor."""
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> Any | None:
|
||||
"""Return the state."""
|
||||
attr = getattr(self._api.storage, self.entity_type)(self._device_id)
|
||||
if attr is None:
|
||||
|
@ -158,16 +161,16 @@ class SynoDSMInfoSensor(SynoDSMSensor, SensorEntity):
|
|||
self,
|
||||
api: SynoApi,
|
||||
entity_type: str,
|
||||
entity_info: dict[str, str],
|
||||
coordinator: DataUpdateCoordinator,
|
||||
):
|
||||
entity_info: EntityInfo,
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, Any]]],
|
||||
) -> None:
|
||||
"""Initialize the Synology SynoDSMInfoSensor entity."""
|
||||
super().__init__(api, entity_type, entity_info, coordinator)
|
||||
self._previous_uptime = None
|
||||
self._last_boot = None
|
||||
self._previous_uptime: str | None = None
|
||||
self._last_boot: str | None = None
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> Any | None:
|
||||
"""Return the state."""
|
||||
attr = getattr(self._api.information, self.entity_type)
|
||||
if attr is None:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from synology_dsm.api.surveillance_station import SynoSurveillanceStation
|
||||
|
||||
|
@ -9,21 +10,28 @@ from homeassistant.components.switch import ToggleEntity
|
|||
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_SWITCHES, DOMAIN, SURVEILLANCE_SWITCH, SYNO_API
|
||||
from .const import (
|
||||
COORDINATOR_SWITCHES,
|
||||
DOMAIN,
|
||||
SURVEILLANCE_SWITCH,
|
||||
SYNO_API,
|
||||
EntityInfo,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the Synology NAS switch."""
|
||||
|
||||
data = hass.data[DOMAIN][entry.unique_id]
|
||||
api = data[SYNO_API]
|
||||
api: SynoApi = data[SYNO_API]
|
||||
|
||||
entities = []
|
||||
|
||||
|
@ -32,7 +40,7 @@ async def async_setup_entry(
|
|||
version = info["data"]["CMSMinVersion"]
|
||||
|
||||
# initial data fetch
|
||||
coordinator = data[COORDINATOR_SWITCHES]
|
||||
coordinator: DataUpdateCoordinator = data[COORDINATOR_SWITCHES]
|
||||
await coordinator.async_refresh()
|
||||
entities += [
|
||||
SynoDSMSurveillanceHomeModeToggle(
|
||||
|
@ -47,14 +55,16 @@ async def async_setup_entry(
|
|||
class SynoDSMSurveillanceHomeModeToggle(SynologyDSMBaseEntity, ToggleEntity):
|
||||
"""Representation a Synology Surveillance Station Home Mode toggle."""
|
||||
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, bool]]]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api: SynoApi,
|
||||
entity_type: str,
|
||||
entity_info: dict[str, str],
|
||||
entity_info: EntityInfo,
|
||||
version: str,
|
||||
coordinator: DataUpdateCoordinator,
|
||||
):
|
||||
coordinator: DataUpdateCoordinator[dict[str, dict[str, bool]]],
|
||||
) -> None:
|
||||
"""Initialize a Synology Surveillance Station Home Mode."""
|
||||
super().__init__(
|
||||
api,
|
||||
|
@ -69,7 +79,7 @@ class SynoDSMSurveillanceHomeModeToggle(SynologyDSMBaseEntity, ToggleEntity):
|
|||
"""Return the state."""
|
||||
return self.coordinator.data["switches"][self.entity_type]
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on Home mode."""
|
||||
_LOGGER.debug(
|
||||
"SynoDSMSurveillanceHomeModeToggle.turn_on(%s)",
|
||||
|
@ -80,7 +90,7 @@ class SynoDSMSurveillanceHomeModeToggle(SynologyDSMBaseEntity, ToggleEntity):
|
|||
)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off Home mode."""
|
||||
_LOGGER.debug(
|
||||
"SynoDSMSurveillanceHomeModeToggle.turn_off(%s)",
|
||||
|
@ -103,8 +113,7 @@ class SynoDSMSurveillanceHomeModeToggle(SynologyDSMBaseEntity, ToggleEntity):
|
|||
"identifiers": {
|
||||
(
|
||||
DOMAIN,
|
||||
self._api.information.serial,
|
||||
SynoSurveillanceStation.INFO_API_KEY,
|
||||
f"{self._api.information.serial}_{SynoSurveillanceStation.INFO_API_KEY}",
|
||||
)
|
||||
},
|
||||
"name": "Surveillance Station",
|
||||
|
|
16
mypy.ini
16
mypy.ini
|
@ -529,6 +529,19 @@ warn_return_any = true
|
|||
warn_unreachable = true
|
||||
warn_unused_ignores = true
|
||||
|
||||
[mypy-homeassistant.components.synology_dsm.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_subclassing_any = true
|
||||
disallow_untyped_calls = true
|
||||
disallow_untyped_decorators = true
|
||||
disallow_untyped_defs = true
|
||||
no_implicit_optional = true
|
||||
strict_equality = true
|
||||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
warn_unused_ignores = true
|
||||
|
||||
[mypy-homeassistant.components.systemmonitor.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
|
@ -1232,9 +1245,6 @@ ignore_errors = true
|
|||
[mypy-homeassistant.components.switcher_kis.*]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.synology_dsm.*]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.synology_srm.*]
|
||||
ignore_errors = true
|
||||
|
||||
|
|
|
@ -205,7 +205,6 @@ IGNORED_MODULES: Final[list[str]] = [
|
|||
"homeassistant.components.surepetcare.*",
|
||||
"homeassistant.components.switchbot.*",
|
||||
"homeassistant.components.switcher_kis.*",
|
||||
"homeassistant.components.synology_dsm.*",
|
||||
"homeassistant.components.synology_srm.*",
|
||||
"homeassistant.components.system_health.*",
|
||||
"homeassistant.components.system_log.*",
|
||||
|
|
Loading…
Reference in New Issue