diff --git a/homeassistant/components/unifiprotect/binary_sensor.py b/homeassistant/components/unifiprotect/binary_sensor.py index 7aa7c6d5cf1..fe4399c4c6d 100644 --- a/homeassistant/components/unifiprotect/binary_sensor.py +++ b/homeassistant/components/unifiprotect/binary_sensor.py @@ -14,8 +14,6 @@ from pyunifiprotect.data import ( ProtectAdoptableDeviceModel, ProtectModelWithId, Sensor, - SmartDetectAudioType, - SmartDetectObjectType, ) from pyunifiprotect.data.nvr import UOSDisk @@ -364,8 +362,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = ( ufp_value="is_smart_detected", ufp_required_field="can_detect_person", ufp_enabled="is_person_detection_on", - ufp_event_obj="last_smart_detect_event", - ufp_smart_type=SmartDetectObjectType.PERSON, + ufp_event_obj="last_person_detect_event", ), ProtectBinaryEventEntityDescription( key="smart_obj_vehicle", @@ -374,8 +371,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = ( ufp_value="is_smart_detected", ufp_required_field="can_detect_vehicle", ufp_enabled="is_vehicle_detection_on", - ufp_event_obj="last_smart_detect_event", - ufp_smart_type=SmartDetectObjectType.VEHICLE, + ufp_event_obj="last_vehicle_detect_event", ), ProtectBinaryEventEntityDescription( key="smart_obj_face", @@ -384,8 +380,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = ( ufp_value="is_smart_detected", ufp_required_field="can_detect_face", ufp_enabled="is_face_detection_on", - ufp_event_obj="last_smart_detect_event", - ufp_smart_type=SmartDetectObjectType.FACE, + ufp_event_obj="last_face_detect_event", ), ProtectBinaryEventEntityDescription( key="smart_obj_package", @@ -394,8 +389,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = ( ufp_value="is_smart_detected", ufp_required_field="can_detect_package", ufp_enabled="is_package_detection_on", - ufp_event_obj="last_smart_detect_event", - ufp_smart_type=SmartDetectObjectType.PACKAGE, + ufp_event_obj="last_package_detect_event", ), ProtectBinaryEventEntityDescription( key="smart_audio_any", @@ -412,8 +406,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = ( ufp_value="is_smart_detected", ufp_required_field="can_detect_smoke", ufp_enabled="is_smoke_detection_on", - ufp_event_obj="last_smart_audio_detect_event", - ufp_smart_type=SmartDetectAudioType.SMOKE, + ufp_event_obj="last_smoke_detect_event", ), ProtectBinaryEventEntityDescription( key="smart_audio_cmonx", @@ -422,8 +415,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = ( ufp_value="is_smart_detected", ufp_required_field="can_detect_smoke", ufp_enabled="is_smoke_detection_on", - ufp_event_obj="last_smart_audio_detect_event", - ufp_smart_type=SmartDetectAudioType.CMONX, + ufp_event_obj="last_cmonx_detect_event", ), ) diff --git a/homeassistant/components/unifiprotect/data.py b/homeassistant/components/unifiprotect/data.py index 68d48003ba6..88c500f18fd 100644 --- a/homeassistant/components/unifiprotect/data.py +++ b/homeassistant/components/unifiprotect/data.py @@ -40,6 +40,11 @@ from .utils import async_dispatch_id as _ufpd, async_get_devices_by_type _LOGGER = logging.getLogger(__name__) ProtectDeviceType = ProtectAdoptableDeviceModel | NVR +SMART_EVENTS = { + EventType.SMART_DETECT, + EventType.SMART_AUDIO_DETECT, + EventType.SMART_DETECT_LINE, +} @callback @@ -223,6 +228,25 @@ class ProtectData: # trigger updates for camera that the event references elif isinstance(obj, Event): + if obj.type in SMART_EVENTS: + if obj.camera is not None: + if obj.end is None: + _LOGGER.debug( + "%s (%s): New smart detection started for %s (%s)", + obj.camera.name, + obj.camera.mac, + obj.smart_detect_types, + obj.id, + ) + else: + _LOGGER.debug( + "%s (%s): Smart detection ended for %s (%s)", + obj.camera.name, + obj.camera.mac, + obj.smart_detect_types, + obj.id, + ) + if obj.type == EventType.DEVICE_ADOPTED: if obj.metadata is not None and obj.metadata.device_id is not None: device = self.api.bootstrap.get_device_from_id( diff --git a/homeassistant/components/unifiprotect/manifest.json b/homeassistant/components/unifiprotect/manifest.json index a2bb76c92b7..e16180b03bc 100644 --- a/homeassistant/components/unifiprotect/manifest.json +++ b/homeassistant/components/unifiprotect/manifest.json @@ -41,7 +41,7 @@ "iot_class": "local_push", "loggers": ["pyunifiprotect", "unifi_discovery"], "quality_scale": "platinum", - "requirements": ["pyunifiprotect==4.9.1", "unifi-discovery==1.1.7"], + "requirements": ["pyunifiprotect==4.10.0", "unifi-discovery==1.1.7"], "ssdp": [ { "manufacturer": "Ubiquiti Networks", diff --git a/homeassistant/components/unifiprotect/models.py b/homeassistant/components/unifiprotect/models.py index 40280c02867..8c688231628 100644 --- a/homeassistant/components/unifiprotect/models.py +++ b/homeassistant/components/unifiprotect/models.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Callable, Coroutine from dataclasses import dataclass +from datetime import timedelta from enum import Enum import logging from typing import Any, Generic, TypeVar, cast @@ -10,6 +11,7 @@ from typing import Any, Generic, TypeVar, cast from pyunifiprotect.data import NVR, Event, ProtectAdoptableDeviceModel from homeassistant.helpers.entity import EntityDescription +from homeassistant.util import dt as dt_util from .utils import get_nested_attr @@ -67,7 +69,6 @@ class ProtectEventMixin(ProtectRequiredKeysMixin[T]): """Mixin for events.""" ufp_event_obj: str | None = None - ufp_smart_type: str | None = None def get_event_obj(self, obj: T) -> Event | None: """Return value from UniFi Protect device.""" @@ -79,23 +80,22 @@ class ProtectEventMixin(ProtectRequiredKeysMixin[T]): def get_is_on(self, obj: T) -> bool: """Return value if event is active.""" - value = bool(self.get_ufp_value(obj)) - if value: - event = self.get_event_obj(obj) - value = event is not None - if not value: - _LOGGER.debug("%s (%s): missing event", self.name, obj.mac) + event = self.get_event_obj(obj) + if event is None: + return False - if event is not None and self.ufp_smart_type is not None: - value = self.ufp_smart_type in event.smart_detect_types - if not value: - _LOGGER.debug( - "%s (%s): %s not in %s", - self.name, - obj.mac, - self.ufp_smart_type, - event.smart_detect_types, - ) + now = dt_util.utcnow() + value = now > event.start + if value and event.end is not None and now > event.end: + value = False + # only log if the recent ended recently + if event.end + timedelta(seconds=10) < now: + _LOGGER.debug( + "%s (%s): end ended at %s", + self.name, + obj.mac, + event.end.isoformat(), + ) if value: _LOGGER.debug("%s (%s): value is on", self.name, obj.mac) diff --git a/homeassistant/components/unifiprotect/sensor.py b/homeassistant/components/unifiprotect/sensor.py index 783955b3401..dec6f10a57f 100644 --- a/homeassistant/components/unifiprotect/sensor.py +++ b/homeassistant/components/unifiprotect/sensor.py @@ -15,7 +15,6 @@ from pyunifiprotect.data import ( ProtectDeviceModel, ProtectModelWithId, Sensor, - SmartDetectObjectType, ) from homeassistant.components.sensor import ( @@ -528,10 +527,9 @@ EVENT_SENSORS: tuple[ProtectSensorEventEntityDescription, ...] = ( name="License Plate Detected", icon="mdi:car", translation_key="license_plate", - ufp_smart_type=SmartDetectObjectType.LICENSE_PLATE, ufp_value="is_smart_detected", ufp_required_field="can_detect_license_plate", - ufp_event_obj="last_smart_detect_event", + ufp_event_obj="last_license_plate_detect_event", ), ) @@ -767,8 +765,7 @@ class ProtectEventSensor(EventEntityMixin, SensorEntity): EventEntityMixin._async_update_device_from_protect(self, device) is_on = self.entity_description.get_is_on(device) is_license_plate = ( - self.entity_description.ufp_smart_type - == SmartDetectObjectType.LICENSE_PLATE + self.entity_description.ufp_event_obj == "last_license_plate_detect_event" ) if ( not is_on diff --git a/requirements_all.txt b/requirements_all.txt index dfbbf3e5f56..f0e69631d5d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2184,7 +2184,7 @@ pytrafikverket==0.3.3 pyudev==0.23.2 # homeassistant.components.unifiprotect -pyunifiprotect==4.9.1 +pyunifiprotect==4.10.0 # homeassistant.components.uptimerobot pyuptimerobot==22.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 962ba12a3d0..55d4af9ecca 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1598,7 +1598,7 @@ pytrafikverket==0.3.3 pyudev==0.23.2 # homeassistant.components.unifiprotect -pyunifiprotect==4.9.1 +pyunifiprotect==4.10.0 # homeassistant.components.uptimerobot pyuptimerobot==22.2.0 diff --git a/tests/components/unifiprotect/test_sensor.py b/tests/components/unifiprotect/test_sensor.py index db7cdc801bf..89a153caed2 100644 --- a/tests/components/unifiprotect/test_sensor.py +++ b/tests/components/unifiprotect/test_sensor.py @@ -537,7 +537,9 @@ async def test_camera_update_licenseplate( new_camera = camera.copy() new_camera.is_smart_detected = True - new_camera.last_smart_detect_event_id = event.id + new_camera.last_smart_detect_event_ids[ + SmartDetectObjectType.LICENSE_PLATE + ] = event.id mock_msg = Mock() mock_msg.changed_data = {}