Fix unifiprotect smart detection when end is set (#120027)
This commit is contained in:
parent
ecadaf314d
commit
68462b014c
8 changed files with 372 additions and 66 deletions
|
@ -14,6 +14,7 @@ from uiprotect.data import (
|
|||
ProtectAdoptableDeviceModel,
|
||||
ProtectModelWithId,
|
||||
Sensor,
|
||||
SmartDetectObjectType,
|
||||
)
|
||||
from uiprotect.data.nvr import UOSDisk
|
||||
|
||||
|
@ -436,11 +437,13 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
ufp_enabled="is_motion_detection_on",
|
||||
ufp_event_obj="last_motion_event",
|
||||
),
|
||||
)
|
||||
|
||||
SMART_EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
||||
ProtectBinaryEventEntityDescription(
|
||||
key="smart_obj_any",
|
||||
name="Object detected",
|
||||
icon="mdi:eye",
|
||||
ufp_value="is_smart_currently_detected",
|
||||
ufp_required_field="feature_flags.has_smart_detect",
|
||||
ufp_event_obj="last_smart_detect_event",
|
||||
),
|
||||
|
@ -448,7 +451,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_obj_person",
|
||||
name="Person detected",
|
||||
icon="mdi:walk",
|
||||
ufp_value="is_person_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.PERSON,
|
||||
ufp_required_field="can_detect_person",
|
||||
ufp_enabled="is_person_detection_on",
|
||||
ufp_event_obj="last_person_detect_event",
|
||||
|
@ -457,7 +460,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_obj_vehicle",
|
||||
name="Vehicle detected",
|
||||
icon="mdi:car",
|
||||
ufp_value="is_vehicle_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.VEHICLE,
|
||||
ufp_required_field="can_detect_vehicle",
|
||||
ufp_enabled="is_vehicle_detection_on",
|
||||
ufp_event_obj="last_vehicle_detect_event",
|
||||
|
@ -466,7 +469,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_obj_animal",
|
||||
name="Animal detected",
|
||||
icon="mdi:paw",
|
||||
ufp_value="is_animal_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.ANIMAL,
|
||||
ufp_required_field="can_detect_animal",
|
||||
ufp_enabled="is_animal_detection_on",
|
||||
ufp_event_obj="last_animal_detect_event",
|
||||
|
@ -475,8 +478,8 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_obj_package",
|
||||
name="Package detected",
|
||||
icon="mdi:package-variant-closed",
|
||||
ufp_value="is_package_currently_detected",
|
||||
entity_registry_enabled_default=False,
|
||||
ufp_obj_type=SmartDetectObjectType.PACKAGE,
|
||||
ufp_required_field="can_detect_package",
|
||||
ufp_enabled="is_package_detection_on",
|
||||
ufp_event_obj="last_package_detect_event",
|
||||
|
@ -485,7 +488,6 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_any",
|
||||
name="Audio object detected",
|
||||
icon="mdi:eye",
|
||||
ufp_value="is_audio_currently_detected",
|
||||
ufp_required_field="feature_flags.has_smart_detect",
|
||||
ufp_event_obj="last_smart_audio_detect_event",
|
||||
),
|
||||
|
@ -493,7 +495,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_smoke",
|
||||
name="Smoke alarm detected",
|
||||
icon="mdi:fire",
|
||||
ufp_value="is_smoke_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.SMOKE,
|
||||
ufp_required_field="can_detect_smoke",
|
||||
ufp_enabled="is_smoke_detection_on",
|
||||
ufp_event_obj="last_smoke_detect_event",
|
||||
|
@ -502,16 +504,16 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_cmonx",
|
||||
name="CO alarm detected",
|
||||
icon="mdi:molecule-co",
|
||||
ufp_value="is_cmonx_currently_detected",
|
||||
ufp_required_field="can_detect_co",
|
||||
ufp_enabled="is_co_detection_on",
|
||||
ufp_event_obj="last_cmonx_detect_event",
|
||||
ufp_obj_type=SmartDetectObjectType.CMONX,
|
||||
),
|
||||
ProtectBinaryEventEntityDescription(
|
||||
key="smart_audio_siren",
|
||||
name="Siren detected",
|
||||
icon="mdi:alarm-bell",
|
||||
ufp_value="is_siren_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.SIREN,
|
||||
ufp_required_field="can_detect_siren",
|
||||
ufp_enabled="is_siren_detection_on",
|
||||
ufp_event_obj="last_siren_detect_event",
|
||||
|
@ -520,7 +522,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_baby_cry",
|
||||
name="Baby cry detected",
|
||||
icon="mdi:cradle",
|
||||
ufp_value="is_baby_cry_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.BABY_CRY,
|
||||
ufp_required_field="can_detect_baby_cry",
|
||||
ufp_enabled="is_baby_cry_detection_on",
|
||||
ufp_event_obj="last_baby_cry_detect_event",
|
||||
|
@ -529,7 +531,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_speak",
|
||||
name="Speaking detected",
|
||||
icon="mdi:account-voice",
|
||||
ufp_value="is_speaking_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.SPEAK,
|
||||
ufp_required_field="can_detect_speaking",
|
||||
ufp_enabled="is_speaking_detection_on",
|
||||
ufp_event_obj="last_speaking_detect_event",
|
||||
|
@ -538,7 +540,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_bark",
|
||||
name="Barking detected",
|
||||
icon="mdi:dog",
|
||||
ufp_value="is_bark_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.BARK,
|
||||
ufp_required_field="can_detect_bark",
|
||||
ufp_enabled="is_bark_detection_on",
|
||||
ufp_event_obj="last_bark_detect_event",
|
||||
|
@ -547,7 +549,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_car_alarm",
|
||||
name="Car alarm detected",
|
||||
icon="mdi:car",
|
||||
ufp_value="is_car_alarm_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.BURGLAR,
|
||||
ufp_required_field="can_detect_car_alarm",
|
||||
ufp_enabled="is_car_alarm_detection_on",
|
||||
ufp_event_obj="last_car_alarm_detect_event",
|
||||
|
@ -556,7 +558,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_car_horn",
|
||||
name="Car horn detected",
|
||||
icon="mdi:bugle",
|
||||
ufp_value="is_car_horn_currently_detected",
|
||||
ufp_obj_type=SmartDetectObjectType.CAR_HORN,
|
||||
ufp_required_field="can_detect_car_horn",
|
||||
ufp_enabled="is_car_horn_detection_on",
|
||||
ufp_event_obj="last_car_horn_detect_event",
|
||||
|
@ -565,7 +567,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
|
|||
key="smart_audio_glass_break",
|
||||
name="Glass break detected",
|
||||
icon="mdi:glass-fragile",
|
||||
ufp_value="last_glass_break_detect",
|
||||
ufp_obj_type=SmartDetectObjectType.GLASS_BREAK,
|
||||
ufp_required_field="can_detect_glass_break",
|
||||
ufp_enabled="is_glass_break_detection_on",
|
||||
ufp_event_obj="last_glass_break_detect_event",
|
||||
|
@ -709,11 +711,50 @@ class ProtectEventBinarySensor(EventEntityMixin, BinarySensorEntity):
|
|||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
super()._async_update_device_from_protect(device)
|
||||
is_on = self.entity_description.get_is_on(self.device, self._event)
|
||||
self._attr_is_on = is_on
|
||||
if not is_on:
|
||||
self._event = None
|
||||
description = self.entity_description
|
||||
event = self._event = self.entity_description.get_event_obj(device)
|
||||
if is_on := bool(description.get_ufp_value(device)):
|
||||
if event:
|
||||
self._set_event_attrs(event)
|
||||
else:
|
||||
self._attr_extra_state_attributes = {}
|
||||
self._attr_is_on = is_on
|
||||
|
||||
|
||||
class ProtectSmartEventBinarySensor(EventEntityMixin, BinarySensorEntity):
|
||||
"""A UniFi Protect Device Binary Sensor for smart events."""
|
||||
|
||||
device: Camera
|
||||
entity_description: ProtectBinaryEventEntityDescription
|
||||
_state_attrs = ("_attr_available", "_attr_is_on", "_attr_extra_state_attributes")
|
||||
|
||||
@callback
|
||||
def _set_event_done(self) -> None:
|
||||
self._attr_is_on = False
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
prev_event = self._event
|
||||
super()._async_update_device_from_protect(device)
|
||||
description = self.entity_description
|
||||
self._event = description.get_event_obj(device)
|
||||
|
||||
if not (
|
||||
(event := self._event)
|
||||
and not self._event_already_ended(prev_event)
|
||||
and description.has_matching_smart(event)
|
||||
and ((is_end := event.end) or self.device.is_smart_detected)
|
||||
):
|
||||
self._set_event_done()
|
||||
return
|
||||
|
||||
was_on = self._attr_is_on
|
||||
self._attr_is_on = True
|
||||
self._set_event_attrs(event)
|
||||
|
||||
if is_end and not was_on:
|
||||
self._async_event_with_immediate_end()
|
||||
|
||||
|
||||
MODEL_DESCRIPTIONS_WITH_CLASS = (
|
||||
|
@ -727,12 +768,19 @@ def _async_event_entities(
|
|||
data: ProtectData,
|
||||
ufp_device: ProtectAdoptableDeviceModel | None = None,
|
||||
) -> list[ProtectDeviceEntity]:
|
||||
return [
|
||||
ProtectEventBinarySensor(data, device, description)
|
||||
for device in (data.get_cameras() if ufp_device is None else [ufp_device])
|
||||
for description in EVENT_SENSORS
|
||||
if description.has_required(device)
|
||||
]
|
||||
entities: list[ProtectDeviceEntity] = []
|
||||
for device in data.get_cameras() if ufp_device is None else [ufp_device]:
|
||||
entities.extend(
|
||||
ProtectSmartEventBinarySensor(data, device, description)
|
||||
for description in SMART_EVENT_SENSORS
|
||||
if description.has_required(device)
|
||||
)
|
||||
entities.extend(
|
||||
ProtectEventBinarySensor(data, device, description)
|
||||
for description in EVENT_SENSORS
|
||||
if description.has_required(device)
|
||||
)
|
||||
return entities
|
||||
|
||||
|
||||
@callback
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue