async def test_camera_ws_update(hass: HomeAssistant, ufp: MockUFPFixture, camera: ProtectCamera): """WS update updates camera entity.""" await init_entry(hass, ufp, [camera]) assert_entity_counts(hass, Platform.CAMERA, 2, 1) entity_id = "camera.test_camera_high" state = hass.states.get(entity_id) assert state and state.state == "idle" new_camera = camera.copy() new_camera.is_recording = True no_camera = camera.copy() no_camera.is_adopted = False ufp.api.bootstrap.cameras = {new_camera.id: new_camera} mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.ws_msg(mock_msg) mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = no_camera ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state and state.state == "recording"
async def test_number_setup_camera_none(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Test number entity setup for camera devices (no features).""" camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags.can_optical_zoom = False camera_obj.feature_flags.has_mic = False # has_wdr is an the inverse of has HDR camera_obj.feature_flags.has_hdr = True mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.NUMBER, 0, 0)
async def test_number_setup_camera_missing_attr(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Test number entity setup for camera devices (no features, bad attrs).""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags = None Camera.__config__.validate_assignment = True mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.NUMBER, 0, 0)
async def test_adopt(hass: HomeAssistant, ufp: MockUFPFixture, camera: ProtectCamera): """Test setting up camera with no camera channels.""" camera1 = camera.copy() camera1.channels = [] await init_entry(hass, ufp, [camera1]) assert_entity_counts(hass, Platform.CAMERA, 0, 0) await remove_entities(hass, ufp, [camera1]) assert_entity_counts(hass, Platform.CAMERA, 0, 0) camera1.channels = [] await adopt_devices(hass, ufp, [camera1]) assert_entity_counts(hass, Platform.CAMERA, 0, 0) camera1.channels = camera.channels for channel in camera1.channels: channel._api = ufp.api mock_msg = Mock() mock_msg.changed_data = {"channels": camera.channels} mock_msg.new_obj = camera1 ufp.ws_msg(mock_msg) await hass.async_block_till_done() assert_entity_counts(hass, Platform.CAMERA, 2, 1) await remove_entities(hass, ufp, [camera1]) assert_entity_counts(hass, Platform.CAMERA, 0, 0) await adopt_devices(hass, ufp, [camera1]) assert_entity_counts(hass, Platform.CAMERA, 2, 1)
async def test_select_update_doorbell_message( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera ): """Test select entity update (change doorbell message).""" await init_entry(hass, ufp, [doorbell]) assert_entity_counts(hass, Platform.SELECT, 4, 4) _, entity_id = ids_from_device_description( Platform.SELECT, doorbell, CAMERA_SELECTS[2] ) state = hass.states.get(entity_id) assert state assert state.state == "Default Message (Welcome)" new_camera = doorbell.copy() new_camera.lcd_message = LCDMessage( type=DoorbellMessageType.CUSTOM_MESSAGE, text="Test" ) mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == "Test"
async def camera_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Fixture for a single camera for testing the media_player platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags.has_speaker = True mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) yield (camera_obj, "media_player.test_camera_speaker") Camera.__config__.validate_assignment = True
async def camera_fixture( hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera, now: datetime, ): """Fixture for a single camera for testing the binary_sensor platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags.has_chime = True camera_obj.last_ring = now - timedelta(hours=1) camera_obj.is_dark = False mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.nvr.system_info.storage.devices = [] mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.BINARY_SENSOR, 2, 2) yield camera_obj Camera.__config__.validate_assignment = True
async def camera_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Fixture for a single camera for testing the number platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags.can_optical_zoom = True camera_obj.feature_flags.has_mic = True # has_wdr is an the inverse of has HDR camera_obj.feature_flags.has_hdr = False camera_obj.isp_settings.wdr = 0 camera_obj.mic_volume = 0 camera_obj.isp_settings.zoom_position = 0 mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.NUMBER, 3, 3) yield camera_obj Camera.__config__.validate_assignment = True
async def camera_fixture( hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera ): """Fixture for a single camera for testing the select platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags.has_lcd_screen = True camera_obj.feature_flags.has_chime = True camera_obj.recording_settings.mode = RecordingMode.ALWAYS camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO camera_obj.lcd_message = None camera_obj.chime_duration = 0 mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.SELECT, 4, 4) yield camera_obj Camera.__config__.validate_assignment = True
async def test_media_player_update( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ): """Test media_player entity update.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) new_camera = doorbell.copy() new_camera.talkback_stream = Mock() new_camera.talkback_stream.is_running = True mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get("media_player.test_camera_speaker") assert state assert state.state == STATE_PLAYING
async def test_select_update_doorbell_message( hass: HomeAssistant, mock_entry: MockEntityFixture, camera: Camera, ): """Test select entity update (change doorbell message).""" _, entity_id = ids_from_device_description( Platform.SELECT, camera, CAMERA_SELECTS[2] ) state = hass.states.get(entity_id) assert state assert state.state == "Default Message (Welcome)" new_bootstrap = copy(mock_entry.api.bootstrap) new_camera = camera.copy() new_camera.lcd_message = LCDMessage( type=DoorbellMessageType.CUSTOM_MESSAGE, text="Test" ) mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera new_bootstrap.cameras = {new_camera.id: new_camera} 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 == "Test"
def doorbell_fixture(camera: Camera, fixed_now: datetime): """Mock UniFi Protect Camera device (with chime).""" doorbell = camera.copy() doorbell.channels = [c.copy() for c in doorbell.channels] package_channel = doorbell.channels[0].copy() package_channel.name = "Package Camera" package_channel.id = 3 package_channel.fps = 2 package_channel.rtsp_alias = "test_package_alias" doorbell.channels.append(package_channel) doorbell.feature_flags.video_modes = [ VideoMode.DEFAULT, VideoMode.HIGH_FPS ] doorbell.feature_flags.smart_detect_types = [ SmartDetectObjectType.PERSON, SmartDetectObjectType.VEHICLE, ] doorbell.has_speaker = True doorbell.feature_flags.has_hdr = True doorbell.feature_flags.has_lcd_screen = True doorbell.feature_flags.has_speaker = True doorbell.feature_flags.has_privacy_mask = True doorbell.feature_flags.has_chime = True doorbell.feature_flags.has_smart_detect = True doorbell.feature_flags.has_package_camera = True doorbell.feature_flags.has_led_status = True doorbell.last_ring = fixed_now - timedelta(hours=1) return doorbell
async def test_media_player_stop( hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera, unadopted_camera: Camera, ): """Test media_player entity test media_stop.""" await init_entry(hass, ufp, [doorbell, unadopted_camera]) assert_entity_counts(hass, Platform.MEDIA_PLAYER, 1, 1) new_camera = doorbell.copy() new_camera.talkback_stream = AsyncMock() new_camera.talkback_stream.is_running = True mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() await hass.services.async_call( "media_player", "media_stop", {ATTR_ENTITY_ID: "media_player.test_camera_speaker"}, blocking=True, ) new_camera.talkback_stream.stop.assert_called_once()
def unadopted_camera(camera: Camera): """Mock UniFi Protect Camera device (unadopted).""" no_camera = camera.copy() no_camera.channels = [c.copy() for c in no_camera.channels] no_camera.name = "Unadopted Camera" no_camera.is_adopted = False return no_camera
async def test_switch_camera_privacy(hass: HomeAssistant, ufp: MockUFPFixture, doorbell: Camera): """Tests Privacy Mode switch for cameras with privacy mode defaulted on.""" previous_mic = doorbell.mic_volume = 53 previous_record = doorbell.recording_settings.mode = RecordingMode.DETECTIONS await init_entry(hass, ufp, [doorbell]) assert_entity_counts(hass, Platform.SWITCH, 15, 14) description = PRIVACY_MODE_SWITCH doorbell.__fields__["set_privacy"] = Mock() doorbell.set_privacy = AsyncMock() _, entity_id = ids_from_device_description(Platform.SWITCH, doorbell, description) state = hass.states.get(entity_id) assert state and state.state == "off" assert ATTR_PREV_MIC not in state.attributes assert ATTR_PREV_RECORD not in state.attributes await hass.services.async_call("switch", "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True) doorbell.set_privacy.assert_called_with(True, 0, RecordingMode.NEVER) new_doorbell = doorbell.copy() new_doorbell.add_privacy_zone() new_doorbell.mic_volume = 0 new_doorbell.recording_settings.mode = RecordingMode.NEVER ufp.api.bootstrap.cameras = {new_doorbell.id: new_doorbell} mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_doorbell ufp.ws_msg(mock_msg) state = hass.states.get(entity_id) assert state and state.state == "on" assert state.attributes[ATTR_PREV_MIC] == previous_mic assert state.attributes[ATTR_PREV_RECORD] == previous_record.value doorbell.set_privacy.reset_mock() await hass.services.async_call("switch", "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True) doorbell.set_privacy.assert_called_with(False, previous_mic, previous_record)
async def test_set_chime_paired_doorbells( hass: HomeAssistant, ufp: MockUFPFixture, chime: Chime, doorbell: Camera, ): """Test set_chime_paired_doorbells.""" ufp.api.update_device = AsyncMock() camera1 = doorbell.copy() camera1.name = "Test Camera 1" camera2 = doorbell.copy() camera2.name = "Test Camera 2" await init_entry(hass, ufp, [camera1, camera2, chime]) registry = er.async_get(hass) chime_entry = registry.async_get("button.test_chime_play_chime") camera_entry = registry.async_get("binary_sensor.test_camera_2_doorbell") assert chime_entry is not None assert camera_entry is not None await hass.services.async_call( DOMAIN, SERVICE_SET_CHIME_PAIRED, { ATTR_DEVICE_ID: chime_entry.device_id, "doorbells": { ATTR_ENTITY_ID: ["binary_sensor.test_camera_1_doorbell"], ATTR_DEVICE_ID: [camera_entry.device_id], }, }, blocking=True, ) ufp.api.update_device.assert_called_once_with( ModelType.CHIME, chime.id, {"cameraIds": sorted([camera1.id, camera2.id])})
async def camera_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Fixture for a single camera for testing the switch platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.recording_settings.mode = RecordingMode.DETECTIONS camera_obj.feature_flags.has_led_status = True camera_obj.feature_flags.has_hdr = True camera_obj.feature_flags.video_modes = [ VideoMode.DEFAULT, VideoMode.HIGH_FPS ] camera_obj.feature_flags.has_privacy_mask = True camera_obj.feature_flags.has_speaker = True camera_obj.feature_flags.has_smart_detect = True camera_obj.feature_flags.smart_detect_types = [ SmartDetectObjectType.PERSON, SmartDetectObjectType.VEHICLE, ] camera_obj.is_ssh_enabled = False camera_obj.led_settings.is_enabled = False camera_obj.hdr_mode = False camera_obj.video_mode = VideoMode.DEFAULT camera_obj.remove_privacy_zone() camera_obj.speaker_settings.are_system_sounds_enabled = False camera_obj.osd_settings.is_name_enabled = False camera_obj.osd_settings.is_date_enabled = False camera_obj.osd_settings.is_logo_enabled = False camera_obj.osd_settings.is_debug_enabled = False camera_obj.smart_detect_settings.object_types = [] mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.SWITCH, 12, 11) yield camera_obj Camera.__config__.validate_assignment = True
async def test_binary_sensor_update_doorbell( hass: HomeAssistant, mock_entry: MockEntityFixture, camera: Camera, ): """Test select entity update (change doorbell message).""" _, entity_id = ids_from_device_description(Platform.BINARY_SENSOR, camera, CAMERA_SENSORS[0]) state = hass.states.get(entity_id) assert state assert state.state == STATE_OFF new_bootstrap = copy(mock_entry.api.bootstrap) new_camera = camera.copy() new_camera.last_ring = utcnow() mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera new_bootstrap.cameras = {new_camera.id: new_camera} 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 # fire event a second time for code coverage (cancel existing) 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 # since time is not really changing, switch the last ring back to allow turn off new_camera.last_ring = utcnow() - RING_INTERVAL await time_changed(hass, RING_INTERVAL.total_seconds()) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state assert state.state == STATE_OFF
async def test_missing_channels( hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: ProtectCamera ): """Test setting up camera with no camera channels.""" camera = mock_camera.copy(deep=True) camera.channels = [] mock_entry.api.bootstrap.cameras = {camera.id: camera} await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() entity_registry = er.async_get(hass) assert len(hass.states.async_all()) == 0 assert len(entity_registry.entities) == 0
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 camera_fixture( hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera, now: datetime, ): """Fixture for a single camera for testing the sensor platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.feature_flags.has_smart_detect = True camera_obj.is_smart_detected = False camera_obj.wired_connection_state = WiredConnectionState(phy_rate=1000) camera_obj.wifi_connection_state = WifiConnectionState(signal_quality=100, signal_strength=-50) camera_obj.stats.rx_bytes = 100.0 camera_obj.stats.tx_bytes = 100.0 camera_obj.stats.video.recording_start = now camera_obj.stats.storage.used = 100.0 camera_obj.stats.storage.used = 100.0 camera_obj.stats.storage.rate = 100.0 camera_obj.voltage = 20.0 mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.nvr.system_info.storage.devices = [] mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() # 3 from all, 6 from camera, 12 NVR assert_entity_counts(hass, Platform.SENSOR, 22, 14) yield camera_obj Camera.__config__.validate_assignment = True
def camera_all_fixture(camera: Camera): """Mock UniFi Protect Camera device.""" all_camera = camera.copy() all_camera.channels = [all_camera.channels[0].copy()] medium_channel = all_camera.channels[0].copy() medium_channel.name = "Medium" medium_channel.id = 1 medium_channel.rtsp_alias = "test_medium_alias" all_camera.channels.append(medium_channel) low_channel = all_camera.channels[0].copy() low_channel.name = "Low" low_channel.id = 2 low_channel.rtsp_alias = "test_medium_alias" all_camera.channels.append(low_channel) return all_camera
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_camera_interval_update(hass: HomeAssistant, ufp: MockUFPFixture, camera: ProtectCamera): """Interval updates updates camera entity.""" await init_entry(hass, ufp, [camera]) assert_entity_counts(hass, Platform.CAMERA, 2, 1) entity_id = "camera.test_camera_high" state = hass.states.get(entity_id) assert state and state.state == "idle" new_camera = camera.copy() new_camera.is_recording = True ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.api.update = AsyncMock(return_value=ufp.api.bootstrap) await time_changed(hass, DEFAULT_SCAN_INTERVAL) state = hass.states.get(entity_id) assert state and state.state == "recording"
async def camera_privacy_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Fixture for a single camera for testing the switch platform.""" # disable pydantic validation so mocking can happen Camera.__config__.validate_assignment = False camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" camera_obj.recording_settings.mode = RecordingMode.NEVER camera_obj.feature_flags.has_led_status = False camera_obj.feature_flags.has_hdr = False camera_obj.feature_flags.video_modes = [VideoMode.DEFAULT] camera_obj.feature_flags.has_privacy_mask = True camera_obj.feature_flags.has_speaker = False camera_obj.feature_flags.has_smart_detect = False camera_obj.add_privacy_zone() camera_obj.is_ssh_enabled = False camera_obj.osd_settings.is_name_enabled = False camera_obj.osd_settings.is_date_enabled = False camera_obj.osd_settings.is_logo_enabled = False camera_obj.osd_settings.is_debug_enabled = False mock_entry.api.bootstrap.reset_objects() mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.SWITCH, 6, 5) yield camera_obj Camera.__config__.validate_assignment = True
async def camera_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera): """Fixture for a single camera for testing the button platform.""" camera_obj = mock_camera.copy(deep=True) camera_obj._api = mock_entry.api camera_obj.channels[0]._api = mock_entry.api camera_obj.channels[1]._api = mock_entry.api camera_obj.channels[2]._api = mock_entry.api camera_obj.name = "Test Camera" mock_entry.api.bootstrap.cameras = { camera_obj.id: camera_obj, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.BUTTON, 1, 0) return (camera_obj, "button.test_camera_reboot_device")
async def test_camera_ws_update_offline(hass: HomeAssistant, ufp: MockUFPFixture, camera: ProtectCamera): """WS updates marks camera unavailable.""" await init_entry(hass, ufp, [camera]) assert_entity_counts(hass, Platform.CAMERA, 2, 1) entity_id = "camera.test_camera_high" state = hass.states.get(entity_id) assert state and state.state == "idle" # camera goes offline new_camera = camera.copy() new_camera.state = StateType.DISCONNECTED mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state and state.state == "unavailable" # camera comes back online new_camera.state = StateType.CONNECTED mock_msg = Mock() mock_msg.changed_data = {} mock_msg.new_obj = new_camera ufp.api.bootstrap.cameras = {new_camera.id: new_camera} ufp.ws_msg(mock_msg) await hass.async_block_till_done() state = hass.states.get(entity_id) assert state and state.state == "idle"
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
async def test_basic_setup( hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: ProtectCamera ): """Test working setup of unifiprotect entry.""" camera_high_only = mock_camera.copy(deep=True) camera_high_only._api = mock_entry.api camera_high_only.channels[0]._api = mock_entry.api camera_high_only.channels[1]._api = mock_entry.api camera_high_only.channels[2]._api = mock_entry.api camera_high_only.name = "Test Camera 1" camera_high_only.id = "test_high" camera_high_only.channels[0].is_rtsp_enabled = True camera_high_only.channels[0].name = "High" camera_high_only.channels[0].rtsp_alias = "test_high_alias" camera_high_only.channels[1].is_rtsp_enabled = False camera_high_only.channels[2].is_rtsp_enabled = False camera_medium_only = mock_camera.copy(deep=True) camera_medium_only._api = mock_entry.api camera_medium_only.channels[0]._api = mock_entry.api camera_medium_only.channels[1]._api = mock_entry.api camera_medium_only.channels[2]._api = mock_entry.api camera_medium_only.name = "Test Camera 2" camera_medium_only.id = "test_medium" camera_medium_only.channels[0].is_rtsp_enabled = False camera_medium_only.channels[1].is_rtsp_enabled = True camera_medium_only.channels[1].name = "Medium" camera_medium_only.channels[1].rtsp_alias = "test_medium_alias" camera_medium_only.channels[2].is_rtsp_enabled = False camera_all_channels = mock_camera.copy(deep=True) camera_all_channels._api = mock_entry.api camera_all_channels.channels[0]._api = mock_entry.api camera_all_channels.channels[1]._api = mock_entry.api camera_all_channels.channels[2]._api = mock_entry.api camera_all_channels.name = "Test Camera 3" camera_all_channels.id = "test_all" camera_all_channels.channels[0].is_rtsp_enabled = True camera_all_channels.channels[0].name = "High" camera_all_channels.channels[0].rtsp_alias = "test_high_alias" camera_all_channels.channels[1].is_rtsp_enabled = True camera_all_channels.channels[1].name = "Medium" camera_all_channels.channels[1].rtsp_alias = "test_medium_alias" camera_all_channels.channels[2].is_rtsp_enabled = True camera_all_channels.channels[2].name = "Low" camera_all_channels.channels[2].rtsp_alias = "test_low_alias" camera_no_channels = mock_camera.copy(deep=True) camera_no_channels._api = mock_entry.api camera_no_channels.channels[0]._api = mock_entry.api camera_no_channels.channels[1]._api = mock_entry.api camera_no_channels.channels[2]._api = mock_entry.api camera_no_channels.name = "Test Camera 4" camera_no_channels.id = "test_none" camera_no_channels.channels[0].is_rtsp_enabled = False camera_no_channels.channels[0].name = "High" camera_no_channels.channels[1].is_rtsp_enabled = False camera_no_channels.channels[2].is_rtsp_enabled = False camera_package = mock_camera.copy(deep=True) camera_package._api = mock_entry.api camera_package.channels[0]._api = mock_entry.api camera_package.channels[1]._api = mock_entry.api camera_package.channels[2]._api = mock_entry.api camera_package.name = "Test Camera 5" camera_package.id = "test_package" camera_package.channels[0].is_rtsp_enabled = True camera_package.channels[0].name = "High" camera_package.channels[0].rtsp_alias = "test_high_alias" camera_package.channels[1].is_rtsp_enabled = False camera_package.channels[2].is_rtsp_enabled = False package_channel = camera_package.channels[0].copy(deep=True) package_channel.is_rtsp_enabled = False package_channel.name = "Package Camera" package_channel.id = 3 package_channel.fps = 2 package_channel.rtsp_alias = "test_package_alias" camera_package.channels.append(package_channel) mock_entry.api.bootstrap.cameras = { camera_high_only.id: camera_high_only, camera_medium_only.id: camera_medium_only, camera_all_channels.id: camera_all_channels, camera_no_channels.id: camera_no_channels, camera_package.id: camera_package, } await hass.config_entries.async_setup(mock_entry.entry.entry_id) await hass.async_block_till_done() assert_entity_counts(hass, Platform.CAMERA, 14, 6) # test camera 1 entity_id = validate_default_camera_entity(hass, camera_high_only, 0) await validate_rtsps_camera_state(hass, camera_high_only, 0, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_high_only, 0) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_high_only, 0, entity_id) # test camera 2 entity_id = validate_default_camera_entity(hass, camera_medium_only, 1) await validate_rtsps_camera_state(hass, camera_medium_only, 1, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_medium_only, 1) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_medium_only, 1, entity_id) # test camera 3 entity_id = validate_default_camera_entity(hass, camera_all_channels, 0) await validate_rtsps_camera_state(hass, camera_all_channels, 0, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_all_channels, 0) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_all_channels, 0, entity_id) entity_id = validate_rtsps_camera_entity(hass, camera_all_channels, 1) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsps_camera_state(hass, camera_all_channels, 1, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_all_channels, 1) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_all_channels, 1, entity_id) entity_id = validate_rtsps_camera_entity(hass, camera_all_channels, 2) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsps_camera_state(hass, camera_all_channels, 2, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_all_channels, 2) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_all_channels, 2, entity_id) # test camera 4 entity_id = validate_default_camera_entity(hass, camera_no_channels, 0) await validate_no_stream_camera_state( hass, camera_no_channels, 0, entity_id, features=0 ) # test camera 5 entity_id = validate_default_camera_entity(hass, camera_package, 0) await validate_rtsps_camera_state(hass, camera_package, 0, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_package, 0) await enable_entity(hass, mock_entry.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_package, 0, entity_id) entity_id = validate_default_camera_entity(hass, camera_package, 3) await validate_no_stream_camera_state( hass, camera_package, 3, entity_id, features=0 )
async def test_basic_setup( hass: HomeAssistant, ufp: MockUFPFixture, camera_all: ProtectCamera, doorbell: ProtectCamera, ): """Test working setup of unifiprotect entry.""" camera_high_only = camera_all.copy() camera_high_only.channels = [c.copy() for c in camera_all.channels] camera_high_only.name = "Test Camera 1" camera_high_only.channels[0].is_rtsp_enabled = True camera_high_only.channels[1].is_rtsp_enabled = False camera_high_only.channels[2].is_rtsp_enabled = False camera_medium_only = camera_all.copy() camera_medium_only.channels = [c.copy() for c in camera_all.channels] camera_medium_only.name = "Test Camera 2" camera_medium_only.channels[0].is_rtsp_enabled = False camera_medium_only.channels[1].is_rtsp_enabled = True camera_medium_only.channels[2].is_rtsp_enabled = False camera_all.name = "Test Camera 3" camera_no_channels = camera_all.copy() camera_no_channels.channels = [c.copy() for c in camera_all.channels] camera_no_channels.name = "Test Camera 4" camera_no_channels.channels[0].is_rtsp_enabled = False camera_no_channels.channels[1].is_rtsp_enabled = False camera_no_channels.channels[2].is_rtsp_enabled = False doorbell.name = "Test Camera 5" devices = [ camera_high_only, camera_medium_only, camera_all, camera_no_channels, doorbell, ] await init_entry(hass, ufp, devices) assert_entity_counts(hass, Platform.CAMERA, 14, 6) # test camera 1 entity_id = validate_default_camera_entity(hass, camera_high_only, 0) await validate_rtsps_camera_state(hass, camera_high_only, 0, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_high_only, 0) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_high_only, 0, entity_id) # test camera 2 entity_id = validate_default_camera_entity(hass, camera_medium_only, 1) await validate_rtsps_camera_state(hass, camera_medium_only, 1, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_medium_only, 1) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_medium_only, 1, entity_id) # test camera 3 entity_id = validate_default_camera_entity(hass, camera_all, 0) await validate_rtsps_camera_state(hass, camera_all, 0, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_all, 0) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_all, 0, entity_id) entity_id = validate_rtsps_camera_entity(hass, camera_all, 1) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsps_camera_state(hass, camera_all, 1, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_all, 1) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_all, 1, entity_id) entity_id = validate_rtsps_camera_entity(hass, camera_all, 2) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsps_camera_state(hass, camera_all, 2, entity_id) entity_id = validate_rtsp_camera_entity(hass, camera_all, 2) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, camera_all, 2, entity_id) # test camera 4 entity_id = validate_default_camera_entity(hass, camera_no_channels, 0) await validate_no_stream_camera_state(hass, camera_no_channels, 0, entity_id, features=0) # test camera 5 entity_id = validate_default_camera_entity(hass, doorbell, 0) await validate_rtsps_camera_state(hass, doorbell, 0, entity_id) entity_id = validate_rtsp_camera_entity(hass, doorbell, 0) await enable_entity(hass, ufp.entry.entry_id, entity_id) await validate_rtsp_camera_state(hass, doorbell, 0, entity_id) entity_id = validate_default_camera_entity(hass, doorbell, 3) await validate_no_stream_camera_state(hass, doorbell, 3, entity_id, features=0)