async def test_resolve_media_thumbnail(hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, fixed_now: datetime): """Test resolving event thumbnails.""" ufp.api.get_bootstrap = AsyncMock(return_value=ufp.api.bootstrap) await init_entry(hass, ufp, [doorbell], regenerate_ids=False) event = Event( id="test_event_id", type=EventType.MOTION, start=fixed_now - timedelta(seconds=20), end=fixed_now, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=doorbell.id, ) event._api = ufp.api ufp.api.bootstrap.events = {"test_event_id": event} source = await async_get_media_source(hass) media_item = MediaSourceItem(hass, DOMAIN, "test_id:eventthumb:test_event_id", None) play_media = await source.async_resolve_media(media_item) assert play_media.mime_type == "image/jpeg" assert play_media.url.startswith( "/api/unifiprotect/thumbnail/test_id/test_event_id")
async def test_resolve_media_event(hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, fixed_now: datetime): """Test resolving event clips.""" ufp.api.get_bootstrap = AsyncMock(return_value=ufp.api.bootstrap) await init_entry(hass, ufp, [doorbell], regenerate_ids=False) event = Event( id="test_event_id", type=EventType.MOTION, start=fixed_now - timedelta(seconds=20), end=fixed_now, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=doorbell.id, ) event._api = ufp.api ufp.api.get_event = AsyncMock(return_value=event) source = await async_get_media_source(hass) media_item = MediaSourceItem(hass, DOMAIN, "test_id:event:test_event_id", None) play_media = await source.async_resolve_media(media_item) start = event.start.replace(microsecond=0).isoformat() end = event.end.replace(microsecond=0).isoformat() assert play_media.mime_type == "video/mp4" assert play_media.url.startswith( f"/api/unifiprotect/video/test_id/{event.camera_id}/{start}/{end}")
async def test_browse_media_eventthumb(hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, fixed_now: datetime): """Test browsing specific event.""" ufp.api.get_bootstrap = AsyncMock(return_value=ufp.api.bootstrap) await init_entry(hass, ufp, [doorbell], regenerate_ids=False) event = Event( id="test_event_id", type=EventType.SMART_DETECT, start=fixed_now - timedelta(seconds=20), end=fixed_now, score=100, smart_detect_types=[SmartDetectObjectType.PERSON], smart_detect_event_ids=[], camera_id=doorbell.id, ) event._api = ufp.api ufp.api.get_event = AsyncMock(return_value=event) source = await async_get_media_source(hass) media_item = MediaSourceItem(hass, DOMAIN, "test_id:eventthumb:test_event_id", None) browse = await source.async_browse_media(media_item) assert browse.identifier == "test_id:eventthumb:test_event_id" assert browse.children is None assert browse.media_class == MEDIA_CLASS_IMAGE
async def test_browse_media_recent(hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, fixed_now: datetime): """Test browsing event selector level media for recent days.""" ufp.api.get_bootstrap = AsyncMock(return_value=ufp.api.bootstrap) await init_entry(hass, ufp, [doorbell], regenerate_ids=False) event = Event( id="test_event_id", type=EventType.MOTION, start=fixed_now - timedelta(seconds=20), end=fixed_now, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=doorbell.id, ) event._api = ufp.api ufp.api.get_events_raw = AsyncMock(return_value=[event.unifi_dict()]) base_id = f"test_id:browse:{doorbell.id}:motion:recent:1" source = await async_get_media_source(hass) media_item = MediaSourceItem(hass, DOMAIN, base_id, None) browse = await source.async_browse_media(media_item) assert ( browse.title == f"UnifiProtect > {doorbell.name} > Motion Events > Last 24 Hours (1)") assert browse.identifier == base_id assert len(browse.children) == 1 assert browse.children[0].identifier == "test_id:event:test_event_id"
async def test_browse_media_event_ongoing(hass: HomeAssistant, ufp: MockUFPFixture, fixed_now: datetime, doorbell: Camera): """Test browsing event that is still ongoing.""" ufp.api.get_bootstrap = AsyncMock(return_value=ufp.api.bootstrap) await init_entry(hass, ufp, [doorbell], regenerate_ids=False) event = Event( id="test_event_id", type=EventType.MOTION, start=fixed_now - timedelta(seconds=20), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=doorbell.id, ) event._api = ufp.api ufp.api.get_event = AsyncMock(return_value=event) source = await async_get_media_source(hass) media_item = MediaSourceItem(hass, DOMAIN, f"test_id:event:{event.id}", None) with pytest.raises(BrowseError): await source.async_browse_media(media_item)
async def adopt_devices( hass: HomeAssistant, ufp: MockUFPFixture, ufp_devices: list[ProtectAdoptableDeviceModel], fully_adopt: bool = False, ): """Emit WS to re-adopt give Protect devices.""" for ufp_device in ufp_devices: if fully_adopt: ufp_device.is_adopted = True ufp_device.is_adopted_by_other = False ufp_device.can_adopt = False devices = getattr(ufp.api.bootstrap, f"{ufp_device.model.value}s") devices[ufp_device.id] = ufp_device mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = Event( api=ufp_device.api, id=random_hex(24), smart_detect_types=[], smart_detect_event_ids=[], type=EventType.DEVICE_ADOPTED, start=dt_util.utcnow(), score=100, metadata={"device_id": ufp_device.id}, model=ModelType.EVENT, ) ufp.ws_msg(mock_msg) await hass.async_block_till_done()
async def test_browse_media_browse_whole_month(hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, fixed_now: datetime): """Test events for a specific day.""" fixed_now = fixed_now.replace(month=11) last_month = fixed_now.replace(day=1) - timedelta(days=1) ufp.api.bootstrap._recording_start = last_month ufp.api.get_bootstrap = AsyncMock(return_value=ufp.api.bootstrap) await init_entry(hass, ufp, [doorbell], regenerate_ids=False) event = Event( id="test_event_id", type=EventType.MOTION, start=fixed_now - timedelta(seconds=20), end=fixed_now, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=doorbell.id, ) event._api = ufp.api ufp.api.get_events_raw = AsyncMock(return_value=[event.unifi_dict()]) base_id = ( f"test_id:browse:{doorbell.id}:all:range:{fixed_now.year}:{fixed_now.month}:all" ) source = await async_get_media_source(hass) media_item = MediaSourceItem(hass, DOMAIN, base_id, None) browse = await source.async_browse_media(media_item) assert ( browse.title == f"UnifiProtect > {doorbell.name} > All Events > {fixed_now.strftime('%B %Y')} > Whole Month (1)" ) assert browse.identifier == base_id assert len(browse.children) == 1 assert browse.children[0].identifier == "test_id:event:test_event_id"
async def test_binary_sensor_update_motion( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, fixed_now: datetime, ): """Test binary_sensor motion entity.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.BINARY_SENSOR, 9, 9) _, entity_id = ids_from_device_description( Platform.BINARY_SENSOR, doorbell, MOTION_SENSORS[0] ) event = Event( id="test_event_id", type=EventType.MOTION, start=fixed_now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=doorbell.id, ) new_camera = doorbell.copy() new_camera.is_motion_detected = True new_camera.last_motion_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.api.bootstrap.events = {event.id: event} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == STATE_ON assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION assert state.attributes[ATTR_EVENT_SCORE] == 100
async def test_sensor_update_alarm( hass: HomeAssistant, mock_entry: MockEntityFixture, sensor: Sensor, now: datetime ): """Test sensor motion entity.""" # 5 from all, 5 from sense, 12 NVR assert_entity_counts(hass, Platform.SENSOR, 22, 14) _, entity_id = ids_from_device_description( Platform.SENSOR, sensor, SENSE_SENSORS[4] ) event_metadata = EventMetadata(sensor_id=sensor.id, alarm_type="smoke") event = Event( id="test_event_id", type=EventType.SENSOR_ALARM, start=now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], metadata=event_metadata, api=mock_entry.api, ) new_bootstrap = copy(mock_entry.api.bootstrap) new_sensor = sensor.copy() new_sensor.set_alarm_timeout() new_sensor.last_alarm_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = event new_bootstrap.sensors = {new_sensor.id: new_sensor} new_bootstrap.events = {event.id: event} mock_entry.api.bootstrap = new_bootstrap mock_entry.api.ws_subscription(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == "smoke" await time_changed(hass, 10)
async def test_sensor_update_motion( hass: HomeAssistant, mock_entry: MockEntityFixture, camera: Camera, now: datetime ): """Test sensor motion entity.""" # 3 from all, 7 from camera, 12 NVR assert_entity_counts(hass, Platform.SENSOR, 24, 13) _, entity_id = ids_from_device_description( Platform.SENSOR, camera, MOTION_SENSORS[0] ) event = Event( id="test_event_id", type=EventType.SMART_DETECT, start=now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[SmartDetectObjectType.PERSON], smart_detect_event_ids=[], camera_id=camera.id, api=mock_entry.api, ) new_bootstrap = copy(mock_entry.api.bootstrap) new_camera = camera.copy() new_camera.is_smart_detected = True new_camera.last_smart_detect_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = event new_bootstrap.cameras = {new_camera.id: new_camera} new_bootstrap.events = {event.id: event} mock_entry.api.bootstrap = new_bootstrap mock_entry.api.ws_subscription(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == SmartDetectObjectType.PERSON.value assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION assert state.attributes[ATTR_EVENT_SCORE] == 100
async def test_binary_sensor_update_light_motion( hass: HomeAssistant, ufp: MockUFPFixture, light: Light, fixed_now: datetime ): """Test binary_sensor motion entity.""" await init_entry(hass, ufp, [light]) assert_entity_counts(hass, Platform.BINARY_SENSOR, 8, 8) _, entity_id = ids_from_device_description( Platform.BINARY_SENSOR, light, LIGHT_SENSOR_WRITE[1] ) event_metadata = EventMetadata(light_id=light.id) event = Event( id="test_event_id", type=EventType.MOTION_LIGHT, start=fixed_now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], metadata=event_metadata, api=ufp.api, ) new_light = light.copy() new_light.is_pir_motion_detected = True new_light.last_motion_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = event ufp.api.bootstrap.lights = {new_light.id: new_light} ufp.api.bootstrap.events = {event.id: event} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == STATE_ON
async def test_sensor_update_alarm(hass: HomeAssistant, ufp: MockUFPFixture, sensor_all: Sensor, fixed_now: datetime): """Test sensor motion entity.""" await init_entry(hass, ufp, [sensor_all]) assert_entity_counts(hass, Platform.SENSOR, 22, 14) _, entity_id = ids_from_device_description(Platform.SENSOR, sensor_all, SENSE_SENSORS_WRITE[4]) event_metadata = EventMetadata(sensor_id=sensor_all.id, alarm_type="smoke") event = Event( id="test_event_id", type=EventType.SENSOR_ALARM, start=fixed_now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], metadata=event_metadata, api=ufp.api, ) new_sensor = sensor_all.copy() new_sensor.set_alarm_timeout() new_sensor.last_alarm_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = event ufp.api.bootstrap.sensors = {new_sensor.id: new_sensor} ufp.api.bootstrap.events = {event.id: event} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == "smoke" await time_changed(hass, 10)
async def test_binary_sensor_update_light_motion(hass: HomeAssistant, mock_entry: MockEntityFixture, light: Light, now: datetime): """Test binary_sensor motion entity.""" _, entity_id = ids_from_device_description(Platform.BINARY_SENSOR, light, LIGHT_SENSORS[1]) event_metadata = EventMetadata(light_id=light.id) event = Event( id="test_event_id", type=EventType.MOTION_LIGHT, start=now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], metadata=event_metadata, api=mock_entry.api, ) new_bootstrap = copy(mock_entry.api.bootstrap) new_light = light.copy() new_light.is_pir_motion_detected = True new_light.last_motion_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = event new_bootstrap.lights = {new_light.id: new_light} new_bootstrap.events = {event.id: event} mock_entry.api.bootstrap = new_bootstrap mock_entry.api.ws_subscription(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == STATE_ON
async def test_binary_sensor_update_motion(hass: HomeAssistant, mock_entry: MockEntityFixture, camera: Camera, now: datetime): """Test binary_sensor motion entity.""" _, entity_id = ids_from_device_description(Platform.BINARY_SENSOR, camera, MOTION_SENSORS[0]) event = Event( id="test_event_id", type=EventType.MOTION, start=now - timedelta(seconds=1), end=None, score=100, smart_detect_types=[], smart_detect_event_ids=[], camera_id=camera.id, ) new_bootstrap = copy(mock_entry.api.bootstrap) new_camera = camera.copy() new_camera.is_motion_detected = True new_camera.last_motion_event_id = event.id mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera new_bootstrap.cameras = {new_camera.id: new_camera} new_bootstrap.events = {event.id: event} mock_entry.api.bootstrap = new_bootstrap mock_entry.api.ws_subscription(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == STATE_ON assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION assert state.attributes[ATTR_EVENT_SCORE] == 100