Add sensors for read-only devices for UniFi Protect (#73768)
This commit is contained in:
parent
db9c242723
commit
9940a85e28
8 changed files with 391 additions and 31 deletions
|
@ -34,7 +34,8 @@ from .entity import (
|
|||
ProtectNVREntity,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .models import ProtectRequiredKeysMixin
|
||||
from .models import PermRequired, ProtectRequiredKeysMixin
|
||||
from .utils import async_get_is_highfps
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_KEY_DOOR = "door"
|
||||
|
@ -69,6 +70,126 @@ CAMERA_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
|||
icon="mdi:brightness-6",
|
||||
ufp_value="is_dark",
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="ssh",
|
||||
name="SSH Enabled",
|
||||
icon="mdi:lock",
|
||||
entity_registry_enabled_default=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="is_ssh_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="status_light",
|
||||
name="Status Light On",
|
||||
icon="mdi:led-on",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_led_status",
|
||||
ufp_value="led_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="hdr_mode",
|
||||
name="HDR Mode",
|
||||
icon="mdi:brightness-7",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_hdr",
|
||||
ufp_value="hdr_mode",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="high_fps",
|
||||
name="High FPS",
|
||||
icon="mdi:video-high-definition",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_highfps",
|
||||
ufp_value_fn=async_get_is_highfps,
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="system_sounds",
|
||||
name="System Sounds",
|
||||
icon="mdi:speaker",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_speaker",
|
||||
ufp_value="speaker_settings.are_system_sounds_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="osd_name",
|
||||
name="Overlay: Show Name",
|
||||
icon="mdi:fullscreen",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="osd_settings.is_name_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="osd_date",
|
||||
name="Overlay: Show Date",
|
||||
icon="mdi:fullscreen",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="osd_settings.is_date_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="osd_logo",
|
||||
name="Overlay: Show Logo",
|
||||
icon="mdi:fullscreen",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="osd_settings.is_logo_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="osd_bitrate",
|
||||
name="Overlay: Show Bitrate",
|
||||
icon="mdi:fullscreen",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="osd_settings.is_debug_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="motion",
|
||||
name="Detections: Motion",
|
||||
icon="mdi:run-fast",
|
||||
ufp_value="recording_settings.enable_motion_detection",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="smart_person",
|
||||
name="Detections: Person",
|
||||
icon="mdi:walk",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="can_detect_person",
|
||||
ufp_value="is_person_detection_on",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="smart_vehicle",
|
||||
name="Detections: Vehicle",
|
||||
icon="mdi:car",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="can_detect_vehicle",
|
||||
ufp_value="is_vehicle_detection_on",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="smart_face",
|
||||
name="Detections: Face",
|
||||
icon="mdi:human-greeting",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="can_detect_face",
|
||||
ufp_value="is_face_detection_on",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="smart_package",
|
||||
name="Detections: Package",
|
||||
icon="mdi:package-variant-closed",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="can_detect_package",
|
||||
ufp_value="is_package_detection_on",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
LIGHT_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
||||
|
@ -84,6 +205,31 @@ LIGHT_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
|||
device_class=BinarySensorDeviceClass.MOTION,
|
||||
ufp_value="is_pir_motion_detected",
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="light",
|
||||
name="Flood Light",
|
||||
icon="mdi:spotlight-beam",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="is_light_on",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="ssh",
|
||||
name="SSH Enabled",
|
||||
icon="mdi:lock",
|
||||
entity_registry_enabled_default=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="is_ssh_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="status_light",
|
||||
name="Status Light On",
|
||||
icon="mdi:led-on",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="light_device_settings.is_indicator_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
SENSE_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
||||
|
@ -114,6 +260,53 @@ SENSE_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
|||
device_class=BinarySensorDeviceClass.TAMPER,
|
||||
ufp_value="is_tampering_detected",
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="status_light",
|
||||
name="Status Light On",
|
||||
icon="mdi:led-on",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="led_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="motion",
|
||||
name="Motion Detection",
|
||||
icon="mdi:walk",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="motion_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="temperature",
|
||||
name="Temperature Sensor",
|
||||
icon="mdi:thermometer",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="temperature_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="humidity",
|
||||
name="Humidity Sensor",
|
||||
icon="mdi:water-percent",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="humidity_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="light",
|
||||
name="Light Sensor",
|
||||
icon="mdi:brightness-5",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="light_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="alarm",
|
||||
name="Alarm Sound Detection",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="alarm_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
MOTION_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
||||
|
@ -133,6 +326,26 @@ DOORLOCK_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
|||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="battery_status.is_low",
|
||||
),
|
||||
ProtectBinaryEntityDescription(
|
||||
key="status_light",
|
||||
name="Status Light On",
|
||||
icon="mdi:led-on",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="led_settings.is_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
VIEWER_SENSORS: tuple[ProtectBinaryEntityDescription, ...] = (
|
||||
ProtectBinaryEntityDescription(
|
||||
key="ssh",
|
||||
name="SSH Enabled",
|
||||
icon="mdi:lock",
|
||||
entity_registry_enabled_default=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="is_ssh_enabled",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -159,6 +372,7 @@ async def async_setup_entry(
|
|||
light_descs=LIGHT_SENSORS,
|
||||
sense_descs=SENSE_SENSORS,
|
||||
lock_descs=DOORLOCK_SENSORS,
|
||||
viewer_descs=VIEWER_SENSORS,
|
||||
)
|
||||
entities += _async_motion_entities(data)
|
||||
entities += _async_nvr_entities(data)
|
||||
|
|
|
@ -50,6 +50,8 @@ def _async_device_entities(
|
|||
can_write = device.can_write(data.api.bootstrap.auth_user)
|
||||
if description.ufp_perm == PermRequired.WRITE and not can_write:
|
||||
continue
|
||||
if description.ufp_perm == PermRequired.NO_WRITE and can_write:
|
||||
continue
|
||||
|
||||
if description.ufp_required_field:
|
||||
required_field = get_nested_attr(device, description.ufp_required_field)
|
||||
|
|
|
@ -39,6 +39,7 @@ from .const import ATTR_DURATION, ATTR_MESSAGE, DOMAIN, TYPE_EMPTY_VALUE
|
|||
from .data import ProtectData
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectSetableKeysMixin, T
|
||||
from .utils import async_get_light_motion_current
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_KEY_LIGHT_MOTION = "light_motion"
|
||||
|
@ -151,16 +152,6 @@ def _get_viewer_current(obj: Viewer) -> str:
|
|||
return obj.liveview_id
|
||||
|
||||
|
||||
def _get_light_motion_current(obj: Light) -> str:
|
||||
# a bit of extra to allow On Motion Always/Dark
|
||||
if (
|
||||
obj.light_mode_settings.mode == LightModeType.MOTION
|
||||
and obj.light_mode_settings.enable_at == LightModeEnableType.DARK
|
||||
):
|
||||
return f"{LightModeType.MOTION.value}Dark"
|
||||
return obj.light_mode_settings.mode.value
|
||||
|
||||
|
||||
def _get_doorbell_current(obj: Camera) -> str | None:
|
||||
if obj.lcd_message is None:
|
||||
return None
|
||||
|
@ -255,7 +246,7 @@ LIGHT_SELECTS: tuple[ProtectSelectEntityDescription, ...] = (
|
|||
icon="mdi:spotlight",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
ufp_options=MOTION_MODE_TO_LIGHT_MODE,
|
||||
ufp_value_fn=_get_light_motion_current,
|
||||
ufp_value_fn=async_get_light_motion_current,
|
||||
ufp_set_method_fn=_set_light_mode,
|
||||
ufp_perm=PermRequired.WRITE,
|
||||
),
|
||||
|
|
|
@ -10,6 +10,7 @@ from pyunifiprotect.data import (
|
|||
NVR,
|
||||
Camera,
|
||||
Event,
|
||||
Light,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectDeviceModel,
|
||||
ProtectModelWithId,
|
||||
|
@ -46,7 +47,8 @@ from .entity import (
|
|||
ProtectNVREntity,
|
||||
async_all_device_entities,
|
||||
)
|
||||
from .models import ProtectRequiredKeysMixin, T
|
||||
from .models import PermRequired, ProtectRequiredKeysMixin, T
|
||||
from .utils import async_get_light_motion_current
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
OBJECT_TYPE_NONE = "none"
|
||||
|
@ -197,6 +199,51 @@ CAMERA_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
|||
ufp_value="last_ring",
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="mic_level",
|
||||
name="Microphone Level",
|
||||
icon="mdi:microphone",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_mic",
|
||||
ufp_value="mic_volume",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="recording_mode",
|
||||
name="Recording Mode",
|
||||
icon="mdi:video-outline",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="recording_settings.mode",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="infrared",
|
||||
name="Infrared Mode",
|
||||
icon="mdi:circle-opacity",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_led_ir",
|
||||
ufp_value="isp_settings.ir_led_mode",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="doorbell_text",
|
||||
name="Doorbell Text",
|
||||
icon="mdi:card-text",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_required_field="feature_flags.has_lcd_screen",
|
||||
ufp_value="lcd_message.text",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="chime_type",
|
||||
name="Chime Type",
|
||||
icon="mdi:bell",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
ufp_required_field="feature_flags.has_chime",
|
||||
ufp_value="chime_type",
|
||||
),
|
||||
)
|
||||
|
||||
CAMERA_DISABLED_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
||||
|
@ -284,6 +331,31 @@ SENSE_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
|||
ufp_value="tampering_detected_at",
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="sensitivity",
|
||||
name="Motion Sensitivity",
|
||||
icon="mdi:walk",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="motion_settings.sensitivity",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="mount_type",
|
||||
name="Mount Type",
|
||||
icon="mdi:screwdriver",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="mount_type",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="paired_camera",
|
||||
name="Paired Camera",
|
||||
icon="mdi:cctv",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="camera.name",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
DOORLOCK_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
||||
|
@ -296,6 +368,14 @@ DOORLOCK_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
|||
state_class=SensorStateClass.MEASUREMENT,
|
||||
ufp_value="battery_status.percentage",
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="paired_camera",
|
||||
name="Paired Camera",
|
||||
icon="mdi:cctv",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="camera.name",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
NVR_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
||||
|
@ -439,6 +519,31 @@ LIGHT_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
|||
ufp_value="last_motion",
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="sensitivity",
|
||||
name="Motion Sensitivity",
|
||||
icon="mdi:walk",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="light_device_settings.pir_sensitivity",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription[Light](
|
||||
key="light_motion",
|
||||
name="Light Mode",
|
||||
icon="mdi:spotlight",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value_fn=async_get_light_motion_current,
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="paired_camera",
|
||||
name="Paired Camera",
|
||||
icon="mdi:cctv",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="camera.name",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
MOTION_TRIP_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
||||
|
@ -459,6 +564,26 @@ CHIME_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
|||
icon="mdi:bell",
|
||||
ufp_value="last_ring",
|
||||
),
|
||||
ProtectSensorEntityDescription(
|
||||
key="volume",
|
||||
name="Volume",
|
||||
icon="mdi:speaker",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="volume",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
VIEWER_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
|
||||
ProtectSensorEntityDescription(
|
||||
key="viewer",
|
||||
name="Liveview",
|
||||
icon="mdi:view-dashboard",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
ufp_value="liveview.name",
|
||||
ufp_perm=PermRequired.NO_WRITE,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -478,6 +603,7 @@ async def async_setup_entry(
|
|||
light_descs=LIGHT_SENSORS,
|
||||
lock_descs=DOORLOCK_SENSORS,
|
||||
chime_descs=CHIME_SENSORS,
|
||||
viewer_descs=VIEWER_SENSORS,
|
||||
)
|
||||
entities += _async_motion_entities(data)
|
||||
entities += _async_nvr_entities(data)
|
||||
|
|
|
@ -22,6 +22,7 @@ from .const import DOMAIN
|
|||
from .data import ProtectData
|
||||
from .entity import ProtectDeviceEntity, async_all_device_entities
|
||||
from .models import PermRequired, ProtectSetableKeysMixin, T
|
||||
from .utils import async_get_is_highfps
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -36,10 +37,6 @@ class ProtectSwitchEntityDescription(
|
|||
_KEY_PRIVACY_MODE = "privacy_mode"
|
||||
|
||||
|
||||
def _get_is_highfps(obj: Camera) -> bool:
|
||||
return bool(obj.video_mode == VideoMode.HIGH_FPS)
|
||||
|
||||
|
||||
async def _set_highfps(obj: Camera, value: bool) -> None:
|
||||
if value:
|
||||
await obj.set_video_mode(VideoMode.HIGH_FPS)
|
||||
|
@ -84,7 +81,7 @@ CAMERA_SWITCHES: tuple[ProtectSwitchEntityDescription, ...] = (
|
|||
icon="mdi:video-high-definition",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
ufp_required_field="feature_flags.has_highfps",
|
||||
ufp_value_fn=_get_is_highfps,
|
||||
ufp_value_fn=async_get_is_highfps,
|
||||
ufp_set_method_fn=_set_highfps,
|
||||
ufp_perm=PermRequired.WRITE,
|
||||
),
|
||||
|
|
|
@ -9,8 +9,13 @@ from typing import Any
|
|||
|
||||
from pyunifiprotect.data import (
|
||||
Bootstrap,
|
||||
Camera,
|
||||
Light,
|
||||
LightModeEnableType,
|
||||
LightModeType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
ProtectDeviceModel,
|
||||
VideoMode,
|
||||
)
|
||||
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
|
@ -104,3 +109,22 @@ def async_get_devices(
|
|||
for device_type in model_type
|
||||
for device in async_get_devices_by_type(bootstrap, device_type).values()
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_is_highfps(obj: Camera) -> bool:
|
||||
"""Return if camera has High FPS mode enabled."""
|
||||
|
||||
return bool(obj.video_mode == VideoMode.HIGH_FPS)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_light_motion_current(obj: Light) -> str:
|
||||
"""Get light motion mode for Flood Light."""
|
||||
|
||||
if (
|
||||
obj.light_mode_settings.mode == LightModeType.MOTION
|
||||
and obj.light_mode_settings.enable_at == LightModeEnableType.DARK
|
||||
):
|
||||
return f"{LightModeType.MOTION.value}Dark"
|
||||
return obj.light_mode_settings.mode.value
|
||||
|
|
|
@ -39,6 +39,9 @@ from .conftest import (
|
|||
reset_objects,
|
||||
)
|
||||
|
||||
LIGHT_SENSOR_WRITE = LIGHT_SENSORS[:2]
|
||||
SENSE_SENSORS_WRITE = SENSE_SENSORS[:4]
|
||||
|
||||
|
||||
@pytest.fixture(name="camera")
|
||||
async def camera_fixture(
|
||||
|
@ -230,7 +233,7 @@ async def test_binary_sensor_setup_light(
|
|||
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
for description in LIGHT_SENSORS:
|
||||
for description in LIGHT_SENSOR_WRITE:
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
Platform.BINARY_SENSOR, light, description
|
||||
)
|
||||
|
@ -328,7 +331,7 @@ async def test_binary_sensor_setup_sensor(
|
|||
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
for description in SENSE_SENSORS:
|
||||
for description in SENSE_SENSORS_WRITE:
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
Platform.BINARY_SENSOR, sensor, description
|
||||
)
|
||||
|
@ -356,7 +359,7 @@ async def test_binary_sensor_setup_sensor_none(
|
|||
STATE_UNAVAILABLE,
|
||||
STATE_OFF,
|
||||
]
|
||||
for index, description in enumerate(SENSE_SENSORS):
|
||||
for index, description in enumerate(SENSE_SENSORS_WRITE):
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
Platform.BINARY_SENSOR, sensor_none, description
|
||||
)
|
||||
|
@ -419,7 +422,7 @@ async def test_binary_sensor_update_light_motion(
|
|||
"""Test binary_sensor motion entity."""
|
||||
|
||||
_, entity_id = ids_from_device_description(
|
||||
Platform.BINARY_SENSOR, light, LIGHT_SENSORS[1]
|
||||
Platform.BINARY_SENSOR, light, LIGHT_SENSOR_WRITE[1]
|
||||
)
|
||||
|
||||
event_metadata = EventMetadata(light_id=light.id)
|
||||
|
@ -461,7 +464,7 @@ async def test_binary_sensor_update_mount_type_window(
|
|||
"""Test binary_sensor motion entity."""
|
||||
|
||||
_, entity_id = ids_from_device_description(
|
||||
Platform.BINARY_SENSOR, sensor, SENSE_SENSORS[0]
|
||||
Platform.BINARY_SENSOR, sensor, SENSE_SENSORS_WRITE[0]
|
||||
)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
@ -492,7 +495,7 @@ async def test_binary_sensor_update_mount_type_garage(
|
|||
"""Test binary_sensor motion entity."""
|
||||
|
||||
_, entity_id = ids_from_device_description(
|
||||
Platform.BINARY_SENSOR, sensor, SENSE_SENSORS[0]
|
||||
Platform.BINARY_SENSOR, sensor, SENSE_SENSORS_WRITE[0]
|
||||
)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
|
|
|
@ -51,6 +51,9 @@ from .conftest import (
|
|||
time_changed,
|
||||
)
|
||||
|
||||
CAMERA_SENSORS_WRITE = CAMERA_SENSORS[:5]
|
||||
SENSE_SENSORS_WRITE = SENSE_SENSORS[:8]
|
||||
|
||||
|
||||
@pytest.fixture(name="sensor")
|
||||
async def sensor_fixture(
|
||||
|
@ -193,7 +196,7 @@ async def test_sensor_setup_sensor(
|
|||
"10.0",
|
||||
"none",
|
||||
)
|
||||
for index, description in enumerate(SENSE_SENSORS):
|
||||
for index, description in enumerate(SENSE_SENSORS_WRITE):
|
||||
if not description.entity_registry_enabled_default:
|
||||
continue
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
|
@ -241,7 +244,7 @@ async def test_sensor_setup_sensor_none(
|
|||
STATE_UNAVAILABLE,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
for index, description in enumerate(SENSE_SENSORS):
|
||||
for index, description in enumerate(SENSE_SENSORS_WRITE):
|
||||
if not description.entity_registry_enabled_default:
|
||||
continue
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
|
@ -411,7 +414,7 @@ async def test_sensor_setup_camera(
|
|||
):
|
||||
"""Test sensor entity setup for camera devices."""
|
||||
# 3 from all, 7 from camera, 12 NVR
|
||||
assert_entity_counts(hass, Platform.SENSOR, 24, 13)
|
||||
assert_entity_counts(hass, Platform.SENSOR, 25, 13)
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
|
@ -421,7 +424,7 @@ async def test_sensor_setup_camera(
|
|||
"100.0",
|
||||
"20.0",
|
||||
)
|
||||
for index, description in enumerate(CAMERA_SENSORS):
|
||||
for index, description in enumerate(CAMERA_SENSORS_WRITE):
|
||||
if not description.entity_registry_enabled_default:
|
||||
continue
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
|
@ -536,7 +539,7 @@ async def test_sensor_update_motion(
|
|||
):
|
||||
"""Test sensor motion entity."""
|
||||
# 3 from all, 7 from camera, 12 NVR
|
||||
assert_entity_counts(hass, Platform.SENSOR, 24, 13)
|
||||
assert_entity_counts(hass, Platform.SENSOR, 25, 13)
|
||||
|
||||
_, entity_id = ids_from_device_description(
|
||||
Platform.SENSOR, camera, MOTION_SENSORS[0]
|
||||
|
@ -584,7 +587,7 @@ async def test_sensor_update_alarm(
|
|||
assert_entity_counts(hass, Platform.SENSOR, 22, 14)
|
||||
|
||||
_, entity_id = ids_from_device_description(
|
||||
Platform.SENSOR, sensor, SENSE_SENSORS[4]
|
||||
Platform.SENSOR, sensor, SENSE_SENSORS_WRITE[4]
|
||||
)
|
||||
|
||||
event_metadata = EventMetadata(sensor_id=sensor.id, alarm_type="smoke")
|
||||
|
@ -632,7 +635,7 @@ async def test_sensor_update_alarm_with_last_trip_time(
|
|||
|
||||
# Last Trip Time
|
||||
unique_id, entity_id = ids_from_device_description(
|
||||
Platform.SENSOR, sensor, SENSE_SENSORS[-3]
|
||||
Platform.SENSOR, sensor, SENSE_SENSORS_WRITE[-3]
|
||||
)
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue