2022-01-02 19:47:25 +00:00
|
|
|
"""Test the UniFi Protect switch platform."""
|
2022-01-01 21:23:10 +00:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from unittest.mock import AsyncMock, Mock
|
|
|
|
|
|
|
|
import pytest
|
2022-06-25 15:15:38 +00:00
|
|
|
from pyunifiprotect.data import Camera, Light, Permission, RecordingMode, VideoMode
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
from homeassistant.components.unifiprotect.const import DEFAULT_ATTRIBUTION
|
|
|
|
from homeassistant.components.unifiprotect.switch import (
|
|
|
|
CAMERA_SWITCHES,
|
|
|
|
LIGHT_SWITCHES,
|
|
|
|
ProtectSwitchEntityDescription,
|
|
|
|
)
|
|
|
|
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_ENTITY_ID, STATE_OFF, Platform
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
from .utils import (
|
|
|
|
MockUFPFixture,
|
2022-01-01 21:23:10 +00:00
|
|
|
assert_entity_counts,
|
|
|
|
enable_entity,
|
|
|
|
ids_from_device_description,
|
2022-06-25 15:15:38 +00:00
|
|
|
init_entry,
|
2022-01-01 21:23:10 +00:00
|
|
|
)
|
|
|
|
|
2022-05-13 22:42:33 +00:00
|
|
|
CAMERA_SWITCHES_BASIC = [
|
|
|
|
d
|
|
|
|
for d in CAMERA_SWITCHES
|
2022-05-14 16:07:17 +00:00
|
|
|
if d.name != "Detections: Face"
|
|
|
|
and d.name != "Detections: Package"
|
|
|
|
and d.name != "SSH Enabled"
|
2022-05-13 22:42:33 +00:00
|
|
|
]
|
2022-04-09 21:34:48 +00:00
|
|
|
CAMERA_SWITCHES_NO_EXTRA = [
|
2022-05-13 22:42:33 +00:00
|
|
|
d for d in CAMERA_SWITCHES_BASIC if d.name not in ("High FPS", "Privacy Mode")
|
2022-04-09 21:34:48 +00:00
|
|
|
]
|
|
|
|
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-21 16:17:29 +00:00
|
|
|
async def test_switch_setup_no_perm(
|
|
|
|
hass: HomeAssistant,
|
2022-06-25 15:15:38 +00:00
|
|
|
ufp: MockUFPFixture,
|
|
|
|
light: Light,
|
|
|
|
doorbell: Camera,
|
2022-06-21 16:17:29 +00:00
|
|
|
):
|
|
|
|
"""Test switch entity setup for light devices."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
ufp.api.bootstrap.auth_user.all_permissions = [
|
2022-06-21 16:17:29 +00:00
|
|
|
Permission.unifi_dict_to_dict({"rawPermission": "light:read:*"})
|
|
|
|
]
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [light, doorbell])
|
2022-06-21 16:17:29 +00:00
|
|
|
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 0, 0)
|
|
|
|
|
|
|
|
|
2022-01-01 21:23:10 +00:00
|
|
|
async def test_switch_setup_light(
|
|
|
|
hass: HomeAssistant,
|
2022-06-25 15:15:38 +00:00
|
|
|
ufp: MockUFPFixture,
|
2022-01-01 21:23:10 +00:00
|
|
|
light: Light,
|
|
|
|
):
|
|
|
|
"""Test switch entity setup for light devices."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [light])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 2, 1)
|
|
|
|
|
2022-01-01 21:23:10 +00:00
|
|
|
entity_registry = er.async_get(hass)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = LIGHT_SWITCHES[1]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
unique_id, entity_id = ids_from_device_description(
|
|
|
|
Platform.SWITCH, light, description
|
|
|
|
)
|
|
|
|
|
|
|
|
entity = entity_registry.async_get(entity_id)
|
|
|
|
assert entity
|
|
|
|
assert entity.unique_id == unique_id
|
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state
|
|
|
|
assert state.state == STATE_OFF
|
|
|
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = LIGHT_SWITCHES[0]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-19 14:22:33 +00:00
|
|
|
unique_id = f"{light.mac}_{description.key}"
|
2022-01-01 21:23:10 +00:00
|
|
|
entity_id = f"switch.test_light_{description.name.lower().replace(' ', '_')}"
|
|
|
|
|
|
|
|
entity = entity_registry.async_get(entity_id)
|
|
|
|
assert entity
|
|
|
|
assert entity.disabled is True
|
|
|
|
assert entity.unique_id == unique_id
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await enable_entity(hass, ufp.entry.entry_id, entity_id)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state
|
|
|
|
assert state.state == STATE_OFF
|
|
|
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
|
|
|
|
|
|
|
|
|
|
|
async def test_switch_setup_camera_all(
|
|
|
|
hass: HomeAssistant,
|
2022-06-25 15:15:38 +00:00
|
|
|
ufp: MockUFPFixture,
|
|
|
|
doorbell: Camera,
|
2022-01-01 21:23:10 +00:00
|
|
|
):
|
|
|
|
"""Test switch entity setup for camera devices (all enabled feature flags)."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [doorbell])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
|
|
|
|
2022-01-01 21:23:10 +00:00
|
|
|
entity_registry = er.async_get(hass)
|
|
|
|
|
2022-05-13 22:42:33 +00:00
|
|
|
for description in CAMERA_SWITCHES_BASIC:
|
2022-01-01 21:23:10 +00:00
|
|
|
unique_id, entity_id = ids_from_device_description(
|
2022-06-25 15:15:38 +00:00
|
|
|
Platform.SWITCH, doorbell, description
|
2022-01-01 21:23:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
entity = entity_registry.async_get(entity_id)
|
|
|
|
assert entity
|
|
|
|
assert entity.unique_id == unique_id
|
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state
|
|
|
|
assert state.state == STATE_OFF
|
|
|
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = CAMERA_SWITCHES[0]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
description_entity_name = (
|
|
|
|
description.name.lower().replace(":", "").replace(" ", "_")
|
|
|
|
)
|
2022-06-25 15:15:38 +00:00
|
|
|
unique_id = f"{doorbell.mac}_{description.key}"
|
2022-01-01 21:23:10 +00:00
|
|
|
entity_id = f"switch.test_camera_{description_entity_name}"
|
|
|
|
|
|
|
|
entity = entity_registry.async_get(entity_id)
|
|
|
|
assert entity
|
|
|
|
assert entity.disabled is True
|
|
|
|
assert entity.unique_id == unique_id
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await enable_entity(hass, ufp.entry.entry_id, entity_id)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state
|
|
|
|
assert state.state == STATE_OFF
|
|
|
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
|
|
|
|
|
|
|
|
|
|
|
async def test_switch_setup_camera_none(
|
|
|
|
hass: HomeAssistant,
|
2022-06-25 15:15:38 +00:00
|
|
|
ufp: MockUFPFixture,
|
|
|
|
camera: Camera,
|
2022-01-01 21:23:10 +00:00
|
|
|
):
|
|
|
|
"""Test switch entity setup for camera devices (no enabled feature flags)."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [camera])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 6, 5)
|
|
|
|
|
2022-01-01 21:23:10 +00:00
|
|
|
entity_registry = er.async_get(hass)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
for description in CAMERA_SWITCHES_BASIC:
|
2022-01-01 21:23:10 +00:00
|
|
|
if description.ufp_required_field is not None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
unique_id, entity_id = ids_from_device_description(
|
2022-06-25 15:15:38 +00:00
|
|
|
Platform.SWITCH, camera, description
|
2022-01-01 21:23:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
entity = entity_registry.async_get(entity_id)
|
|
|
|
assert entity
|
|
|
|
assert entity.unique_id == unique_id
|
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state
|
|
|
|
assert state.state == STATE_OFF
|
|
|
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = CAMERA_SWITCHES[0]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
description_entity_name = (
|
|
|
|
description.name.lower().replace(":", "").replace(" ", "_")
|
|
|
|
)
|
2022-06-25 15:15:38 +00:00
|
|
|
unique_id = f"{camera.mac}_{description.key}"
|
2022-01-01 21:23:10 +00:00
|
|
|
entity_id = f"switch.test_camera_{description_entity_name}"
|
|
|
|
|
|
|
|
entity = entity_registry.async_get(entity_id)
|
|
|
|
assert entity
|
|
|
|
assert entity.disabled is True
|
|
|
|
assert entity.unique_id == unique_id
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await enable_entity(hass, ufp.entry.entry_id, entity_id)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
state = hass.states.get(entity_id)
|
|
|
|
assert state
|
|
|
|
assert state.state == STATE_OFF
|
|
|
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
|
|
|
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
async def test_switch_light_status(
|
|
|
|
hass: HomeAssistant, ufp: MockUFPFixture, light: Light
|
|
|
|
):
|
2022-01-01 21:23:10 +00:00
|
|
|
"""Tests status light switch for lights."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [light])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 2, 1)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = LIGHT_SWITCHES[1]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
light.__fields__["set_status_light"] = Mock()
|
|
|
|
light.set_status_light = AsyncMock()
|
|
|
|
|
|
|
|
_, entity_id = ids_from_device_description(Platform.SWITCH, light, description)
|
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
|
|
|
light.set_status_light.assert_called_once_with(True)
|
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
|
|
|
light.set_status_light.assert_called_with(False)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_switch_camera_ssh(
|
2022-06-25 15:15:38 +00:00
|
|
|
hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera
|
2022-01-01 21:23:10 +00:00
|
|
|
):
|
|
|
|
"""Tests SSH switch for cameras."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [doorbell])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = CAMERA_SWITCHES[0]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.__fields__["set_ssh"] = Mock()
|
|
|
|
doorbell.set_ssh = AsyncMock()
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
_, entity_id = ids_from_device_description(Platform.SWITCH, doorbell, description)
|
|
|
|
await enable_entity(hass, ufp.entry.entry_id, entity_id)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_ssh.assert_called_once_with(True)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_ssh.assert_called_with(False)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
|
2022-04-09 21:34:48 +00:00
|
|
|
@pytest.mark.parametrize("description", CAMERA_SWITCHES_NO_EXTRA)
|
2022-01-01 21:23:10 +00:00
|
|
|
async def test_switch_camera_simple(
|
2022-06-25 15:15:38 +00:00
|
|
|
hass: HomeAssistant,
|
|
|
|
ufp: MockUFPFixture,
|
|
|
|
doorbell: Camera,
|
|
|
|
description: ProtectSwitchEntityDescription,
|
2022-01-01 21:23:10 +00:00
|
|
|
):
|
|
|
|
"""Tests all simple switches for cameras."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [doorbell])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
|
|
|
|
2022-01-10 04:37:24 +00:00
|
|
|
assert description.ufp_set_method is not None
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.__fields__[description.ufp_set_method] = Mock()
|
|
|
|
setattr(doorbell, description.ufp_set_method, AsyncMock())
|
|
|
|
set_method = getattr(doorbell, description.ufp_set_method)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
_, entity_id = ids_from_device_description(Platform.SWITCH, doorbell, description)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
|
|
|
set_method.assert_called_once_with(True)
|
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
|
|
|
set_method.assert_called_with(False)
|
|
|
|
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
async def test_switch_camera_highfps(
|
|
|
|
hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera
|
|
|
|
):
|
2022-01-01 21:23:10 +00:00
|
|
|
"""Tests High FPS switch for cameras."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [doorbell])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = CAMERA_SWITCHES[3]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.__fields__["set_video_mode"] = Mock()
|
|
|
|
doorbell.set_video_mode = AsyncMock()
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
_, entity_id = ids_from_device_description(Platform.SWITCH, doorbell, description)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_video_mode.assert_called_once_with(VideoMode.HIGH_FPS)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_video_mode.assert_called_with(VideoMode.DEFAULT)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
async def test_switch_camera_privacy(
|
|
|
|
hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera
|
|
|
|
):
|
2022-01-01 21:23:10 +00:00
|
|
|
"""Tests Privacy Mode switch for cameras."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
await init_entry(hass, ufp, [doorbell])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = CAMERA_SWITCHES[4]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.__fields__["set_privacy"] = Mock()
|
|
|
|
doorbell.set_privacy = AsyncMock()
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
_, entity_id = ids_from_device_description(Platform.SWITCH, doorbell, description)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_privacy.assert_called_once_with(True, 0, RecordingMode.NEVER)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_privacy.assert_called_with(
|
|
|
|
False, doorbell.mic_volume, doorbell.recording_settings.mode
|
2022-01-01 21:23:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_switch_camera_privacy_already_on(
|
2022-06-25 15:15:38 +00:00
|
|
|
hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera
|
2022-01-01 21:23:10 +00:00
|
|
|
):
|
|
|
|
"""Tests Privacy Mode switch for cameras with privacy mode defaulted on."""
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.add_privacy_zone()
|
|
|
|
await init_entry(hass, ufp, [doorbell])
|
|
|
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
|
|
|
|
2022-05-14 16:07:17 +00:00
|
|
|
description = CAMERA_SWITCHES[4]
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.__fields__["set_privacy"] = Mock()
|
|
|
|
doorbell.set_privacy = AsyncMock()
|
2022-01-01 21:23:10 +00:00
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
_, entity_id = ids_from_device_description(Platform.SWITCH, doorbell, description)
|
2022-01-01 21:23:10 +00:00
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
"switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
|
|
|
)
|
|
|
|
|
2022-06-25 15:15:38 +00:00
|
|
|
doorbell.set_privacy.assert_called_once_with(False, 100, RecordingMode.ALWAYS)
|