mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add UniFi Protect chime button/camera switch (#73195)
This commit is contained in:
parent
4435c641de
commit
4c45cb5c52
@ -43,6 +43,15 @@ ALL_DEVICE_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SENSOR_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
|
||||||
|
ProtectButtonEntityDescription(
|
||||||
|
key="clear_tamper",
|
||||||
|
name="Clear Tamper",
|
||||||
|
icon="mdi:notification-clear-all",
|
||||||
|
ufp_press="clear_tamper",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
CHIME_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
|
CHIME_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = (
|
||||||
ProtectButtonEntityDescription(
|
ProtectButtonEntityDescription(
|
||||||
key="play",
|
key="play",
|
||||||
@ -69,7 +78,11 @@ async def async_setup_entry(
|
|||||||
data: ProtectData = hass.data[DOMAIN][entry.entry_id]
|
data: ProtectData = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
|
||||||
entities: list[ProtectDeviceEntity] = async_all_device_entities(
|
entities: list[ProtectDeviceEntity] = async_all_device_entities(
|
||||||
data, ProtectButton, all_descs=ALL_DEVICE_BUTTONS, chime_descs=CHIME_BUTTONS
|
data,
|
||||||
|
ProtectButton,
|
||||||
|
all_descs=ALL_DEVICE_BUTTONS,
|
||||||
|
chime_descs=CHIME_BUTTONS,
|
||||||
|
sense_descs=SENSOR_BUTTONS,
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
@ -140,9 +140,9 @@ class ProtectCamera(ProtectDeviceEntity, Camera):
|
|||||||
def _async_update_device_from_protect(self) -> None:
|
def _async_update_device_from_protect(self) -> None:
|
||||||
super()._async_update_device_from_protect()
|
super()._async_update_device_from_protect()
|
||||||
self.channel = self.device.channels[self.channel.id]
|
self.channel = self.device.channels[self.channel.id]
|
||||||
|
motion_enabled = self.device.recording_settings.enable_motion_detection
|
||||||
self._attr_motion_detection_enabled = (
|
self._attr_motion_detection_enabled = (
|
||||||
self.device.state == StateType.CONNECTED
|
motion_enabled if motion_enabled is not None else True
|
||||||
and self.device.feature_flags.has_motion_zones
|
|
||||||
)
|
)
|
||||||
self._attr_is_recording = (
|
self._attr_is_recording = (
|
||||||
self.device.state == StateType.CONNECTED and self.device.is_recording
|
self.device.state == StateType.CONNECTED and self.device.is_recording
|
||||||
@ -171,3 +171,11 @@ class ProtectCamera(ProtectDeviceEntity, Camera):
|
|||||||
async def stream_source(self) -> str | None:
|
async def stream_source(self) -> str | None:
|
||||||
"""Return the Stream Source."""
|
"""Return the Stream Source."""
|
||||||
return self._stream_source
|
return self._stream_source
|
||||||
|
|
||||||
|
async def async_enable_motion_detection(self) -> None:
|
||||||
|
"""Call the job and enable motion detection."""
|
||||||
|
await self.device.set_motion_detection(True)
|
||||||
|
|
||||||
|
async def async_disable_motion_detection(self) -> None:
|
||||||
|
"""Call the job and disable motion detection."""
|
||||||
|
await self.device.set_motion_detection(False)
|
||||||
|
@ -133,6 +133,14 @@ CAMERA_SWITCHES: tuple[ProtectSwitchEntityDescription, ...] = (
|
|||||||
ufp_value="osd_settings.is_debug_enabled",
|
ufp_value="osd_settings.is_debug_enabled",
|
||||||
ufp_set_method="set_osd_bitrate",
|
ufp_set_method="set_osd_bitrate",
|
||||||
),
|
),
|
||||||
|
ProtectSwitchEntityDescription(
|
||||||
|
key="motion",
|
||||||
|
name="Detections: Motion",
|
||||||
|
icon="mdi:run-fast",
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
ufp_value="recording_settings.enable_motion_detection",
|
||||||
|
ufp_set_method="set_motion_detection",
|
||||||
|
),
|
||||||
ProtectSwitchEntityDescription(
|
ProtectSwitchEntityDescription(
|
||||||
key="smart_person",
|
key="smart_person",
|
||||||
name="Detections: Person",
|
name="Detections: Person",
|
||||||
|
@ -48,6 +48,9 @@ async def camera_fixture(
|
|||||||
):
|
):
|
||||||
"""Fixture for a single camera for testing the camera platform."""
|
"""Fixture for a single camera for testing the camera platform."""
|
||||||
|
|
||||||
|
# disable pydantic validation so mocking can happen
|
||||||
|
ProtectCamera.__config__.validate_assignment = False
|
||||||
|
|
||||||
camera_obj = mock_camera.copy(deep=True)
|
camera_obj = mock_camera.copy(deep=True)
|
||||||
camera_obj._api = mock_entry.api
|
camera_obj._api = mock_entry.api
|
||||||
camera_obj.channels[0]._api = mock_entry.api
|
camera_obj.channels[0]._api = mock_entry.api
|
||||||
@ -68,7 +71,9 @@ async def camera_fixture(
|
|||||||
|
|
||||||
assert_entity_counts(hass, Platform.CAMERA, 2, 1)
|
assert_entity_counts(hass, Platform.CAMERA, 2, 1)
|
||||||
|
|
||||||
return (camera_obj, "camera.test_camera_high")
|
yield (camera_obj, "camera.test_camera_high")
|
||||||
|
|
||||||
|
ProtectCamera.__config__.validate_assignment = True
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="camera_package")
|
@pytest.fixture(name="camera_package")
|
||||||
@ -572,3 +577,43 @@ async def test_camera_ws_update_offline(
|
|||||||
|
|
||||||
state = hass.states.get(camera[1])
|
state = hass.states.get(camera[1])
|
||||||
assert state and state.state == "idle"
|
assert state and state.state == "idle"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_camera_enable_motion(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_entry: MockEntityFixture,
|
||||||
|
camera: tuple[ProtectCamera, str],
|
||||||
|
):
|
||||||
|
"""Tests generic entity update service."""
|
||||||
|
|
||||||
|
camera[0].__fields__["set_motion_detection"] = Mock()
|
||||||
|
camera[0].set_motion_detection = AsyncMock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"camera",
|
||||||
|
"enable_motion_detection",
|
||||||
|
{ATTR_ENTITY_ID: camera[1]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
camera[0].set_motion_detection.assert_called_once_with(True)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_camera_disable_motion(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_entry: MockEntityFixture,
|
||||||
|
camera: tuple[ProtectCamera, str],
|
||||||
|
):
|
||||||
|
"""Tests generic entity update service."""
|
||||||
|
|
||||||
|
camera[0].__fields__["set_motion_detection"] = Mock()
|
||||||
|
camera[0].set_motion_detection = AsyncMock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"camera",
|
||||||
|
"disable_motion_detection",
|
||||||
|
{ATTR_ENTITY_ID: camera[1]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
camera[0].set_motion_detection.assert_called_once_with(False)
|
||||||
|
@ -118,7 +118,7 @@ async def camera_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.SWITCH, 12, 11)
|
assert_entity_counts(hass, Platform.SWITCH, 13, 12)
|
||||||
|
|
||||||
yield camera_obj
|
yield camera_obj
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ async def camera_none_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.SWITCH, 5, 4)
|
assert_entity_counts(hass, Platform.SWITCH, 6, 5)
|
||||||
|
|
||||||
yield camera_obj
|
yield camera_obj
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ async def camera_privacy_fixture(
|
|||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert_entity_counts(hass, Platform.SWITCH, 6, 5)
|
assert_entity_counts(hass, Platform.SWITCH, 7, 6)
|
||||||
|
|
||||||
yield camera_obj
|
yield camera_obj
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user