"""Tests for the motionEye integration.""" from __future__ import annotations from typing import Any from unittest.mock import AsyncMock, Mock, patch from motioneye_client.const import DEFAULT_PORT from homeassistant.components.motioneye import get_motioneye_entity_unique_id from homeassistant.components.motioneye.const import DOMAIN from homeassistant.config import async_process_ha_core_config from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_URL from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from tests.common import MockConfigEntry TEST_CONFIG_ENTRY_ID = "74565ad414754616000674c87bdc876c" TEST_URL = f"http://test:{DEFAULT_PORT+1}" TEST_CAMERA_ID = 100 TEST_CAMERA_NAME = "Test Camera" TEST_CAMERA_ENTITY_ID = "camera.test_camera" TEST_CAMERA_DEVICE_IDENTIFIER = (DOMAIN, f"{TEST_CONFIG_ENTRY_ID}_{TEST_CAMERA_ID}") TEST_CAMERA = { "show_frame_changes": False, "framerate": 25, "actions": ["one", "two", "three"], "preserve_movies": 0, "auto_threshold_tuning": True, "recording_mode": "motion-triggered", "monday_to": "", "streaming_resolution": 100, "light_switch_detect": 0, "command_end_notifications_enabled": False, "smb_shares": False, "upload_server": "", "monday_from": "", "movie_passthrough": False, "auto_brightness": False, "frame_change_threshold": 3.0, "name": TEST_CAMERA_NAME, "movie_format": "mp4:h264_omx", "network_username": "", "preserve_pictures": 0, "event_gap": 30, "enabled": True, "upload_movie": True, "video_streaming": True, "upload_location": "", "max_movie_length": 0, "movie_file_name": "%Y-%m-%d/%H-%M-%S", "upload_authorization_key": "", "still_images": False, "upload_method": "post", "max_frame_change_threshold": 0, "device_url": "rtsp://localhost/live", "text_overlay": False, "right_text": "timestamp", "upload_picture": True, "email_notifications_enabled": False, "working_schedule_type": "during", "movie_quality": 75, "disk_total": 44527655808, "upload_service": "ftp", "upload_password": "", "wednesday_to": "", "mask_type": "smart", "command_storage_enabled": False, "disk_used": 11419704992, "streaming_motion": 0, "manual_snapshots": True, "noise_level": 12, "mask_lines": [], "upload_enabled": False, "root_directory": f"/var/lib/motioneye/{TEST_CAMERA_NAME}", "clean_cloud_enabled": False, "working_schedule": False, "pre_capture": 1, "command_notifications_enabled": False, "streaming_framerate": 25, "email_notifications_picture_time_span": 0, "thursday_to": "", "streaming_server_resize": False, "upload_subfolders": True, "sunday_to": "", "left_text": "", "image_file_name": "%Y-%m-%d/%H-%M-%S", "rotation": 0, "capture_mode": "manual", "movies": False, "motion_detection": True, "text_scale": 1, "upload_username": "", "upload_port": "", "available_disks": [], "network_smb_ver": "1.0", "streaming_auth_mode": "basic", "despeckle_filter": "", "snapshot_interval": 0, "minimum_motion_frames": 20, "auto_noise_detect": True, "network_share_name": "", "sunday_from": "", "friday_from": "", "web_hook_storage_enabled": False, "custom_left_text": "", "streaming_port": 8081, "id": TEST_CAMERA_ID, "post_capture": 1, "streaming_quality": 75, "wednesday_from": "", "proto": "netcam", "extra_options": [], "image_quality": 85, "create_debug_media": False, "friday_to": "", "custom_right_text": "", "web_hook_notifications_enabled": False, "saturday_from": "", "available_resolutions": [ "1600x1200", "1920x1080", ], "tuesday_from": "", "network_password": "", "saturday_to": "", "network_server": "", "smart_mask_sluggishness": 5, "mask": False, "tuesday_to": "", "thursday_from": "", "storage_device": "custom-path", "resolution": "1920x1080", } TEST_CAMERAS = {"cameras": [TEST_CAMERA]} TEST_SURVEILLANCE_USERNAME = "surveillance_username" TEST_SENSOR_ACTION_ENTITY_ID = "sensor.test_camera_actions" TEST_SWITCH_ENTITY_ID_BASE = "switch.test_camera" TEST_SWITCH_MOTION_DETECTION_ENTITY_ID = ( f"{TEST_SWITCH_ENTITY_ID_BASE}_motion_detection" ) def create_mock_motioneye_client() -> AsyncMock: """Create mock motionEye client.""" mock_client = AsyncMock() mock_client.async_client_login = AsyncMock(return_value={}) mock_client.async_get_cameras = AsyncMock(return_value=TEST_CAMERAS) mock_client.async_client_close = AsyncMock(return_value=True) mock_client.get_camera_snapshot_url = Mock(return_value="") mock_client.get_camera_stream_url = Mock(return_value="") return mock_client def create_mock_motioneye_config_entry( hass: HomeAssistant, data: dict[str, Any] | None = None, options: dict[str, Any] | None = None, ) -> ConfigEntry: """Add a test config entry.""" config_entry: MockConfigEntry = MockConfigEntry( entry_id=TEST_CONFIG_ENTRY_ID, domain=DOMAIN, data=data or {CONF_URL: TEST_URL}, title=f"{TEST_URL}", options=options or {}, ) config_entry.add_to_hass(hass) return config_entry async def setup_mock_motioneye_config_entry( hass: HomeAssistant, config_entry: ConfigEntry | None = None, client: Mock | None = None, ) -> ConfigEntry: """Create and setup a mock motionEye config entry.""" await async_process_ha_core_config( hass, { "internal_url": "https://internal.url", "external_url": "https://external.url", }, ) config_entry = config_entry or create_mock_motioneye_config_entry(hass) client = client or create_mock_motioneye_client() with patch( "homeassistant.components.motioneye.MotionEyeClient", return_value=client, ): await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() return config_entry def register_test_entity( hass: HomeAssistant, platform: str, camera_id: int, type_name: str, entity_id: str ) -> None: """Register a test entity.""" unique_id = get_motioneye_entity_unique_id( TEST_CONFIG_ENTRY_ID, camera_id, type_name ) entity_id = entity_id.split(".")[1] entity_registry = er.async_get(hass) entity_registry.async_get_or_create( platform, DOMAIN, unique_id, suggested_object_id=entity_id, disabled_by=None, )