Merge unifiprotect entity and models modules (#126532)
This commit is contained in:
parent
0e0ac3efe5
commit
de88068c66
10 changed files with 146 additions and 129 deletions
|
@ -29,12 +29,14 @@ from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
|||
from .entity import (
|
||||
BaseProtectEntity,
|
||||
EventEntityMixin,
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectEventMixin,
|
||||
ProtectIsOnEntity,
|
||||
ProtectNVREntity,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectEventMixin
|
||||
|
||||
_KEY_DOOR = "door"
|
||||
|
||||
|
|
|
@ -23,8 +23,14 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
|
||||
from .const import DEVICES_THAT_ADOPT, DOMAIN
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
from .entity import (
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectSetableKeysMixin,
|
||||
T,
|
||||
async_all_device_entities,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -2,14 +2,24 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Sequence
|
||||
from collections.abc import Callable, Coroutine, Sequence
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
import logging
|
||||
from operator import attrgetter
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Any, Generic, TypeVar
|
||||
|
||||
from uiprotect.data import NVR, Event, ModelType, ProtectAdoptableDeviceModel, StateType
|
||||
from uiprotect import make_enabled_getter, make_required_getter, make_value_getter
|
||||
from uiprotect.data import (
|
||||
NVR,
|
||||
Event,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
SmartDetectObjectType,
|
||||
StateType,
|
||||
)
|
||||
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
|
@ -24,10 +34,19 @@ from .const import (
|
|||
DOMAIN,
|
||||
)
|
||||
from .data import ProtectData, ProtectDeviceType
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectEventMixin
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
T = TypeVar("T", bound=ProtectAdoptableDeviceModel | NVR)
|
||||
|
||||
|
||||
class PermRequired(int, Enum):
|
||||
"""Type of permission level required for entity."""
|
||||
|
||||
NO_WRITE = 1
|
||||
WRITE = 2
|
||||
DELETE = 3
|
||||
|
||||
|
||||
@callback
|
||||
def _async_device_entities(
|
||||
|
@ -352,3 +371,82 @@ class EventEntityMixin(ProtectDeviceEntity):
|
|||
and prev_event_end
|
||||
and prev_event.id == event.id
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ProtectEntityDescription(EntityDescription, Generic[T]):
|
||||
"""Base class for protect entity descriptions."""
|
||||
|
||||
ufp_required_field: str | None = None
|
||||
ufp_value: str | None = None
|
||||
ufp_value_fn: Callable[[T], Any] | None = None
|
||||
ufp_enabled: str | None = None
|
||||
ufp_perm: PermRequired | None = None
|
||||
|
||||
# The below are set in __post_init__
|
||||
has_required: Callable[[T], bool] = bool
|
||||
get_ufp_enabled: Callable[[T], bool] | None = None
|
||||
|
||||
def get_ufp_value(self, obj: T) -> Any:
|
||||
"""Return value from UniFi Protect device; overridden in __post_init__."""
|
||||
# ufp_value or ufp_value_fn are required, the
|
||||
# RuntimeError is to catch any issues in the code
|
||||
# with new descriptions.
|
||||
raise RuntimeError( # pragma: no cover
|
||||
f"`ufp_value` or `ufp_value_fn` is required for {self}"
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""Override get_ufp_value, has_required, and get_ufp_enabled if required."""
|
||||
_setter = partial(object.__setattr__, self)
|
||||
|
||||
if (ufp_value := self.ufp_value) is not None:
|
||||
_setter("get_ufp_value", make_value_getter(ufp_value))
|
||||
elif (ufp_value_fn := self.ufp_value_fn) is not None:
|
||||
_setter("get_ufp_value", ufp_value_fn)
|
||||
|
||||
if (ufp_enabled := self.ufp_enabled) is not None:
|
||||
_setter("get_ufp_enabled", make_enabled_getter(ufp_enabled))
|
||||
|
||||
if (ufp_required_field := self.ufp_required_field) is not None:
|
||||
_setter("has_required", make_required_getter(ufp_required_field))
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ProtectEventMixin(ProtectEntityDescription[T]):
|
||||
"""Mixin for events."""
|
||||
|
||||
ufp_event_obj: str | None = None
|
||||
ufp_obj_type: SmartDetectObjectType | None = None
|
||||
|
||||
def get_event_obj(self, obj: T) -> Event | None:
|
||||
"""Return value from UniFi Protect device."""
|
||||
return None
|
||||
|
||||
def has_matching_smart(self, event: Event) -> bool:
|
||||
"""Determine if the detection type is a match."""
|
||||
return (
|
||||
not (obj_type := self.ufp_obj_type) or obj_type in event.smart_detect_types
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""Override get_event_obj if ufp_event_obj is set."""
|
||||
if (_ufp_event_obj := self.ufp_event_obj) is not None:
|
||||
object.__setattr__(self, "get_event_obj", attrgetter(_ufp_event_obj))
|
||||
super().__post_init__()
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ProtectSetableKeysMixin(ProtectEntityDescription[T]):
|
||||
"""Mixin for settable values."""
|
||||
|
||||
ufp_set_method: str | None = None
|
||||
ufp_set_method_fn: Callable[[T, Any], Coroutine[Any, Any, None]] | None = None
|
||||
|
||||
async def ufp_set(self, obj: T, value: Any) -> None:
|
||||
"""Set value for UniFi Protect device."""
|
||||
_LOGGER.debug("Setting %s to %s for %s", self.name, value, obj.display_name)
|
||||
if self.ufp_set_method is not None:
|
||||
await getattr(obj, self.ufp_set_method)(value)
|
||||
elif self.ufp_set_method_fn is not None:
|
||||
await self.ufp_set_method_fn(obj, value)
|
||||
|
|
|
@ -16,8 +16,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
|
||||
from .const import ATTR_EVENT_ID
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import EventEntityMixin, ProtectDeviceEntity
|
||||
from .models import ProtectEventMixin
|
||||
from .entity import EventEntityMixin, ProtectDeviceEntity, ProtectEventMixin
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True, kw_only=True)
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
"""The unifiprotect integration models."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Coroutine
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
import logging
|
||||
from operator import attrgetter
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from uiprotect import make_enabled_getter, make_required_getter, make_value_getter
|
||||
from uiprotect.data import (
|
||||
NVR,
|
||||
Event,
|
||||
ProtectAdoptableDeviceModel,
|
||||
SmartDetectObjectType,
|
||||
)
|
||||
|
||||
from homeassistant.helpers.entity import EntityDescription
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
T = TypeVar("T", bound=ProtectAdoptableDeviceModel | NVR)
|
||||
|
||||
|
||||
class PermRequired(int, Enum):
|
||||
"""Type of permission level required for entity."""
|
||||
|
||||
NO_WRITE = 1
|
||||
WRITE = 2
|
||||
DELETE = 3
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ProtectEntityDescription(EntityDescription, Generic[T]):
|
||||
"""Base class for protect entity descriptions."""
|
||||
|
||||
ufp_required_field: str | None = None
|
||||
ufp_value: str | None = None
|
||||
ufp_value_fn: Callable[[T], Any] | None = None
|
||||
ufp_enabled: str | None = None
|
||||
ufp_perm: PermRequired | None = None
|
||||
|
||||
# The below are set in __post_init__
|
||||
has_required: Callable[[T], bool] = bool
|
||||
get_ufp_enabled: Callable[[T], bool] | None = None
|
||||
|
||||
def get_ufp_value(self, obj: T) -> Any:
|
||||
"""Return value from UniFi Protect device; overridden in __post_init__."""
|
||||
# ufp_value or ufp_value_fn are required, the
|
||||
# RuntimeError is to catch any issues in the code
|
||||
# with new descriptions.
|
||||
raise RuntimeError( # pragma: no cover
|
||||
f"`ufp_value` or `ufp_value_fn` is required for {self}"
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""Override get_ufp_value, has_required, and get_ufp_enabled if required."""
|
||||
_setter = partial(object.__setattr__, self)
|
||||
|
||||
if (ufp_value := self.ufp_value) is not None:
|
||||
_setter("get_ufp_value", make_value_getter(ufp_value))
|
||||
elif (ufp_value_fn := self.ufp_value_fn) is not None:
|
||||
_setter("get_ufp_value", ufp_value_fn)
|
||||
|
||||
if (ufp_enabled := self.ufp_enabled) is not None:
|
||||
_setter("get_ufp_enabled", make_enabled_getter(ufp_enabled))
|
||||
|
||||
if (ufp_required_field := self.ufp_required_field) is not None:
|
||||
_setter("has_required", make_required_getter(ufp_required_field))
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ProtectEventMixin(ProtectEntityDescription[T]):
|
||||
"""Mixin for events."""
|
||||
|
||||
ufp_event_obj: str | None = None
|
||||
ufp_obj_type: SmartDetectObjectType | None = None
|
||||
|
||||
def get_event_obj(self, obj: T) -> Event | None:
|
||||
"""Return value from UniFi Protect device."""
|
||||
return None
|
||||
|
||||
def has_matching_smart(self, event: Event) -> bool:
|
||||
"""Determine if the detection type is a match."""
|
||||
return (
|
||||
not (obj_type := self.ufp_obj_type) or obj_type in event.smart_detect_types
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""Override get_event_obj if ufp_event_obj is set."""
|
||||
if (_ufp_event_obj := self.ufp_event_obj) is not None:
|
||||
object.__setattr__(self, "get_event_obj", attrgetter(_ufp_event_obj))
|
||||
super().__post_init__()
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ProtectSetableKeysMixin(ProtectEntityDescription[T]):
|
||||
"""Mixin for settable values."""
|
||||
|
||||
ufp_set_method: str | None = None
|
||||
ufp_set_method_fn: Callable[[T, Any], Coroutine[Any, Any, None]] | None = None
|
||||
|
||||
async def ufp_set(self, obj: T, value: Any) -> None:
|
||||
"""Set value for UniFi Protect device."""
|
||||
_LOGGER.debug("Setting %s to %s for %s", self.name, value, obj.display_name)
|
||||
if self.ufp_set_method is not None:
|
||||
await getattr(obj, self.ufp_set_method)(value)
|
||||
elif self.ufp_set_method_fn is not None:
|
||||
await self.ufp_set_method_fn(obj, value)
|
|
@ -20,8 +20,14 @@ from homeassistant.core import HomeAssistant, callback
|
|||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
from .entity import (
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectSetableKeysMixin,
|
||||
T,
|
||||
async_all_device_entities,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
|
|
|
@ -33,8 +33,14 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
|
||||
from .const import TYPE_EMPTY_VALUE
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
from .entity import (
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectSetableKeysMixin,
|
||||
T,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .utils import async_get_light_motion_current
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
|
|
@ -44,11 +44,14 @@ from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
|||
from .entity import (
|
||||
BaseProtectEntity,
|
||||
EventEntityMixin,
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectEventMixin,
|
||||
ProtectNVREntity,
|
||||
T,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectEventMixin, T
|
||||
from .utils import async_get_light_motion_current
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
|
|
@ -24,12 +24,15 @@ from homeassistant.helpers.restore_state import RestoreEntity
|
|||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import (
|
||||
BaseProtectEntity,
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectIsOnEntity,
|
||||
ProtectNVREntity,
|
||||
ProtectSetableKeysMixin,
|
||||
T,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
|
||||
ATTR_PREV_MIC = "prev_mic_level"
|
||||
ATTR_PREV_RECORD = "prev_record_mode"
|
||||
|
|
|
@ -18,8 +18,14 @@ from homeassistant.core import HomeAssistant, callback
|
|||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
from .entity import (
|
||||
PermRequired,
|
||||
ProtectDeviceEntity,
|
||||
ProtectEntityDescription,
|
||||
ProtectSetableKeysMixin,
|
||||
T,
|
||||
async_all_device_entities,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
|
|
Loading…
Add table
Reference in a new issue