Add support for animal detection in unifiprotect (#116290)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
William Taylor 2024-06-11 01:16:36 +10:00 committed by GitHub
parent 52379ad7cb
commit 30fab7b807
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 43 additions and 12 deletions

View file

@ -175,6 +175,15 @@ CAMERA_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
ufp_value="is_vehicle_detection_on", ufp_value="is_vehicle_detection_on",
ufp_perm=PermRequired.NO_WRITE, ufp_perm=PermRequired.NO_WRITE,
), ),
ProtectBinaryEntityDescription(
key="smart_animal",
name="Detections: Animal",
icon="mdi:paw",
entity_category=EntityCategory.DIAGNOSTIC,
ufp_required_field="can_detect_animal",
ufp_value="is_animal_detection_on",
ufp_perm=PermRequired.NO_WRITE,
),
ProtectBinaryEntityDescription( ProtectBinaryEntityDescription(
key="smart_package", key="smart_package",
name="Detections: Package", name="Detections: Package",
@ -453,6 +462,15 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
ufp_enabled="is_vehicle_detection_on", ufp_enabled="is_vehicle_detection_on",
ufp_event_obj="last_vehicle_detect_event", ufp_event_obj="last_vehicle_detect_event",
), ),
ProtectBinaryEventEntityDescription(
key="smart_obj_animal",
name="Animal Detected",
icon="mdi:paw",
ufp_value="is_animal_currently_detected",
ufp_required_field="can_detect_animal",
ufp_enabled="is_animal_detection_on",
ufp_event_obj="last_animal_detect_event",
),
ProtectBinaryEventEntityDescription( ProtectBinaryEventEntityDescription(
key="smart_obj_package", key="smart_obj_package",
name="Package Detected", name="Package Detected",

View file

@ -179,6 +179,17 @@ CAMERA_SWITCHES: tuple[ProtectSwitchEntityDescription, ...] = (
ufp_set_method="set_vehicle_detection", ufp_set_method="set_vehicle_detection",
ufp_perm=PermRequired.WRITE, ufp_perm=PermRequired.WRITE,
), ),
ProtectSwitchEntityDescription(
key="smart_animal",
name="Detections: Animal",
icon="mdi:paw",
entity_category=EntityCategory.CONFIG,
ufp_required_field="can_detect_animal",
ufp_value="is_animal_detection_on",
ufp_enabled="is_recording_enabled",
ufp_set_method="set_animal_detection",
ufp_perm=PermRequired.WRITE,
),
ProtectSwitchEntityDescription( ProtectSwitchEntityDescription(
key="smart_package", key="smart_package",
name="Detections: Package", name="Detections: Package",

View file

@ -216,6 +216,7 @@ def doorbell_fixture(camera: Camera, fixed_now: datetime):
doorbell.feature_flags.smart_detect_types = [ doorbell.feature_flags.smart_detect_types = [
SmartDetectObjectType.PERSON, SmartDetectObjectType.PERSON,
SmartDetectObjectType.VEHICLE, SmartDetectObjectType.VEHICLE,
SmartDetectObjectType.ANIMAL,
] ]
doorbell.has_speaker = True doorbell.has_speaker = True
doorbell.feature_flags.has_hdr = True doorbell.feature_flags.has_hdr = True

View file

@ -50,11 +50,11 @@ async def test_binary_sensor_camera_remove(
ufp.api.bootstrap.nvr.system_info.ustorage = None ufp.api.bootstrap.nvr.system_info.ustorage = None
await init_entry(hass, ufp, [doorbell, unadopted_camera]) await init_entry(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.BINARY_SENSOR, 7, 7) assert_entity_counts(hass, Platform.BINARY_SENSOR, 8, 8)
await remove_entities(hass, ufp, [doorbell, unadopted_camera]) await remove_entities(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.BINARY_SENSOR, 0, 0) assert_entity_counts(hass, Platform.BINARY_SENSOR, 0, 0)
await adopt_devices(hass, ufp, [doorbell, unadopted_camera]) await adopt_devices(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.BINARY_SENSOR, 7, 7) assert_entity_counts(hass, Platform.BINARY_SENSOR, 8, 8)
async def test_binary_sensor_light_remove( async def test_binary_sensor_light_remove(
@ -122,7 +122,7 @@ async def test_binary_sensor_setup_camera_all(
ufp.api.bootstrap.nvr.system_info.ustorage = None ufp.api.bootstrap.nvr.system_info.ustorage = None
await init_entry(hass, ufp, [doorbell, unadopted_camera]) await init_entry(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.BINARY_SENSOR, 7, 7) assert_entity_counts(hass, Platform.BINARY_SENSOR, 8, 8)
description = EVENT_SENSORS[0] description = EVENT_SENSORS[0]
unique_id, entity_id = ids_from_device_description( unique_id, entity_id = ids_from_device_description(
@ -274,7 +274,7 @@ async def test_binary_sensor_update_motion(
"""Test binary_sensor motion entity.""" """Test binary_sensor motion entity."""
await init_entry(hass, ufp, [doorbell, unadopted_camera]) await init_entry(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.BINARY_SENSOR, 13, 13) assert_entity_counts(hass, Platform.BINARY_SENSOR, 14, 14)
_, entity_id = ids_from_device_description( _, entity_id = ids_from_device_description(
Platform.BINARY_SENSOR, doorbell, EVENT_SENSORS[1] Platform.BINARY_SENSOR, doorbell, EVENT_SENSORS[1]

View file

@ -43,6 +43,7 @@ CAMERA_SWITCHES_BASIC = [
or d.name == "Detections: Motion" or d.name == "Detections: Motion"
or d.name == "Detections: Person" or d.name == "Detections: Person"
or d.name == "Detections: Vehicle" or d.name == "Detections: Vehicle"
or d.name == "Detections: Animal"
] ]
CAMERA_SWITCHES_NO_EXTRA = [ CAMERA_SWITCHES_NO_EXTRA = [
d d
@ -58,11 +59,11 @@ async def test_switch_camera_remove(
ufp.api.bootstrap.nvr.system_info.ustorage = None ufp.api.bootstrap.nvr.system_info.ustorage = None
await init_entry(hass, ufp, [doorbell, unadopted_camera]) await init_entry(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
await remove_entities(hass, ufp, [doorbell, unadopted_camera]) await remove_entities(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SWITCH, 2, 2) assert_entity_counts(hass, Platform.SWITCH, 2, 2)
await adopt_devices(hass, ufp, [doorbell, unadopted_camera]) await adopt_devices(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
async def test_switch_light_remove( async def test_switch_light_remove(
@ -174,7 +175,7 @@ async def test_switch_setup_camera_all(
"""Test switch entity setup for camera devices (all enabled feature flags).""" """Test switch entity setup for camera devices (all enabled feature flags)."""
await init_entry(hass, ufp, [doorbell]) await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
for description in CAMERA_SWITCHES_BASIC: for description in CAMERA_SWITCHES_BASIC:
unique_id, entity_id = ids_from_device_description( unique_id, entity_id = ids_from_device_description(
@ -294,7 +295,7 @@ async def test_switch_camera_ssh(
"""Tests SSH switch for cameras.""" """Tests SSH switch for cameras."""
await init_entry(hass, ufp, [doorbell]) await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
description = CAMERA_SWITCHES[0] description = CAMERA_SWITCHES[0]
@ -327,7 +328,7 @@ async def test_switch_camera_simple(
"""Tests all simple switches for cameras.""" """Tests all simple switches for cameras."""
await init_entry(hass, ufp, [doorbell]) await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
assert description.ufp_set_method is not None assert description.ufp_set_method is not None
@ -356,7 +357,7 @@ async def test_switch_camera_highfps(
"""Tests High FPS switch for cameras.""" """Tests High FPS switch for cameras."""
await init_entry(hass, ufp, [doorbell]) await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
description = CAMERA_SWITCHES[3] description = CAMERA_SWITCHES[3]
@ -387,7 +388,7 @@ async def test_switch_camera_privacy(
previous_record = doorbell.recording_settings.mode = RecordingMode.DETECTIONS previous_record = doorbell.recording_settings.mode = RecordingMode.DETECTIONS
await init_entry(hass, ufp, [doorbell]) await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
description = PRIVACY_MODE_SWITCH description = PRIVACY_MODE_SWITCH
@ -439,7 +440,7 @@ async def test_switch_camera_privacy_already_on(
doorbell.add_privacy_zone() doorbell.add_privacy_zone()
await init_entry(hass, ufp, [doorbell]) await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 13) assert_entity_counts(hass, Platform.SWITCH, 16, 14)
description = PRIVACY_MODE_SWITCH description = PRIVACY_MODE_SWITCH