Add new fields from UniFi Protect v3 (#113631)

pull/113619/head
Christopher Bailey 2024-03-16 19:17:23 -04:00 committed by GitHub
parent 73f11064d7
commit e703baba0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 70 additions and 25 deletions

View File

@ -120,6 +120,20 @@ CAMERA_NUMBERS: tuple[ProtectNumberEntityDescription, ...] = (
ufp_set_method="set_chime_duration",
ufp_perm=PermRequired.WRITE,
),
ProtectNumberEntityDescription(
key="icr_lux",
name="Infrared Custom Lux Trigger",
icon="mdi:white-balance-sunny",
entity_category=EntityCategory.CONFIG,
ufp_min=1,
ufp_max=30,
ufp_step=1,
ufp_required_field="feature_flags.has_led_ir",
ufp_value="icr_lux_display",
ufp_set_method="set_icr_custom_lux",
ufp_enabled="is_ir_led_slider_enabled",
ufp_perm=PermRequired.WRITE,
),
)
LIGHT_NUMBERS: tuple[ProtectNumberEntityDescription, ...] = (

View File

@ -42,6 +42,12 @@ from .utils import async_dispatch_id as _ufpd, async_get_light_motion_current
_LOGGER = logging.getLogger(__name__)
_KEY_LIGHT_MOTION = "light_motion"
HDR_MODES = [
{"id": "always", "name": "Always On"},
{"id": "off", "name": "Always Off"},
{"id": "auto", "name": "Auto"},
]
INFRARED_MODES = [
{"id": IRLEDMode.AUTO.value, "name": "Auto"},
{"id": IRLEDMode.ON.value, "name": "Always Enable"},
@ -228,6 +234,17 @@ CAMERA_SELECTS: tuple[ProtectSelectEntityDescription, ...] = (
ufp_set_method="set_chime_type",
ufp_perm=PermRequired.WRITE,
),
ProtectSelectEntityDescription(
key="hdr_mode",
name="HDR Mode",
icon="mdi:brightness-7",
entity_category=EntityCategory.CONFIG,
ufp_required_field="feature_flags.has_hdr",
ufp_options=HDR_MODES,
ufp_value="hdr_mode_display",
ufp_set_method="set_hdr_mode",
ufp_perm=PermRequired.WRITE,
),
)
LIGHT_SELECTS: tuple[ProtectSelectEntityDescription, ...] = (

View File

@ -74,6 +74,7 @@ CAMERA_SWITCHES: tuple[ProtectSwitchEntityDescription, ...] = (
name="HDR Mode",
icon="mdi:brightness-7",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
ufp_required_field="feature_flags.has_hdr",
ufp_value="hdr_mode",
ufp_set_method="set_hdr",

View File

@ -6,7 +6,7 @@ from datetime import timedelta
from unittest.mock import AsyncMock, Mock
import pytest
from pyunifiprotect.data import Camera, Doorlock, Light
from pyunifiprotect.data import Camera, Doorlock, IRLEDMode, Light
from homeassistant.components.unifiprotect.const import DEFAULT_ATTRIBUTION
from homeassistant.components.unifiprotect.number import (
@ -35,11 +35,11 @@ async def test_number_sensor_camera_remove(
"""Test removing and re-adding a camera device."""
await init_entry(hass, ufp, [camera, unadopted_camera])
assert_entity_counts(hass, Platform.NUMBER, 3, 3)
assert_entity_counts(hass, Platform.NUMBER, 4, 4)
await remove_entities(hass, ufp, [camera, unadopted_camera])
assert_entity_counts(hass, Platform.NUMBER, 0, 0)
await adopt_devices(hass, ufp, [camera, unadopted_camera])
assert_entity_counts(hass, Platform.NUMBER, 3, 3)
assert_entity_counts(hass, Platform.NUMBER, 4, 4)
async def test_number_sensor_light_remove(
@ -99,8 +99,11 @@ async def test_number_setup_camera_all(
camera.feature_flags.has_chime = True
camera.chime_duration = timedelta(seconds=1)
camera.feature_flags.has_led_ir = True
camera.isp_settings.icr_custom_value = 1
camera.isp_settings.ir_led_mode = IRLEDMode.CUSTOM
await init_entry(hass, ufp, [camera])
assert_entity_counts(hass, Platform.NUMBER, 4, 4)
assert_entity_counts(hass, Platform.NUMBER, 5, 5)
entity_registry = er.async_get(hass)
@ -128,6 +131,7 @@ async def test_number_setup_camera_none(
camera.feature_flags.has_mic = False
# has_wdr is an the inverse of has HDR
camera.feature_flags.has_hdr = True
camera.feature_flags.has_led_ir = False
await init_entry(hass, ufp, [camera])
assert_entity_counts(hass, Platform.NUMBER, 0, 0)
@ -199,7 +203,7 @@ async def test_number_camera_simple(
"""Tests all simple numbers for cameras."""
await init_entry(hass, ufp, [camera])
assert_entity_counts(hass, Platform.NUMBER, 3, 3)
assert_entity_counts(hass, Platform.NUMBER, 4, 4)
assert description.ufp_set_method is not None

View File

@ -48,11 +48,11 @@ async def test_select_camera_remove(
ufp.api.bootstrap.nvr.system_info.ustorage = None
await init_entry(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
await remove_entities(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SELECT, 0, 0)
await adopt_devices(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
async def test_select_light_remove(
@ -142,10 +142,16 @@ async def test_select_setup_camera_all(
"""Test select entity setup for camera devices (all features)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
entity_registry = er.async_get(hass)
expected_values = ("Always", "Auto", "Default Message (Welcome)", "None")
expected_values = (
"Always",
"Auto",
"Default Message (Welcome)",
"None",
"Always Off",
)
for index, description in enumerate(CAMERA_SELECTS):
unique_id, entity_id = ids_from_device_description(
@ -233,7 +239,7 @@ async def test_select_update_doorbell_settings(
"""Test select entity update (new Doorbell Message)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
expected_length = len(ufp.api.bootstrap.nvr.doorbell_settings.all_messages) + 1
@ -279,7 +285,7 @@ async def test_select_update_doorbell_message(
"""Test select entity update (change doorbell message)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
_, entity_id = ids_from_device_description(
Platform.SELECT, doorbell, CAMERA_SELECTS[2]
@ -372,7 +378,7 @@ async def test_select_set_option_camera_recording(
"""Test Recording Mode select."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
_, entity_id = ids_from_device_description(
Platform.SELECT, doorbell, CAMERA_SELECTS[0]
@ -397,7 +403,7 @@ async def test_select_set_option_camera_ir(
"""Test Infrared Mode select."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
_, entity_id = ids_from_device_description(
Platform.SELECT, doorbell, CAMERA_SELECTS[1]
@ -422,7 +428,7 @@ async def test_select_set_option_camera_doorbell_custom(
"""Test Doorbell Text select (user defined message)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
_, entity_id = ids_from_device_description(
Platform.SELECT, doorbell, CAMERA_SELECTS[2]
@ -449,7 +455,7 @@ async def test_select_set_option_camera_doorbell_unifi(
"""Test Doorbell Text select (unifi message)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
_, entity_id = ids_from_device_description(
Platform.SELECT, doorbell, CAMERA_SELECTS[2]
@ -491,7 +497,7 @@ async def test_select_set_option_camera_doorbell_default(
"""Test Doorbell Text select (default message)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SELECT, 4, 4)
assert_entity_counts(hass, Platform.SELECT, 5, 5)
_, entity_id = ids_from_device_description(
Platform.SELECT, doorbell, CAMERA_SELECTS[2]

View File

@ -38,13 +38,16 @@ CAMERA_SWITCHES_BASIC = [
and d.name != "SSH Enabled"
and d.name != "Color Night Vision"
and d.name != "Tracking: Person"
and d.name != "HDR Mode"
)
or d.name == "Detections: Motion"
or d.name == "Detections: Person"
or d.name == "Detections: Vehicle"
]
CAMERA_SWITCHES_NO_EXTRA = [
d for d in CAMERA_SWITCHES_BASIC if d.name not in ("High FPS", "Privacy Mode")
d
for d in CAMERA_SWITCHES_BASIC
if d.name not in ("High FPS", "Privacy Mode", "HDR Mode")
]
@ -55,11 +58,11 @@ async def test_switch_camera_remove(
ufp.api.bootstrap.nvr.system_info.ustorage = None
await init_entry(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
await remove_entities(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SWITCH, 2, 2)
await adopt_devices(hass, ufp, [doorbell, unadopted_camera])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
async def test_switch_light_remove(
@ -171,7 +174,7 @@ async def test_switch_setup_camera_all(
"""Test switch entity setup for camera devices (all enabled feature flags)."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
entity_registry = er.async_get(hass)
@ -294,7 +297,7 @@ async def test_switch_camera_ssh(
"""Tests SSH switch for cameras."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
description = CAMERA_SWITCHES[0]
@ -327,7 +330,7 @@ async def test_switch_camera_simple(
"""Tests all simple switches for cameras."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
assert description.ufp_set_method is not None
@ -356,7 +359,7 @@ async def test_switch_camera_highfps(
"""Tests High FPS switch for cameras."""
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
description = CAMERA_SWITCHES[3]
@ -387,7 +390,7 @@ async def test_switch_camera_privacy(
previous_record = doorbell.recording_settings.mode = RecordingMode.DETECTIONS
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
description = PRIVACY_MODE_SWITCH
@ -439,7 +442,7 @@ async def test_switch_camera_privacy_already_on(
doorbell.add_privacy_zone()
await init_entry(hass, ufp, [doorbell])
assert_entity_counts(hass, Platform.SWITCH, 15, 14)
assert_entity_counts(hass, Platform.SWITCH, 15, 13)
description = PRIVACY_MODE_SWITCH