mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Cleanup unifiprotect entity classes (#121184)
This commit is contained in:
parent
22718ca32a
commit
d3f424227f
@ -8,11 +8,9 @@ import dataclasses
|
||||
from uiprotect.data import (
|
||||
NVR,
|
||||
Camera,
|
||||
Light,
|
||||
ModelType,
|
||||
MountType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
Sensor,
|
||||
SmartDetectObjectType,
|
||||
)
|
||||
@ -27,11 +25,12 @@ from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import (
|
||||
BaseProtectEntity,
|
||||
EventEntityMixin,
|
||||
ProtectDeviceEntity,
|
||||
ProtectIsOnEntity,
|
||||
ProtectNVREntity,
|
||||
async_all_device_entities,
|
||||
)
|
||||
@ -623,31 +622,22 @@ _MOUNTABLE_MODEL_DESCRIPTIONS: dict[ModelType, Sequence[ProtectEntityDescription
|
||||
}
|
||||
|
||||
|
||||
class ProtectDeviceBinarySensor(ProtectDeviceEntity, BinarySensorEntity):
|
||||
class ProtectDeviceBinarySensor(
|
||||
ProtectIsOnEntity, ProtectDeviceEntity, BinarySensorEntity
|
||||
):
|
||||
"""A UniFi Protect Device Binary Sensor."""
|
||||
|
||||
device: Camera | Light | Sensor
|
||||
entity_description: ProtectBinaryEntityDescription
|
||||
_state_attrs: tuple[str, ...] = ("_attr_available", "_attr_is_on")
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
self._attr_is_on = self.entity_description.get_ufp_value(self.device)
|
||||
|
||||
|
||||
class MountableProtectDeviceBinarySensor(ProtectDeviceBinarySensor):
|
||||
"""A UniFi Protect Device Binary Sensor that can change device class at runtime."""
|
||||
|
||||
device: Sensor
|
||||
_state_attrs: tuple[str, ...] = (
|
||||
"_attr_available",
|
||||
"_attr_is_on",
|
||||
"_attr_device_class",
|
||||
)
|
||||
_state_attrs = ("_attr_available", "_attr_is_on", "_attr_device_class")
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
# UP Sense can be any of the 3 contact sensor device classes
|
||||
self._attr_device_class = MOUNT_DEVICE_CLASS_MAP.get(
|
||||
@ -673,7 +663,6 @@ class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity):
|
||||
self._disk = disk
|
||||
# backwards compat with old unique IDs
|
||||
index = self._disk.slot - 1
|
||||
|
||||
description = dataclasses.replace(
|
||||
description,
|
||||
key=f"{description.key}_{index}",
|
||||
@ -682,7 +671,7 @@ class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity):
|
||||
super().__init__(data, device, description)
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
slot = self._disk.slot
|
||||
self._attr_available = False
|
||||
@ -712,7 +701,7 @@ class ProtectEventBinarySensor(EventEntityMixin, BinarySensorEntity):
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
description = self.entity_description
|
||||
|
||||
prev_event = self._event
|
||||
|
@ -4,10 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Final
|
||||
from typing import TYPE_CHECKING, Final
|
||||
|
||||
from uiprotect.data import ModelType, ProtectAdoptableDeviceModel, ProtectModelWithId
|
||||
from uiprotect.data import ModelType, ProtectAdoptableDeviceModel
|
||||
|
||||
from homeassistant.components.button import (
|
||||
ButtonDeviceClass,
|
||||
@ -21,7 +22,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DEVICES_THAT_ADOPT, DOMAIN
|
||||
from .data import UFPConfigEntry
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
|
||||
@ -38,7 +39,6 @@ class ProtectButtonEntityDescription(
|
||||
|
||||
|
||||
DEVICE_CLASS_CHIME_BUTTON: Final = "unifiprotect__chime_button"
|
||||
KEY_ADOPT = "adopt"
|
||||
|
||||
|
||||
ALL_DEVICE_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
|
||||
@ -61,7 +61,7 @@ ALL_DEVICE_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
|
||||
)
|
||||
|
||||
ADOPT_BUTTON = ProtectButtonEntityDescription[ProtectAdoptableDeviceModel](
|
||||
key=KEY_ADOPT,
|
||||
key="adopt",
|
||||
name="Adopt device",
|
||||
icon="mdi:plus-circle",
|
||||
ufp_press="adopt",
|
||||
@ -119,17 +119,25 @@ async def async_setup_entry(
|
||||
"""Discover devices on a UniFi Protect NVR."""
|
||||
data = entry.runtime_data
|
||||
|
||||
adopt_entities = partial(
|
||||
async_all_device_entities,
|
||||
data,
|
||||
ProtectAdoptButton,
|
||||
unadopted_descs=[ADOPT_BUTTON],
|
||||
)
|
||||
base_entities = partial(
|
||||
async_all_device_entities,
|
||||
data,
|
||||
ProtectButton,
|
||||
all_descs=ALL_DEVICE_BUTTONS,
|
||||
model_descriptions=_MODEL_DESCRIPTIONS,
|
||||
)
|
||||
|
||||
@callback
|
||||
def _add_new_device(device: ProtectAdoptableDeviceModel) -> None:
|
||||
entities = async_all_device_entities(
|
||||
data,
|
||||
ProtectButton,
|
||||
all_descs=ALL_DEVICE_BUTTONS,
|
||||
unadopted_descs=[ADOPT_BUTTON],
|
||||
model_descriptions=_MODEL_DESCRIPTIONS,
|
||||
ufp_device=device,
|
||||
async_add_entities(
|
||||
[*base_entities(ufp_device=device), *adopt_entities(ufp_device=device)]
|
||||
)
|
||||
async_add_entities(entities)
|
||||
_async_remove_adopt_button(hass, device)
|
||||
|
||||
@callback
|
||||
@ -137,29 +145,13 @@ async def async_setup_entry(
|
||||
if not device.can_adopt or not device.can_create(data.api.bootstrap.auth_user):
|
||||
_LOGGER.debug("Device is not adoptable: %s", device.id)
|
||||
return
|
||||
async_add_entities(
|
||||
async_all_device_entities(
|
||||
data,
|
||||
ProtectButton,
|
||||
unadopted_descs=[ADOPT_BUTTON],
|
||||
ufp_device=device,
|
||||
)
|
||||
)
|
||||
async_add_entities(adopt_entities(ufp_device=device))
|
||||
|
||||
data.async_subscribe_adopt(_add_new_device)
|
||||
entry.async_on_unload(
|
||||
async_dispatcher_connect(hass, data.add_signal, _async_add_unadopted_device)
|
||||
)
|
||||
|
||||
async_add_entities(
|
||||
async_all_device_entities(
|
||||
data,
|
||||
ProtectButton,
|
||||
all_descs=ALL_DEVICE_BUTTONS,
|
||||
unadopted_descs=[ADOPT_BUTTON],
|
||||
model_descriptions=_MODEL_DESCRIPTIONS,
|
||||
)
|
||||
)
|
||||
async_add_entities([*base_entities(), *adopt_entities()])
|
||||
|
||||
for device in data.get_by_types(DEVICES_THAT_ADOPT):
|
||||
_async_remove_adopt_button(hass, device)
|
||||
@ -170,16 +162,20 @@ class ProtectButton(ProtectDeviceEntity, ButtonEntity):
|
||||
|
||||
entity_description: ProtectButtonEntityDescription
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
if self.entity_description.key == KEY_ADOPT:
|
||||
device = self.device
|
||||
self._attr_available = device.can_adopt and device.can_create(
|
||||
self.data.api.bootstrap.auth_user
|
||||
)
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
if self.entity_description.ufp_press is not None:
|
||||
await getattr(self.device, self.entity_description.ufp_press)()
|
||||
|
||||
|
||||
class ProtectAdoptButton(ProtectButton):
|
||||
"""A Ubiquiti UniFi Protect Adopt button."""
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
if TYPE_CHECKING:
|
||||
assert isinstance(device, ProtectAdoptableDeviceModel)
|
||||
self._attr_available = device.can_adopt and device.can_create(
|
||||
self.data.api.bootstrap.auth_user
|
||||
)
|
||||
|
@ -9,7 +9,6 @@ from uiprotect.data import (
|
||||
Camera as UFPCamera,
|
||||
CameraChannel,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
StateType,
|
||||
)
|
||||
|
||||
@ -28,7 +27,7 @@ from .const import (
|
||||
ATTR_WIDTH,
|
||||
DOMAIN,
|
||||
)
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity
|
||||
from .utils import get_camera_base_name
|
||||
|
||||
@ -216,7 +215,7 @@ class ProtectCamera(ProtectDeviceEntity, Camera):
|
||||
self._attr_supported_features = _EMPTY_CAMERA_FEATURES
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
updated_device = self.device
|
||||
channel = updated_device.channels[self.channel.id]
|
||||
|
@ -9,14 +9,7 @@ import logging
|
||||
from operator import attrgetter
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from uiprotect.data import (
|
||||
NVR,
|
||||
Event,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
StateType,
|
||||
)
|
||||
from uiprotect.data import NVR, Event, ModelType, ProtectAdoptableDeviceModel, StateType
|
||||
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
@ -30,7 +23,7 @@ from .const import (
|
||||
DEFAULT_BRAND,
|
||||
DOMAIN,
|
||||
)
|
||||
from .data import ProtectData
|
||||
from .data import ProtectData, ProtectDeviceType
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectEventMixin
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -160,7 +153,7 @@ def async_all_device_entities(
|
||||
class BaseProtectEntity(Entity):
|
||||
"""Base class for UniFi protect entities."""
|
||||
|
||||
device: ProtectAdoptableDeviceModel | NVR
|
||||
device: ProtectDeviceType
|
||||
|
||||
_attr_should_poll = False
|
||||
_attr_attribution = DEFAULT_ATTRIBUTION
|
||||
@ -171,7 +164,7 @@ class BaseProtectEntity(Entity):
|
||||
def __init__(
|
||||
self,
|
||||
data: ProtectData,
|
||||
device: ProtectAdoptableDeviceModel | NVR,
|
||||
device: ProtectDeviceType,
|
||||
description: EntityDescription | None = None,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
@ -203,37 +196,32 @@ class BaseProtectEntity(Entity):
|
||||
|
||||
@callback
|
||||
def _async_set_device_info(self) -> None:
|
||||
self._attr_device_info = DeviceInfo(
|
||||
name=self.device.display_name,
|
||||
manufacturer=DEFAULT_BRAND,
|
||||
model=self.device.type,
|
||||
via_device=(DOMAIN, self.data.api.bootstrap.nvr.mac),
|
||||
sw_version=self.device.firmware_version,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, self.device.mac)},
|
||||
configuration_url=self.device.protect_url,
|
||||
)
|
||||
"""Set device info."""
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
"""Update Entity object from Protect device."""
|
||||
if TYPE_CHECKING:
|
||||
assert isinstance(device, ProtectAdoptableDeviceModel)
|
||||
|
||||
if last_update_success := self.data.last_update_success:
|
||||
was_available = self._attr_available
|
||||
if last_updated_success := self.data.last_update_success:
|
||||
self.device = device
|
||||
|
||||
async_get_ufp_enabled = self._async_get_ufp_enabled
|
||||
self._attr_available = (
|
||||
last_update_success
|
||||
and (
|
||||
device.state is StateType.CONNECTED
|
||||
or (not device.is_adopted_by_us and device.can_adopt)
|
||||
if device.model is ModelType.NVR:
|
||||
available = last_updated_success
|
||||
else:
|
||||
if TYPE_CHECKING:
|
||||
assert isinstance(device, ProtectAdoptableDeviceModel)
|
||||
connected = device.state is StateType.CONNECTED or (
|
||||
not device.is_adopted_by_us and device.can_adopt
|
||||
)
|
||||
and (not async_get_ufp_enabled or async_get_ufp_enabled(device))
|
||||
)
|
||||
async_get_ufp_enabled = self._async_get_ufp_enabled
|
||||
enabled = not async_get_ufp_enabled or async_get_ufp_enabled(device)
|
||||
available = last_updated_success and connected and enabled
|
||||
|
||||
if available != was_available:
|
||||
self._attr_available = available
|
||||
|
||||
@callback
|
||||
def _async_updated_event(self, device: ProtectAdoptableDeviceModel | NVR) -> None:
|
||||
def _async_updated_event(self, device: ProtectDeviceType) -> None:
|
||||
"""When device is updated from Protect."""
|
||||
previous_attrs = [getter() for getter in self._state_getters]
|
||||
self._async_update_device_from_protect(device)
|
||||
@ -266,10 +254,36 @@ class BaseProtectEntity(Entity):
|
||||
)
|
||||
|
||||
|
||||
class ProtectIsOnEntity(BaseProtectEntity):
|
||||
"""Base class for entities with is_on property."""
|
||||
|
||||
_state_attrs: tuple[str, ...] = ("_attr_available", "_attr_is_on")
|
||||
_attr_is_on: bool | None
|
||||
entity_description: ProtectEntityDescription
|
||||
|
||||
def _async_update_device_from_protect(
|
||||
self, device: ProtectAdoptableDeviceModel | NVR
|
||||
) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
was_on = self._attr_is_on
|
||||
if was_on != (is_on := self.entity_description.get_ufp_value(device) is True):
|
||||
self._attr_is_on = is_on
|
||||
|
||||
|
||||
class ProtectDeviceEntity(BaseProtectEntity):
|
||||
"""Base class for UniFi protect entities."""
|
||||
|
||||
device: ProtectAdoptableDeviceModel
|
||||
@callback
|
||||
def _async_set_device_info(self) -> None:
|
||||
self._attr_device_info = DeviceInfo(
|
||||
name=self.device.display_name,
|
||||
manufacturer=DEFAULT_BRAND,
|
||||
model=self.device.type,
|
||||
via_device=(DOMAIN, self.data.api.bootstrap.nvr.mac),
|
||||
sw_version=self.device.firmware_version,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, self.device.mac)},
|
||||
configuration_url=self.device.protect_url,
|
||||
)
|
||||
|
||||
|
||||
class ProtectNVREntity(BaseProtectEntity):
|
||||
@ -289,14 +303,6 @@ class ProtectNVREntity(BaseProtectEntity):
|
||||
configuration_url=self.device.api.base_url,
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
data = self.data
|
||||
if last_update_success := data.last_update_success:
|
||||
self.device = data.api.bootstrap.nvr
|
||||
|
||||
self._attr_available = last_update_success
|
||||
|
||||
|
||||
class EventEntityMixin(ProtectDeviceEntity):
|
||||
"""Adds motion event attributes to sensor."""
|
||||
@ -338,9 +344,8 @@ class EventEntityMixin(ProtectDeviceEntity):
|
||||
event object so we need to check the datetime object that was
|
||||
saved from the last time the entity was updated.
|
||||
"""
|
||||
event = self._event
|
||||
return bool(
|
||||
event
|
||||
(event := self._event)
|
||||
and event.end
|
||||
and prev_event
|
||||
and prev_event_end
|
||||
|
@ -4,12 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
|
||||
from uiprotect.data import (
|
||||
Camera,
|
||||
EventType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
)
|
||||
from uiprotect.data import Camera, EventType, ProtectAdoptableDeviceModel
|
||||
|
||||
from homeassistant.components.event import (
|
||||
EventDeviceClass,
|
||||
@ -20,7 +15,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import ATTR_EVENT_ID
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import EventEntityMixin, ProtectDeviceEntity
|
||||
from .models import ProtectEventMixin
|
||||
|
||||
@ -50,7 +45,7 @@ class ProtectDeviceEventEntity(EventEntityMixin, ProtectDeviceEntity, EventEntit
|
||||
entity_description: ProtectEventEntityDescription
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
description = self.entity_description
|
||||
|
||||
prev_event = self._event
|
||||
|
@ -5,18 +5,13 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from uiprotect.data import (
|
||||
Light,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
)
|
||||
from uiprotect.data import Light, ModelType, ProtectAdoptableDeviceModel
|
||||
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import UFPConfigEntry
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -66,7 +61,7 @@ class ProtectLight(ProtectDeviceEntity, LightEntity):
|
||||
_state_attrs = ("_attr_available", "_attr_is_on", "_attr_brightness")
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
updated_device = self.device
|
||||
self._attr_is_on = updated_device.is_light_on
|
||||
|
@ -10,14 +10,13 @@ from uiprotect.data import (
|
||||
LockStatusType,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
)
|
||||
|
||||
from homeassistant.components.lock import LockEntity, LockEntityDescription
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import UFPConfigEntry
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -60,7 +59,7 @@ class ProtectLock(ProtectDeviceEntity, LockEntity):
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
lock_status = self.device.lock_status
|
||||
|
||||
|
@ -5,12 +5,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from uiprotect.data import (
|
||||
Camera,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
StateType,
|
||||
)
|
||||
from uiprotect.data import Camera, ProtectAdoptableDeviceModel, StateType
|
||||
from uiprotect.exceptions import StreamError
|
||||
|
||||
from homeassistant.components import media_source
|
||||
@ -28,7 +23,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import UFPConfigEntry
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -77,7 +72,7 @@ class ProtectMediaPlayer(ProtectDeviceEntity, MediaPlayerEntity):
|
||||
_state_attrs = ("_attr_available", "_attr_state", "_attr_volume_level")
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
updated_device = self.device
|
||||
self._attr_volume_level = float(updated_device.speaker_settings.volume / 100)
|
||||
|
@ -12,7 +12,6 @@ from uiprotect.data import (
|
||||
Light,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
)
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
@ -20,7 +19,7 @@ from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
|
||||
@ -268,7 +267,7 @@ class ProtectNumbers(ProtectDeviceEntity, NumberEntity):
|
||||
self._attr_native_step = self.entity_description.ufp_step
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
self._attr_native_value = self.entity_description.get_ufp_value(self.device)
|
||||
|
||||
|
@ -21,7 +21,6 @@ from uiprotect.data import (
|
||||
ModelType,
|
||||
MountType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
RecordingMode,
|
||||
Sensor,
|
||||
Viewer,
|
||||
@ -33,7 +32,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import TYPE_EMPTY_VALUE
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
from .utils import async_get_light_motion_current
|
||||
@ -371,7 +370,7 @@ class ProtectSelects(ProtectDeviceEntity, SelectEntity):
|
||||
super().__init__(data, device, description)
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
entity_description = self.entity_description
|
||||
# entities with categories are not exposed for voice
|
||||
|
@ -16,7 +16,6 @@ from uiprotect.data import (
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectDeviceModel,
|
||||
ProtectModelWithId,
|
||||
Sensor,
|
||||
SmartDetectObjectType,
|
||||
)
|
||||
@ -41,7 +40,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import (
|
||||
BaseProtectEntity,
|
||||
EventEntityMixin,
|
||||
@ -721,7 +720,7 @@ class BaseProtectSensor(BaseProtectEntity, SensorEntity):
|
||||
entity_description: ProtectSensorEntityDescription
|
||||
_state_attrs = ("_attr_available", "_attr_native_value")
|
||||
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
self._attr_native_value = self.entity_description.get_ufp_value(self.device)
|
||||
|
||||
@ -756,7 +755,7 @@ class ProtectLicensePlateEventSensor(ProtectEventSensor):
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
description = self.entity_description
|
||||
|
||||
prev_event = self._event
|
||||
|
@ -5,14 +5,12 @@ from __future__ import annotations
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from uiprotect.data import (
|
||||
Camera,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
RecordingMode,
|
||||
VideoMode,
|
||||
)
|
||||
@ -23,16 +21,16 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
from .data import ProtectData, UFPConfigEntry
|
||||
from .data import ProtectData, ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import (
|
||||
BaseProtectEntity,
|
||||
ProtectDeviceEntity,
|
||||
ProtectIsOnEntity,
|
||||
ProtectNVREntity,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
ATTR_PREV_MIC = "prev_mic_level"
|
||||
ATTR_PREV_RECORD = "prev_record_mode"
|
||||
|
||||
@ -45,10 +43,7 @@ class ProtectSwitchEntityDescription(
|
||||
|
||||
|
||||
async def _set_highfps(obj: Camera, value: bool) -> None:
|
||||
if value:
|
||||
await obj.set_video_mode(VideoMode.HIGH_FPS)
|
||||
else:
|
||||
await obj.set_video_mode(VideoMode.DEFAULT)
|
||||
await obj.set_video_mode(VideoMode.HIGH_FPS if value else VideoMode.DEFAULT)
|
||||
|
||||
|
||||
CAMERA_SWITCHES: tuple[ProtectSwitchEntityDescription, ...] = (
|
||||
@ -472,15 +467,10 @@ _PRIVACY_DESCRIPTIONS: dict[ModelType, Sequence[ProtectEntityDescription]] = {
|
||||
}
|
||||
|
||||
|
||||
class ProtectBaseSwitch(BaseProtectEntity, SwitchEntity):
|
||||
class ProtectBaseSwitch(ProtectIsOnEntity):
|
||||
"""Base class for UniFi Protect Switch."""
|
||||
|
||||
entity_description: ProtectSwitchEntityDescription
|
||||
_state_attrs = ("_attr_available", "_attr_is_on")
|
||||
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
self._attr_is_on = self.entity_description.get_ufp_value(self.device) is True
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
@ -491,18 +481,23 @@ class ProtectBaseSwitch(BaseProtectEntity, SwitchEntity):
|
||||
await self.entity_description.ufp_set(self.device, False)
|
||||
|
||||
|
||||
class ProtectSwitch(ProtectBaseSwitch, ProtectDeviceEntity):
|
||||
class ProtectSwitch(ProtectDeviceEntity, ProtectBaseSwitch, SwitchEntity):
|
||||
"""A UniFi Protect Switch."""
|
||||
|
||||
entity_description: ProtectSwitchEntityDescription
|
||||
|
||||
class ProtectNVRSwitch(ProtectBaseSwitch, ProtectNVREntity):
|
||||
|
||||
class ProtectNVRSwitch(ProtectNVREntity, ProtectBaseSwitch, SwitchEntity):
|
||||
"""A UniFi Protect NVR Switch."""
|
||||
|
||||
entity_description: ProtectSwitchEntityDescription
|
||||
|
||||
|
||||
class ProtectPrivacyModeSwitch(RestoreEntity, ProtectSwitch):
|
||||
"""A UniFi Protect Switch."""
|
||||
|
||||
device: Camera
|
||||
entity_description: ProtectSwitchEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -533,7 +528,7 @@ class ProtectPrivacyModeSwitch(RestoreEntity, ProtectSwitch):
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
# do not add extra state attribute on initialize
|
||||
if self.entity_id:
|
||||
|
@ -10,7 +10,6 @@ from uiprotect.data import (
|
||||
DoorbellMessageType,
|
||||
ModelType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
)
|
||||
|
||||
from homeassistant.components.text import TextEntity, TextEntityDescription
|
||||
@ -18,7 +17,7 @@ from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .data import UFPConfigEntry
|
||||
from .data import ProtectDeviceType, UFPConfigEntry
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T
|
||||
|
||||
@ -89,7 +88,7 @@ class ProtectDeviceText(ProtectDeviceEntity, TextEntity):
|
||||
_state_attrs = ("_attr_available", "_attr_native_value")
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
self._attr_native_value = self.entity_description.get_ufp_value(self.device)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user